android13/kernel-5.10/drivers/video/rockchip/rga/rga_mmu_info.c

1326 lines
39 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/pagemap.h>
#include <linux/seq_file.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/memory.h>
#include <linux/dma-mapping.h>
#include <asm/memory.h>
#include <asm/atomic.h>
#include <asm/cacheflush.h>
#include "rga_mmu_info.h"
#include <linux/delay.h>
extern rga_service_info rga_service;
extern struct rga_mmu_buf_t rga_mmu_buf;
#if RGA_DEBUGFS
extern int RGA_CHECK_MODE;
#endif
#define KERNEL_SPACE_VALID 0xc0000000
void rga_dma_flush_range(void *pstart, void *pend)
{
dma_sync_single_for_device(rga_drvdata->dev, virt_to_phys(pstart), pend - pstart, DMA_TO_DEVICE);
}
static int rga_mmu_buf_get(struct rga_mmu_buf_t *t, uint32_t size)
{
mutex_lock(&rga_service.lock);
t->front += size;
mutex_unlock(&rga_service.lock);
return 0;
}
static void rga_current_mm_read_lock(struct mm_struct *mm)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
mmap_read_lock(mm);
#else
down_read(&mm->mmap_sem);
#endif
}
static void rga_current_mm_read_unlock(struct mm_struct *mm)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
mmap_read_unlock(mm);
#else
up_read(&mm->mmap_sem);
#endif
}
static long rga_get_user_pages(struct page **pages, unsigned long Memory,
uint32_t pageCount, int writeFlag,
struct mm_struct *current_mm)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 168) && \
LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0)
return get_user_pages(current, current_mm, Memory << PAGE_SHIFT,
pageCount, writeFlag ? FOLL_WRITE : 0, pages, NULL);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
return get_user_pages(current, current_mm, Memory << PAGE_SHIFT,
pageCount, writeFlag ? FOLL_WRITE : 0, 0, pages, NULL);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
return get_user_pages_remote(current, current_mm, Memory << PAGE_SHIFT,
pageCount, writeFlag ? FOLL_WRITE : 0, pages,
NULL, NULL);
#else
return get_user_pages_remote(current_mm, Memory << PAGE_SHIFT,
pageCount, writeFlag ? FOLL_WRITE : 0, pages,
NULL, NULL);
#endif
}
static int rga_mmu_buf_get_try(struct rga_mmu_buf_t *t, uint32_t size)
{
int ret = 0;
mutex_lock(&rga_service.lock);
if ((t->back - t->front) > t->size) {
if(t->front + size > t->back - t->size) {
ret = -ENOMEM;
goto out;
}
} else {
if ((t->front + size) > t->back) {
ret = -ENOMEM;
goto out;
}
if (t->front + size > t->size) {
if (size > (t->back - t->size)) {
ret = -ENOMEM;
goto out;
}
t->front = 0;
}
}
out:
mutex_unlock(&rga_service.lock);
return ret;
}
static int rga_mem_size_cal(unsigned long Mem, uint32_t MemSize, unsigned long *StartAddr)
{
unsigned long start, end;
uint32_t pageCount;
end = (Mem + (MemSize + PAGE_SIZE - 1)) >> PAGE_SHIFT;
start = Mem >> PAGE_SHIFT;
pageCount = end - start;
*StartAddr = start;
return pageCount;
}
static int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr, unsigned long v_addr,
int format, uint32_t w, uint32_t h, unsigned long *StartAddr )
{
uint32_t size_yrgb = 0;
uint32_t size_uv = 0;
uint32_t size_v = 0;
uint32_t stride = 0;
unsigned long start, end;
uint32_t pageCount;
switch(format)
{
case RK_FORMAT_RGBA_8888 :
stride = (w * 4 + 3) & (~3);
size_yrgb = stride*h;
start = yrgb_addr >> PAGE_SHIFT;
pageCount = (size_yrgb + PAGE_SIZE - 1) >> PAGE_SHIFT;
break;
case RK_FORMAT_RGBX_8888 :
stride = (w * 4 + 3) & (~3);
size_yrgb = stride*h;
start = yrgb_addr >> PAGE_SHIFT;
pageCount = (size_yrgb + PAGE_SIZE - 1) >> PAGE_SHIFT;
break;
case RK_FORMAT_RGB_888 :
stride = (w * 3 + 3) & (~3);
size_yrgb = stride*h;
start = yrgb_addr >> PAGE_SHIFT;
pageCount = (size_yrgb + PAGE_SIZE - 1) >> PAGE_SHIFT;
break;
case RK_FORMAT_BGRA_8888 :
size_yrgb = w*h*4;
start = yrgb_addr >> PAGE_SHIFT;
pageCount = (size_yrgb + PAGE_SIZE - 1) >> PAGE_SHIFT;
break;
case RK_FORMAT_RGB_565 :
stride = (w*2 + 3) & (~3);
size_yrgb = stride * h;
start = yrgb_addr >> PAGE_SHIFT;
pageCount = (size_yrgb + PAGE_SIZE - 1) >> PAGE_SHIFT;
break;
case RK_FORMAT_RGBA_5551 :
stride = (w*2 + 3) & (~3);
size_yrgb = stride * h;
start = yrgb_addr >> PAGE_SHIFT;
pageCount = (size_yrgb + PAGE_SIZE - 1) >> PAGE_SHIFT;
break;
case RK_FORMAT_RGBA_4444 :
stride = (w*2 + 3) & (~3);
size_yrgb = stride * h;
start = yrgb_addr >> PAGE_SHIFT;
pageCount = (size_yrgb + PAGE_SIZE - 1) >> PAGE_SHIFT;
break;
case RK_FORMAT_BGR_888 :
stride = (w*3 + 3) & (~3);
size_yrgb = stride * h;
start = yrgb_addr >> PAGE_SHIFT;
pageCount = (size_yrgb + PAGE_SIZE - 1) >> PAGE_SHIFT;
break;
/* YUV FORMAT */
case RK_FORMAT_YCbCr_422_SP :
stride = (w + 3) & (~3);
size_yrgb = stride * h;
size_uv = stride * h;
start = MIN(yrgb_addr, uv_addr);
start >>= PAGE_SHIFT;
end = MAX((yrgb_addr + size_yrgb), (uv_addr + size_uv));
end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
pageCount = end - start;
break;
case RK_FORMAT_YCbCr_422_P :
stride = (w + 3) & (~3);
size_yrgb = stride * h;
size_uv = ((stride >> 1) * h);
size_v = ((stride >> 1) * h);
start = MIN(MIN(yrgb_addr, uv_addr), v_addr);
start = start >> PAGE_SHIFT;
end = MAX(MAX((yrgb_addr + size_yrgb), (uv_addr + size_uv)), (v_addr + size_v));
end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
pageCount = end - start;
break;
case RK_FORMAT_YCbCr_420_SP :
stride = (w + 3) & (~3);
size_yrgb = stride * h;
size_uv = (stride * (h >> 1));
start = MIN(yrgb_addr, uv_addr);
start >>= PAGE_SHIFT;
end = MAX((yrgb_addr + size_yrgb), (uv_addr + size_uv));
end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
pageCount = end - start;
break;
case RK_FORMAT_YCbCr_420_P :
stride = (w + 3) & (~3);
size_yrgb = stride * h;
size_uv = ((stride >> 1) * (h >> 1));
size_v = ((stride >> 1) * (h >> 1));
start = MIN(MIN(yrgb_addr, uv_addr), v_addr);
start >>= PAGE_SHIFT;
end = MAX(MAX((yrgb_addr + size_yrgb), (uv_addr + size_uv)), (v_addr + size_v));
end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
pageCount = end - start;
break;
case RK_FORMAT_YCrCb_422_SP :
stride = (w + 3) & (~3);
size_yrgb = stride * h;
size_uv = stride * h;
start = MIN(yrgb_addr, uv_addr);
start >>= PAGE_SHIFT;
end = MAX((yrgb_addr + size_yrgb), (uv_addr + size_uv));
end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
pageCount = end - start;
break;
case RK_FORMAT_YCrCb_422_P :
stride = (w + 3) & (~3);
size_yrgb = stride * h;
size_uv = ((stride >> 1) * h);
size_v = ((stride >> 1) * h);
start = MIN(MIN(yrgb_addr, uv_addr), v_addr);
start >>= PAGE_SHIFT;
end = MAX(MAX((yrgb_addr + size_yrgb), (uv_addr + size_uv)), (v_addr + size_v));
end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
pageCount = end - start;
break;
case RK_FORMAT_YCrCb_420_SP :
stride = (w + 3) & (~3);
size_yrgb = stride * h;
size_uv = (stride * (h >> 1));
start = MIN(yrgb_addr, uv_addr);
start >>= PAGE_SHIFT;
end = MAX((yrgb_addr + size_yrgb), (uv_addr + size_uv));
end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
pageCount = end - start;
break;
case RK_FORMAT_YCrCb_420_P :
stride = (w + 3) & (~3);
size_yrgb = stride * h;
size_uv = ((stride >> 1) * (h >> 1));
size_v = ((stride >> 1) * (h >> 1));
start = MIN(MIN(yrgb_addr, uv_addr), v_addr);
start >>= PAGE_SHIFT;
end = MAX(MAX((yrgb_addr + size_yrgb), (uv_addr + size_uv)), (v_addr + size_v));
end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
pageCount = end - start;
break;
#if 0
case RK_FORMAT_BPP1 :
break;
case RK_FORMAT_BPP2 :
break;
case RK_FORMAT_BPP4 :
break;
case RK_FORMAT_BPP8 :
break;
#endif
default :
pageCount = 0;
start = 0;
break;
}
*StartAddr = start;
return pageCount;
}
#if RGA_DEBUGFS
static int rga_usermemory_cheeck(struct page **pages, u32 w, u32 h, u32 format, int flag)
{
int bits;
void *vaddr = NULL;
int taipage_num;
int taidata_num;
int *tai_vaddr = NULL;
switch (format) {
case RK_FORMAT_RGBA_8888:
case RK_FORMAT_RGBX_8888:
case RK_FORMAT_BGRA_8888:
bits = 32;
break;
case RK_FORMAT_RGB_888:
case RK_FORMAT_BGR_888:
bits = 24;
break;
case RK_FORMAT_RGB_565:
case RK_FORMAT_RGBA_5551:
case RK_FORMAT_RGBA_4444:
case RK_FORMAT_YCbCr_422_SP:
case RK_FORMAT_YCbCr_422_P:
case RK_FORMAT_YCrCb_422_SP:
case RK_FORMAT_YCrCb_422_P:
bits = 16;
break;
case RK_FORMAT_YCbCr_420_SP:
case RK_FORMAT_YCbCr_420_P:
case RK_FORMAT_YCrCb_420_SP:
case RK_FORMAT_YCrCb_420_P:
bits = 12;
break;
case RK_FORMAT_YCbCr_420_SP_10B:
case RK_FORMAT_YCrCb_420_SP_10B:
bits = 15;
break;
default:
printk(KERN_DEBUG "un know format\n");
return -1;
}
taipage_num = w * h * bits / 8 / (1024 * 4);
taidata_num = w * h * bits / 8 % (1024 * 4);
if (taidata_num == 0) {
vaddr = kmap(pages[taipage_num - 1]);
tai_vaddr = (int *)vaddr + 1023;
} else {
vaddr = kmap(pages[taipage_num]);
tai_vaddr = (int *)vaddr + taidata_num / 4 - 1;
}
if (flag == 1) {
printk(KERN_DEBUG "src user memory check\n");
printk(KERN_DEBUG "tai data is %d\n", *tai_vaddr);
} else {
printk(KERN_DEBUG "dst user memory check\n");
printk(KERN_DEBUG "tai data is %d\n", *tai_vaddr);
}
if (taidata_num == 0)
kunmap(pages[taipage_num - 1]);
else
kunmap(pages[taipage_num]);
return 0;
}
#endif
static int rga_MapUserMemory(struct page **pages,
uint32_t *pageTable,
unsigned long Memory,
uint32_t pageCount)
{
int32_t result;
uint32_t i;
uint32_t status;
unsigned long Address;
status = 0;
Address = 0;
do {
rga_current_mm_read_lock(current->mm);
result = rga_get_user_pages(pages, Memory, pageCount, 1, current->mm);
rga_current_mm_read_unlock(current->mm);
#if 0
if(result <= 0 || result < pageCount)
{
status = 0;
for(i=0; i<pageCount; i++)
{
temp = armv7_va_to_pa((Memory + i) << PAGE_SHIFT);
if (temp == 0xffffffff)
{
printk("rga find mmu phy ddr error\n ");
status = RGA_OUT_OF_RESOURCES;
break;
}
pageTable[i] = temp;
}
return status;
}
#else
if(result <= 0 || result < pageCount)
{
struct vm_area_struct *vma;
if (result>0) {
rga_current_mm_read_lock(current->mm);
for (i = 0; i < result; i++)
put_page(pages[i]);
rga_current_mm_read_unlock(current->mm);
}
for(i=0; i<pageCount; i++)
{
vma = find_vma(current->mm, (Memory + i) << PAGE_SHIFT);
if (vma)//&& (vma->vm_flags & VM_PFNMAP) )
{
do
{
pte_t * pte;
spinlock_t * ptl;
unsigned long pfn;
pgd_t * pgd;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
p4d_t * p4d;
#endif
pud_t * pud;
pgd = pgd_offset(current->mm, (Memory + i) << PAGE_SHIFT);
if(pgd_val(*pgd) == 0)
{
//printk("rga pgd value is zero \n");
break;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
/* In the four-level page table, it will do nothing and return pgd. */
p4d = p4d_offset(pgd, (Memory + i) << PAGE_SHIFT);
if (p4d_none(*p4d) || unlikely(p4d_bad(*p4d))) {
pr_err("RGA2 failed to get p4d, result = %d, pageCount = %d\n",
result, pageCount);
status = RGA_OUT_OF_RESOURCES;
break;
}
pud = pud_offset(p4d, (Memory + i) << PAGE_SHIFT);
#else
pud = pud_offset(pgd, (Memory + i) << PAGE_SHIFT);
#endif
if (pud)
{
pmd_t * pmd = pmd_offset(pud, (Memory + i) << PAGE_SHIFT);
if (pmd)
{
pte = pte_offset_map_lock(current->mm, pmd, (Memory + i) << PAGE_SHIFT, &ptl);
if (!pte)
{
pte_unmap_unlock(pte, ptl);
break;
}
}
else
{
break;
}
}
else
{
break;
}
pfn = pte_pfn(*pte);
Address = ((pfn << PAGE_SHIFT) | (((unsigned long)((Memory + i) << PAGE_SHIFT)) & ~PAGE_MASK));
pte_unmap_unlock(pte, ptl);
}
while (0);
pageTable[i] = Address;
}
else
{
status = RGA_OUT_OF_RESOURCES;
break;
}
}
return status;
}
#endif
/* Fill the page table. */
for(i=0; i<pageCount; i++)
{
/* Get the physical address from page struct. */
pageTable[i] = page_to_phys(pages[i]);
}
rga_current_mm_read_lock(current->mm);
for (i = 0; i < result; i++)
put_page(pages[i]);
rga_current_mm_read_unlock(current->mm);
return 0;
}
while(0);
return status;
}
static int rga_MapION(struct sg_table *sg,
uint32_t *Memory,
int32_t pageCount,
uint32_t offset)
{
uint32_t i;
uint32_t status;
unsigned long Address;
uint32_t mapped_size = 0;
uint32_t len = 0;
struct scatterlist *sgl = sg->sgl;
uint32_t sg_num = 0;
status = 0;
Address = 0;
offset = offset >> PAGE_SHIFT;
if (offset != 0) {
do {
len += (sg_dma_len(sgl) >> PAGE_SHIFT);
if (len == offset) {
sg_num += 1;
break;
}
else {
if (len > offset)
break;
}
sg_num += 1;
}
while((sgl = sg_next(sgl)) && (mapped_size < pageCount) && (sg_num < sg->nents));
sgl = sg->sgl;
len = 0;
do {
len += (sg_dma_len(sgl) >> PAGE_SHIFT);
sgl = sg_next(sgl);
}
while(--sg_num);
offset -= len;
len = sg_dma_len(sgl) >> PAGE_SHIFT;
Address = sg_phys(sgl);
Address += offset;
for(i=offset; i<len; i++) {
Memory[i - offset] = Address + (i << PAGE_SHIFT);
}
mapped_size += (len - offset);
sg_num = 1;
sgl = sg_next(sgl);
do {
len = sg_dma_len(sgl) >> PAGE_SHIFT;
Address = sg_phys(sgl);
for(i=0; i<len; i++) {
Memory[mapped_size + i] = Address + (i << PAGE_SHIFT);
}
mapped_size += len;
sg_num += 1;
}
while((sgl = sg_next(sgl)) && (mapped_size < pageCount) && (sg_num < sg->nents));
}
else {
do {
len = sg_dma_len(sgl) >> PAGE_SHIFT;
Address = sg_phys(sgl);
for(i=0; i<len; i++) {
Memory[mapped_size + i] = Address + (i << PAGE_SHIFT);
}
mapped_size += len;
sg_num += 1;
}
while((sgl = sg_next(sgl)) && (mapped_size < pageCount) && (sg_num < sg->nents));
}
return 0;
}
static int rga_mmu_info_BitBlt_mode(struct rga_reg *reg, struct rga_req *req)
{
int SrcMemSize, DstMemSize;
unsigned long SrcStart, DstStart;
uint32_t i;
uint32_t AllSize;
uint32_t *MMU_Base, *MMU_p, *MMU_Base_phys;
int ret;
int status;
uint32_t uv_size, v_size;
struct page **pages = NULL;
MMU_Base = NULL;
SrcMemSize = 0;
DstMemSize = 0;
do {
/* cal src buf mmu info */
SrcMemSize = rga_buf_size_cal(req->src.yrgb_addr, req->src.uv_addr, req->src.v_addr,
req->src.format, req->src.vir_w, req->src.act_h + req->src.y_offset,
&SrcStart);
if(SrcMemSize == 0) {
return -EINVAL;
}
/* cal dst buf mmu info */
DstMemSize = rga_buf_size_cal(req->dst.yrgb_addr, req->dst.uv_addr, req->dst.v_addr,
req->dst.format, req->dst.vir_w, req->dst.vir_h,
&DstStart);
if(DstMemSize == 0)
return -EINVAL;
/* Cal out the needed mem size */
SrcMemSize = (SrcMemSize + 15) & (~15);
DstMemSize = (DstMemSize + 15) & (~15);
AllSize = SrcMemSize + DstMemSize;
if (rga_mmu_buf_get_try(&rga_mmu_buf, AllSize + 16)) {
pr_err("RGA Get MMU mem failed\n");
status = RGA_MALLOC_ERROR;
break;
}
mutex_lock(&rga_service.lock);
MMU_Base = rga_mmu_buf.buf_virtual + (rga_mmu_buf.front & (rga_mmu_buf.size - 1));
MMU_Base_phys = rga_mmu_buf.buf + (rga_mmu_buf.front & (rga_mmu_buf.size - 1));
mutex_unlock(&rga_service.lock);
pages = rga_mmu_buf.pages;
if((req->mmu_info.mmu_flag >> 8) & 1) {
if (req->sg_src) {
ret = rga_MapION(req->sg_src, &MMU_Base[0], SrcMemSize, req->line_draw_info.flag);
}
else {
ret = rga_MapUserMemory(&pages[0], &MMU_Base[0], SrcStart, SrcMemSize);
if (ret < 0) {
pr_err("rga map src memory failed\n");
status = ret;
break;
}
#if RGA_DEBUGFS
if (RGA_CHECK_MODE)
rga_usermemory_cheeck(&pages[0], req->src.vir_w,
req->src.vir_h, req->src.format, 1);
#endif
}
}
else {
MMU_p = MMU_Base;
if(req->src.yrgb_addr == (unsigned long)rga_service.pre_scale_buf) {
for(i=0; i<SrcMemSize; i++)
MMU_p[i] = rga_service.pre_scale_buf[i];
}
else {
for(i=0; i<SrcMemSize; i++)
MMU_p[i] = (uint32_t)((SrcStart + i) << PAGE_SHIFT);
}
}
if ((req->mmu_info.mmu_flag >> 10) & 1) {
if (req->sg_dst) {
ret = rga_MapION(req->sg_dst, &MMU_Base[SrcMemSize], DstMemSize, req->line_draw_info.line_width);
}
else {
ret = rga_MapUserMemory(&pages[SrcMemSize], &MMU_Base[SrcMemSize], DstStart, DstMemSize);
if (ret < 0) {
pr_err("rga map dst memory failed\n");
status = ret;
break;
}
#if RGA_DEBUGFS
if (RGA_CHECK_MODE)
rga_usermemory_cheeck(&pages[0], req->src.vir_w,
req->src.vir_h, req->src.format, 2);
#endif
}
}
else {
MMU_p = MMU_Base + SrcMemSize;
for(i=0; i<DstMemSize; i++)
MMU_p[i] = (uint32_t)((DstStart + i) << PAGE_SHIFT);
}
MMU_Base[AllSize] = MMU_Base[AllSize-1];
/* zsq
* change the buf address in req struct
*/
req->mmu_info.base_addr = (unsigned long)MMU_Base_phys >> 2;
uv_size = (req->src.uv_addr - (SrcStart << PAGE_SHIFT)) >> PAGE_SHIFT;
v_size = (req->src.v_addr - (SrcStart << PAGE_SHIFT)) >> PAGE_SHIFT;
req->src.yrgb_addr = (req->src.yrgb_addr & (~PAGE_MASK));
req->src.uv_addr = (req->src.uv_addr & (~PAGE_MASK)) | (uv_size << PAGE_SHIFT);
req->src.v_addr = (req->src.v_addr & (~PAGE_MASK)) | (v_size << PAGE_SHIFT);
uv_size = (req->dst.uv_addr - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT;
req->dst.yrgb_addr = (req->dst.yrgb_addr & (~PAGE_MASK)) | (SrcMemSize << PAGE_SHIFT);
req->dst.uv_addr = (req->dst.uv_addr & (~PAGE_MASK)) | ((SrcMemSize + uv_size) << PAGE_SHIFT);
/* flush data to DDR */
rga_dma_flush_range(MMU_Base, (MMU_Base + AllSize + 1));
rga_mmu_buf_get(&rga_mmu_buf, AllSize + 16);
reg->MMU_len = AllSize + 16;
status = 0;
return status;
}
while(0);
return status;
}
static int rga_mmu_info_color_palette_mode(struct rga_reg *reg, struct rga_req *req)
{
int SrcMemSize, DstMemSize, CMDMemSize;
unsigned long SrcStart, DstStart, CMDStart;
struct page **pages = NULL;
uint32_t i;
uint32_t AllSize;
uint32_t *MMU_Base = NULL, *MMU_Base_phys = NULL;
uint32_t *MMU_p;
int ret, status = 0;
uint32_t stride;
uint8_t shift;
uint16_t sw, byte_num;
shift = 3 - (req->palette_mode & 3);
sw = req->src.vir_w;
byte_num = sw >> shift;
stride = (byte_num + 3) & (~3);
do {
SrcMemSize = rga_mem_size_cal(req->src.yrgb_addr, stride, &SrcStart);
if(SrcMemSize == 0) {
return -EINVAL;
}
DstMemSize = rga_buf_size_cal(req->dst.yrgb_addr, req->dst.uv_addr, req->dst.v_addr,
req->dst.format, req->dst.vir_w, req->dst.vir_h,
&DstStart);
if(DstMemSize == 0) {
return -EINVAL;
}
CMDMemSize = rga_mem_size_cal((unsigned long)rga_service.cmd_buff, RGA_CMD_BUF_SIZE, &CMDStart);
if(CMDMemSize == 0) {
return -EINVAL;
}
SrcMemSize = (SrcMemSize + 15) & (~15);
DstMemSize = (DstMemSize + 15) & (~15);
CMDMemSize = (CMDMemSize + 15) & (~15);
AllSize = SrcMemSize + DstMemSize + CMDMemSize;
if (rga_mmu_buf_get_try(&rga_mmu_buf, AllSize + 16)) {
pr_err("RGA Get MMU mem failed\n");
status = RGA_MALLOC_ERROR;
break;
}
mutex_lock(&rga_service.lock);
MMU_Base = rga_mmu_buf.buf_virtual + (rga_mmu_buf.front & (rga_mmu_buf.size - 1));
MMU_Base_phys = rga_mmu_buf.buf + (rga_mmu_buf.front & (rga_mmu_buf.size - 1));
mutex_unlock(&rga_service.lock);
pages = rga_mmu_buf.pages;
/* map CMD addr */
for(i=0; i<CMDMemSize; i++) {
MMU_Base[i] = (uint32_t)virt_to_phys((uint32_t *)((CMDStart + i)<<PAGE_SHIFT));
}
/* map src addr */
if (req->src.yrgb_addr < KERNEL_SPACE_VALID) {
ret = rga_MapUserMemory(&pages[CMDMemSize], &MMU_Base[CMDMemSize], SrcStart, SrcMemSize);
if (ret < 0) {
pr_err("rga map src memory failed\n");
status = ret;
break;
}
}
else {
MMU_p = MMU_Base + CMDMemSize;
for(i=0; i<SrcMemSize; i++)
{
MMU_p[i] = (uint32_t)virt_to_phys((uint32_t *)((SrcStart + i) << PAGE_SHIFT));
}
}
/* map dst addr */
if (req->src.yrgb_addr < KERNEL_SPACE_VALID) {
ret = rga_MapUserMemory(&pages[CMDMemSize + SrcMemSize], &MMU_Base[CMDMemSize + SrcMemSize], DstStart, DstMemSize);
if (ret < 0) {
pr_err("rga map dst memory failed\n");
status = ret;
break;
}
}
else {
MMU_p = MMU_Base + CMDMemSize + SrcMemSize;
for(i=0; i<DstMemSize; i++)
MMU_p[i] = (uint32_t)virt_to_phys((uint32_t *)((DstStart + i) << PAGE_SHIFT));
}
/* zsq
* change the buf address in req struct
* for the reason of lie to MMU
*/
req->mmu_info.base_addr = (virt_to_phys(MMU_Base)>>2);
req->src.yrgb_addr = (req->src.yrgb_addr & (~PAGE_MASK)) | (CMDMemSize << PAGE_SHIFT);
req->dst.yrgb_addr = (req->dst.yrgb_addr & (~PAGE_MASK)) | ((CMDMemSize + SrcMemSize) << PAGE_SHIFT);
/*record the malloc buf for the cmd end to release*/
reg->MMU_base = MMU_Base;
/* flush data to DDR */
rga_dma_flush_range(MMU_Base, (MMU_Base + AllSize + 1));
rga_mmu_buf_get(&rga_mmu_buf, AllSize + 16);
reg->MMU_len = AllSize + 16;
return status;
}
while(0);
return 0;
}
static int rga_mmu_info_color_fill_mode(struct rga_reg *reg, struct rga_req *req)
{
int DstMemSize;
unsigned long DstStart;
struct page **pages = NULL;
uint32_t i;
uint32_t AllSize;
uint32_t *MMU_Base, *MMU_p, *MMU_Base_phys;
int ret;
int status;
MMU_Base = NULL;
do {
DstMemSize = rga_buf_size_cal(req->dst.yrgb_addr, req->dst.uv_addr, req->dst.v_addr,
req->dst.format, req->dst.vir_w, req->dst.vir_h,
&DstStart);
if(DstMemSize == 0) {
return -EINVAL;
}
AllSize = (DstMemSize + 15) & (~15);
pages = rga_mmu_buf.pages;
if (rga_mmu_buf_get_try(&rga_mmu_buf, AllSize + 16)) {
pr_err("RGA Get MMU mem failed\n");
status = RGA_MALLOC_ERROR;
break;
}
mutex_lock(&rga_service.lock);
MMU_Base = rga_mmu_buf.buf_virtual + (rga_mmu_buf.front & (rga_mmu_buf.size - 1));
MMU_Base_phys = rga_mmu_buf.buf + (rga_mmu_buf.front & (rga_mmu_buf.size - 1));
mutex_unlock(&rga_service.lock);
if (req->dst.yrgb_addr < KERNEL_SPACE_VALID) {
if (req->sg_dst) {
ret = rga_MapION(req->sg_dst, &MMU_Base[0], DstMemSize, req->line_draw_info.line_width);
}
else {
ret = rga_MapUserMemory(&pages[0], &MMU_Base[0], DstStart, DstMemSize);
if (ret < 0) {
pr_err("rga map dst memory failed\n");
status = ret;
break;
}
}
}
else {
MMU_p = MMU_Base;
for(i=0; i<DstMemSize; i++)
MMU_p[i] = (uint32_t)((DstStart + i) << PAGE_SHIFT);
}
MMU_Base[AllSize] = MMU_Base[AllSize - 1];
/* zsq
* change the buf address in req struct
*/
req->mmu_info.base_addr = ((unsigned long)(MMU_Base_phys)>>2);
req->dst.yrgb_addr = (req->dst.yrgb_addr & (~PAGE_MASK));
/*record the malloc buf for the cmd end to release*/
reg->MMU_base = MMU_Base;
/* flush data to DDR */
rga_dma_flush_range(MMU_Base, (MMU_Base + AllSize + 1));
rga_mmu_buf_get(&rga_mmu_buf, AllSize + 16);
reg->MMU_len = AllSize + 16;
return 0;
}
while(0);
return status;
}
static int rga_mmu_info_line_point_drawing_mode(struct rga_reg *reg, struct rga_req *req)
{
return 0;
}
static int rga_mmu_info_blur_sharp_filter_mode(struct rga_reg *reg, struct rga_req *req)
{
return 0;
}
static int rga_mmu_info_pre_scale_mode(struct rga_reg *reg, struct rga_req *req)
{
int SrcMemSize, DstMemSize;
unsigned long SrcStart, DstStart;
struct page **pages = NULL;
uint32_t i;
uint32_t AllSize;
uint32_t *MMU_Base, *MMU_p, *MMU_Base_phys;
int ret;
int status;
uint32_t uv_size, v_size;
MMU_Base = NULL;
do {
/* cal src buf mmu info */
SrcMemSize = rga_buf_size_cal(req->src.yrgb_addr, req->src.uv_addr, req->src.v_addr,
req->src.format, req->src.vir_w, req->src.vir_h,
&SrcStart);
if(SrcMemSize == 0) {
return -EINVAL;
}
/* cal dst buf mmu info */
DstMemSize = rga_buf_size_cal(req->dst.yrgb_addr, req->dst.uv_addr, req->dst.v_addr,
req->dst.format, req->dst.vir_w, req->dst.vir_h,
&DstStart);
if(DstMemSize == 0) {
return -EINVAL;
}
SrcMemSize = (SrcMemSize + 15) & (~15);
DstMemSize = (DstMemSize + 15) & (~15);
AllSize = SrcMemSize + DstMemSize;
pages = rga_mmu_buf.pages;
if (rga_mmu_buf_get_try(&rga_mmu_buf, AllSize + 16)) {
pr_err("RGA Get MMU mem failed\n");
status = RGA_MALLOC_ERROR;
break;
}
mutex_lock(&rga_service.lock);
MMU_Base = rga_mmu_buf.buf_virtual + (rga_mmu_buf.front & (rga_mmu_buf.size - 1));
MMU_Base_phys = rga_mmu_buf.buf + (rga_mmu_buf.front & (rga_mmu_buf.size - 1));
mutex_unlock(&rga_service.lock);
/* map src pages */
if ((req->mmu_info.mmu_flag >> 8) & 1) {
if (req->sg_src) {
ret = rga_MapION(req->sg_src, &MMU_Base[0], SrcMemSize,req->line_draw_info.flag);
}
else {
ret = rga_MapUserMemory(&pages[0], &MMU_Base[0], SrcStart, SrcMemSize);
if (ret < 0) {
pr_err("rga map src memory failed\n");
status = ret;
break;
}
}
}
else {
MMU_p = MMU_Base;
for(i=0; i<SrcMemSize; i++)
MMU_p[i] = (uint32_t)((SrcStart + i) << PAGE_SHIFT);
}
if((req->mmu_info.mmu_flag >> 10) & 1) {
if (req->sg_dst) {
ret = rga_MapION(req->sg_dst, &MMU_Base[SrcMemSize], DstMemSize, req->line_draw_info.line_width);
}
else {
ret = rga_MapUserMemory(&pages[SrcMemSize], &MMU_Base[SrcMemSize], DstStart, DstMemSize);
if (ret < 0) {
pr_err("rga map dst memory failed\n");
status = ret;
break;
}
}
}
else
{
/* kernel space */
MMU_p = MMU_Base + SrcMemSize;
if(req->dst.yrgb_addr == (unsigned long)rga_service.pre_scale_buf) {
for(i=0; i<DstMemSize; i++)
MMU_p[i] = rga_service.pre_scale_buf[i];
}
else {
for(i=0; i<DstMemSize; i++)
MMU_p[i] = (uint32_t)((DstStart + i) << PAGE_SHIFT);
}
}
MMU_Base[AllSize] = MMU_Base[AllSize];
/* zsq
* change the buf address in req struct
* for the reason of lie to MMU
*/
req->mmu_info.base_addr = ((unsigned long)(MMU_Base_phys)>>2);
uv_size = (req->src.uv_addr - (SrcStart << PAGE_SHIFT)) >> PAGE_SHIFT;
v_size = (req->src.v_addr - (SrcStart << PAGE_SHIFT)) >> PAGE_SHIFT;
req->src.yrgb_addr = (req->src.yrgb_addr & (~PAGE_MASK));
req->src.uv_addr = (req->src.uv_addr & (~PAGE_MASK)) | (uv_size << PAGE_SHIFT);
req->src.v_addr = (req->src.v_addr & (~PAGE_MASK)) | (v_size << PAGE_SHIFT);
uv_size = (req->dst.uv_addr - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT;
v_size = (req->dst.v_addr - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT;
req->dst.yrgb_addr = (req->dst.yrgb_addr & (~PAGE_MASK)) | ((SrcMemSize) << PAGE_SHIFT);
req->dst.uv_addr = (req->dst.uv_addr & (~PAGE_MASK)) | ((SrcMemSize + uv_size) << PAGE_SHIFT);
req->dst.v_addr = (req->dst.v_addr & (~PAGE_MASK)) | ((SrcMemSize + v_size) << PAGE_SHIFT);
/*record the malloc buf for the cmd end to release*/
reg->MMU_base = MMU_Base;
/* flush data to DDR */
rga_dma_flush_range(MMU_Base, (MMU_Base + AllSize + 1));
rga_mmu_buf_get(&rga_mmu_buf, AllSize + 16);
reg->MMU_len = AllSize + 16;
return 0;
}
while(0);
return status;
}
static int rga_mmu_info_update_palette_table_mode(struct rga_reg *reg, struct rga_req *req)
{
int SrcMemSize, CMDMemSize;
unsigned long SrcStart, CMDStart;
struct page **pages = NULL;
uint32_t i;
uint32_t AllSize;
uint32_t *MMU_Base, *MMU_p;
int ret, status;
MMU_Base = NULL;
do {
/* cal src buf mmu info */
SrcMemSize = rga_mem_size_cal(req->src.yrgb_addr, req->src.vir_w * req->src.vir_h, &SrcStart);
if(SrcMemSize == 0) {
return -EINVAL;
}
/* cal cmd buf mmu info */
CMDMemSize = rga_mem_size_cal((unsigned long)rga_service.cmd_buff, RGA_CMD_BUF_SIZE, &CMDStart);
if(CMDMemSize == 0) {
return -EINVAL;
}
AllSize = SrcMemSize + CMDMemSize;
pages = kzalloc(AllSize * sizeof(struct page *), GFP_KERNEL);
if(pages == NULL) {
pr_err("RGA MMU malloc pages mem failed\n");
status = RGA_MALLOC_ERROR;
break;
}
MMU_Base = kzalloc((AllSize + 1)* sizeof(uint32_t), GFP_KERNEL);
if(pages == NULL) {
pr_err("RGA MMU malloc MMU_Base point failed\n");
status = RGA_MALLOC_ERROR;
break;
}
for(i=0; i<CMDMemSize; i++) {
MMU_Base[i] = (uint32_t)virt_to_phys((uint32_t *)((CMDStart + i) << PAGE_SHIFT));
}
if (req->src.yrgb_addr < KERNEL_SPACE_VALID)
{
ret = rga_MapUserMemory(&pages[CMDMemSize], &MMU_Base[CMDMemSize], SrcStart, SrcMemSize);
if (ret < 0) {
pr_err("rga map src memory failed\n");
return -EINVAL;
}
}
else
{
MMU_p = MMU_Base + CMDMemSize;
for(i=0; i<SrcMemSize; i++)
{
MMU_p[i] = (uint32_t)virt_to_phys((uint32_t *)((SrcStart + i) << PAGE_SHIFT));
}
}
/* zsq
* change the buf address in req struct
* for the reason of lie to MMU
*/
req->mmu_info.base_addr = (virt_to_phys(MMU_Base) >> 2);
req->src.yrgb_addr = (req->src.yrgb_addr & (~PAGE_MASK)) | (CMDMemSize << PAGE_SHIFT);
/*record the malloc buf for the cmd end to release*/
reg->MMU_base = MMU_Base;
/* flush data to DDR */
rga_dma_flush_range(MMU_Base, (MMU_Base + AllSize));
if (pages != NULL) {
/* Free the page table */
kfree(pages);
}
return 0;
}
while(0);
if (pages != NULL)
kfree(pages);
if (MMU_Base != NULL)
kfree(MMU_Base);
return status;
}
static int rga_mmu_info_update_patten_buff_mode(struct rga_reg *reg, struct rga_req *req)
{
int SrcMemSize, CMDMemSize;
unsigned long SrcStart, CMDStart;
struct page **pages = NULL;
uint32_t i;
uint32_t AllSize;
uint32_t *MMU_Base, *MMU_p;
int ret, status;
MMU_Base = MMU_p = 0;
do
{
/* cal src buf mmu info */
SrcMemSize = rga_mem_size_cal(req->pat.yrgb_addr, req->pat.vir_w * req->pat.vir_h * 4, &SrcStart);
if(SrcMemSize == 0) {
return -EINVAL;
}
/* cal cmd buf mmu info */
CMDMemSize = rga_mem_size_cal((unsigned long)rga_service.cmd_buff, RGA_CMD_BUF_SIZE, &CMDStart);
if(CMDMemSize == 0) {
return -EINVAL;
}
AllSize = SrcMemSize + CMDMemSize;
pages = kzalloc(AllSize * sizeof(struct page *), GFP_KERNEL);
if(pages == NULL) {
pr_err("RGA MMU malloc pages mem failed\n");
status = RGA_MALLOC_ERROR;
break;
}
MMU_Base = kzalloc(AllSize * sizeof(uint32_t), GFP_KERNEL);
if(MMU_Base == NULL) {
pr_err("RGA MMU malloc MMU_Base point failed\n");
status = RGA_MALLOC_ERROR;
break;
}
for(i=0; i<CMDMemSize; i++) {
MMU_Base[i] = virt_to_phys((uint32_t *)((CMDStart + i) << PAGE_SHIFT));
}
if (req->src.yrgb_addr < KERNEL_SPACE_VALID)
{
ret = rga_MapUserMemory(&pages[CMDMemSize], &MMU_Base[CMDMemSize], SrcStart, SrcMemSize);
if (ret < 0) {
pr_err("rga map src memory failed\n");
status = ret;
break;
}
}
else
{
MMU_p = MMU_Base + CMDMemSize;
for(i=0; i<SrcMemSize; i++)
{
MMU_p[i] = (uint32_t)virt_to_phys((uint32_t *)((SrcStart + i) << PAGE_SHIFT));
}
}
/* zsq
* change the buf address in req struct
* for the reason of lie to MMU
*/
req->mmu_info.base_addr = (virt_to_phys(MMU_Base) >> 2);
req->src.yrgb_addr = (req->src.yrgb_addr & (~PAGE_MASK)) | (CMDMemSize << PAGE_SHIFT);
/*record the malloc buf for the cmd end to release*/
reg->MMU_base = MMU_Base;
/* flush data to DDR */
rga_dma_flush_range(MMU_Base, (MMU_Base + AllSize));
if (pages != NULL) {
/* Free the page table */
kfree(pages);
}
return 0;
}
while(0);
if (pages != NULL)
kfree(pages);
if (MMU_Base != NULL)
kfree(MMU_Base);
return status;
}
int rga_set_mmu_info(struct rga_reg *reg, struct rga_req *req)
{
int ret;
switch (req->render_mode) {
case bitblt_mode :
ret = rga_mmu_info_BitBlt_mode(reg, req);
break;
case color_palette_mode :
ret = rga_mmu_info_color_palette_mode(reg, req);
break;
case color_fill_mode :
ret = rga_mmu_info_color_fill_mode(reg, req);
break;
case line_point_drawing_mode :
ret = rga_mmu_info_line_point_drawing_mode(reg, req);
break;
case blur_sharp_filter_mode :
ret = rga_mmu_info_blur_sharp_filter_mode(reg, req);
break;
case pre_scaling_mode :
ret = rga_mmu_info_pre_scale_mode(reg, req);
break;
case update_palette_table_mode :
ret = rga_mmu_info_update_palette_table_mode(reg, req);
break;
case update_patten_buff_mode :
ret = rga_mmu_info_update_patten_buff_mode(reg, req);
break;
default :
ret = -1;
break;
}
return ret;
}