/* SPDX-License-Identifier: GPL-2.0 */ #define pr_fmt(fmt) "rga2_mmu: " fmt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)) #include #endif #include "rga2_mmu_info.h" #include "rga2_debugger.h" extern struct rga2_service_info rga2_service; extern struct rga2_mmu_buf_t rga2_mmu_buf; extern struct rga2_drvdata_t *rga2_drvdata; //extern int mmu_buff_temp[1024]; #define KERNEL_SPACE_VALID 0xc0000000 #define V7_VATOPA_SUCESS_MASK (0x1) #define V7_VATOPA_GET_PADDR(X) (X & 0xFFFFF000) #define V7_VATOPA_GET_INER(X) ((X>>4) & 7) #define V7_VATOPA_GET_OUTER(X) ((X>>2) & 3) #define V7_VATOPA_GET_SH(X) ((X>>7) & 1) #define V7_VATOPA_GET_NS(X) ((X>>9) & 1) #define V7_VATOPA_GET_SS(X) ((X>>1) & 1) void rga2_dma_flush_range(void *pstart, void *pend) { dma_sync_single_for_device(rga2_drvdata->dev, virt_to_phys(pstart), pend - pstart, DMA_TO_DEVICE); } dma_addr_t rga2_dma_flush_page(struct page *page, int map) { dma_addr_t paddr; /* * Through dma_map_page to ensure that the physical address * will not exceed the addressing range of dma. */ if (map & MMU_MAP_MASK) { switch (map) { case MMU_MAP_CLEAN: paddr = dma_map_page(rga2_drvdata->dev, page, 0, PAGE_SIZE, DMA_TO_DEVICE); break; case MMU_MAP_INVALID: paddr = dma_map_page(rga2_drvdata->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); break; case MMU_MAP_CLEAN | MMU_MAP_INVALID: paddr = dma_map_page(rga2_drvdata->dev, page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); break; default: paddr = 0; pr_err("unknown map cmd 0x%x\n", map); break; } return paddr; } else if (map & MMU_UNMAP_MASK) { paddr = page_to_phys(page); switch (map) { case MMU_UNMAP_CLEAN: dma_unmap_page(rga2_drvdata->dev, paddr, PAGE_SIZE, DMA_TO_DEVICE); break; case MMU_UNMAP_INVALID: dma_unmap_page(rga2_drvdata->dev, paddr, PAGE_SIZE, DMA_FROM_DEVICE); break; case MMU_UNMAP_CLEAN | MMU_UNMAP_INVALID: dma_unmap_page(rga2_drvdata->dev, paddr, PAGE_SIZE, DMA_BIDIRECTIONAL); break; default: pr_err("unknown map cmd 0x%x\n", map); break; } return paddr; } pr_err("RGA2 failed to flush page, map= %x\n", map); return 0; } #if 0 static unsigned int armv7_va_to_pa(unsigned int v_addr) { unsigned int p_addr; __asm__ volatile ( "mcr p15, 0, %1, c7, c8, 0\n" "isb\n" "dsb\n" "mrc p15, 0, %0, c7, c4, 0\n" : "=r" (p_addr) : "r" (v_addr) : "cc"); if (p_addr & V7_VATOPA_SUCESS_MASK) return 0xFFFFFFFF; else return (V7_VATOPA_GET_SS(p_addr) ? 0xFFFFFFFF : V7_VATOPA_GET_PADDR(p_addr)); } #endif static bool rga2_is_yuv422p_format(u32 format) { bool ret = false; switch (format) { case RGA2_FORMAT_YCbCr_422_P: case RGA2_FORMAT_YCrCb_422_P: ret = true; break; } return ret; } #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER static int rga2_get_format_bits(u32 format) { int bits = 0; switch (format) { case RGA2_FORMAT_RGBA_8888: case RGA2_FORMAT_RGBX_8888: case RGA2_FORMAT_BGRA_8888: case RGA2_FORMAT_BGRX_8888: case RGA2_FORMAT_ARGB_8888: case RGA2_FORMAT_XRGB_8888: case RGA2_FORMAT_ABGR_8888: case RGA2_FORMAT_XBGR_8888: bits = 32; break; case RGA2_FORMAT_RGB_888: case RGA2_FORMAT_BGR_888: bits = 24; break; case RGA2_FORMAT_RGB_565: case RGA2_FORMAT_RGBA_5551: case RGA2_FORMAT_RGBA_4444: case RGA2_FORMAT_BGR_565: case RGA2_FORMAT_YCbCr_422_SP: case RGA2_FORMAT_YCbCr_422_P: case RGA2_FORMAT_YCrCb_422_SP: case RGA2_FORMAT_YCrCb_422_P: case RGA2_FORMAT_BGRA_5551: case RGA2_FORMAT_BGRA_4444: case RGA2_FORMAT_ARGB_5551: case RGA2_FORMAT_ARGB_4444: case RGA2_FORMAT_ABGR_5551: case RGA2_FORMAT_ABGR_4444: bits = 16; break; case RGA2_FORMAT_YCbCr_420_SP: case RGA2_FORMAT_YCbCr_420_P: case RGA2_FORMAT_YCrCb_420_SP: case RGA2_FORMAT_YCrCb_420_P: bits = 12; break; case RGA2_FORMAT_YCbCr_420_SP_10B: case RGA2_FORMAT_YCrCb_420_SP_10B: case RGA2_FORMAT_YCbCr_422_SP_10B: case RGA2_FORMAT_YCrCb_422_SP_10B: bits = 15; break; default: pr_err("unknown format [%d]\n", format); return -1; } return bits; } static int rga2_user_memory_check(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; bits = rga2_get_format_bits(format); if (bits < 0) 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) { pr_info("src user memory check\n"); pr_info("tai data is %d\n", *tai_vaddr); } else { pr_info("dst user memory check\n"); pr_info("tai data is %d\n", *tai_vaddr); } if (taidata_num == 0) kunmap(pages[taipage_num - 1]); else kunmap(pages[taipage_num]); return 0; } static int rga2_virtual_memory_check(void *vaddr, u32 w, u32 h, u32 format, int fd) { int bits = 32; int temp_data = 0; void *one_line = NULL; bits = rga2_get_format_bits(format); if (bits < 0) return -1; one_line = kzalloc(w * 4, GFP_KERNEL); if (!one_line) { ERR("kzalloc fail %s[%d]\n", __func__, __LINE__); return 0; } temp_data = w * (h - 1) * bits >> 3; if (fd > 0) { INFO("vaddr is%p, bits is %d, fd check\n", vaddr, bits); memcpy(one_line, (char *)vaddr + temp_data, w * bits >> 3); INFO("fd check ok\n"); } else { INFO("vir addr memory check.\n"); memcpy((void *)((char *)vaddr + temp_data), one_line, w * bits >> 3); INFO("vir addr check ok.\n"); } kfree(one_line); return 0; } static int rga2_dma_memory_check(struct rga_dma_buffer_t *buffer, struct rga_img_info_t *img) { int ret = 0; void *vaddr; struct dma_buf *dma_buffer; dma_buffer = buffer->dma_buf; if (!IS_ERR_OR_NULL(dma_buffer)) { vaddr = dma_buf_vmap(dma_buffer); if (vaddr) { ret = rga2_virtual_memory_check(vaddr, img->vir_w, img->vir_h, img->format, img->yrgb_addr); } else { pr_err("can't vmap the dma buffer!\n"); return -EINVAL; } dma_buf_vunmap(dma_buffer, vaddr); } return ret; } #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) static int rga2_map_dma_buffer(int fd, struct rga_dma_buffer_t *rga_dma_buffer, enum dma_data_direction dir) { struct device *rga_dev = NULL; struct dma_buf *dma_buf = NULL; struct dma_buf_attachment *attach = NULL; struct sg_table *sgt = NULL; int ret = 0; rga_dev = rga2_drvdata->dev; dma_buf = dma_buf_get(fd); if (IS_ERR(dma_buf)) { ret = -EINVAL; pr_err("dma_buf_get fail fd[%d]\n", fd); return ret; } attach = dma_buf_attach(dma_buf, rga_dev); if (IS_ERR(attach)) { ret = -EINVAL; pr_err("Failed to attach dma_buf\n"); goto err_get_attach; } sgt = dma_buf_map_attachment(attach, dir); if (IS_ERR(sgt)) { ret = -EINVAL; pr_err("Failed to map src attachment\n"); goto err_get_sgt; } rga_dma_buffer->dma_buf = dma_buf; rga_dma_buffer->attach = attach; rga_dma_buffer->sgt = sgt; rga_dma_buffer->size = sg_dma_len(sgt->sgl); rga_dma_buffer->dir = dir; return ret; err_get_sgt: if (attach) dma_buf_detach(dma_buf, attach); err_get_attach: if (dma_buf) dma_buf_put(dma_buf); return ret; } static void rga2_unmap_dma_buffer(struct rga_dma_buffer_t *rga_dma_buffer) { if (rga_dma_buffer->attach && rga_dma_buffer->sgt) dma_buf_unmap_attachment(rga_dma_buffer->attach, rga_dma_buffer->sgt, rga_dma_buffer->dir); if (rga_dma_buffer->attach) { dma_buf_detach(rga_dma_buffer->dma_buf, rga_dma_buffer->attach); dma_buf_put(rga_dma_buffer->dma_buf); } } static void rga2_convert_addr(struct rga_img_info_t *img) { /* * If it is not using dma fd, the virtual/phyical address is assigned * to the address of the corresponding channel. */ img->yrgb_addr = img->uv_addr; img->uv_addr = img->yrgb_addr + (img->vir_w * img->vir_h); if (rga2_is_yuv422p_format(img->format)) img->v_addr = img->uv_addr + (img->vir_w * img->vir_h) / 2; else img->v_addr = img->uv_addr + (img->vir_w * img->vir_h) / 4; } int rga2_get_dma_info(struct rga2_reg *reg, struct rga2_req *req) { uint32_t mmu_flag; int ret; struct rga_dma_buffer_t *buffer_src0, *buffer_src1, *buffer_dst, *buffer_els; struct rga_img_info_t *src0, *src1, *dst, *els; /* * Since the life cycle of rga2_req cannot satisfy the release of * dmabuffer after the task is over, the mapped dmabuffer is saved * in rga2_reg. */ buffer_src0 = ®->dma_buffer_src0; buffer_src1 = ®->dma_buffer_src1; buffer_dst = ®->dma_buffer_dst; buffer_els = ®->dma_buffer_els; src0 = &req->src; src1 = &req->src1; dst = &req->dst; els = &req->pat; /* src0 chanel */ mmu_flag = req->mmu_info.src0_mmu_flag; if (unlikely(!mmu_flag && src0->yrgb_addr)) { pr_err("Fix it please enable src0 mmu\n"); return -EINVAL; } else if (mmu_flag && src0->yrgb_addr) { ret = rga2_map_dma_buffer(src0->yrgb_addr, buffer_src0, DMA_BIDIRECTIONAL); if (ret < 0) { pr_err("src0: can't map dma-buf\n"); return ret; } } #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) { ret = rga2_dma_memory_check(buffer_src0, src0); if (ret < 0) { pr_err("src0 channel check memory error!\n"); return ret; } } #endif rga2_convert_addr(src0); /* src1 chanel */ mmu_flag = req->mmu_info.src1_mmu_flag; if (unlikely(!mmu_flag && src1->yrgb_addr)) { pr_err("Fix it please enable src1 mmu\n"); ret = -EINVAL; goto err_src1_channel; } else if (mmu_flag && src1->yrgb_addr) { ret = rga2_map_dma_buffer(src1->yrgb_addr, buffer_src1, DMA_BIDIRECTIONAL); if (ret < 0) { pr_err("src1: can't map dma-buf\n"); goto err_src1_channel; } } #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) { ret = rga2_dma_memory_check(buffer_src1, src1); if (ret < 0) { pr_err("src1 channel check memory error!\n"); goto err_src1_channel; } } #endif rga2_convert_addr(src1); /* dst chanel */ mmu_flag = req->mmu_info.dst_mmu_flag; if (unlikely(!mmu_flag && dst->yrgb_addr)) { pr_err("Fix it please enable dst mmu\n"); ret = -EINVAL; goto err_dst_channel; } else if (mmu_flag && dst->yrgb_addr) { ret = rga2_map_dma_buffer(dst->yrgb_addr, buffer_dst, DMA_BIDIRECTIONAL); if (ret < 0) { pr_err("dst: can't map dma-buf\n"); goto err_dst_channel; } } #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) { ret = rga2_dma_memory_check(buffer_dst, dst); if (ret < 0) { pr_err("dst channel check memory error!\n"); goto err_dst_channel; } } #endif rga2_convert_addr(dst); /* els chanel */ mmu_flag = req->mmu_info.els_mmu_flag; if (unlikely(!mmu_flag && els->yrgb_addr)) { pr_err("Fix it please enable els mmu\n"); ret = -EINVAL; goto err_els_channel; } else if (mmu_flag && els->yrgb_addr) { ret = rga2_map_dma_buffer(els->yrgb_addr, buffer_els, DMA_BIDIRECTIONAL); if (ret < 0) { pr_err("els: can't map dma-buf\n"); goto err_els_channel; } } #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) { ret = rga2_dma_memory_check(buffer_els, els); if (ret < 0) { pr_err("els channel check memory error!\n"); goto err_els_channel; } } #endif rga2_convert_addr(els); return 0; err_els_channel: rga2_unmap_dma_buffer(buffer_dst); err_dst_channel: rga2_unmap_dma_buffer(buffer_src1); err_src1_channel: rga2_unmap_dma_buffer(buffer_src0); return ret; } void rga2_put_dma_info(struct rga2_reg *reg) { rga2_unmap_dma_buffer(®->dma_buffer_src0); rga2_unmap_dma_buffer(®->dma_buffer_src1); rga2_unmap_dma_buffer(®->dma_buffer_dst); rga2_unmap_dma_buffer(®->dma_buffer_els); } #else static int rga2_get_dma_info(struct rga2_reg *reg, struct rga2_req *req) { struct ion_handle *hdl; ion_phys_addr_t phy_addr; size_t len; int ret; u32 src_vir_w, dst_vir_w; void *vaddr = NULL; struct rga_dma_buffer_t *buffer_src0, *buffer_src1, *buffer_dst, *buffer_els; src_vir_w = req->src.vir_w; dst_vir_w = req->dst.vir_w; buffer_src0 = ®->dma_buffer_src0; buffer_src1 = ®->dma_buffer_src1; buffer_dst = ®->dma_buffer_dst; buffer_els = ®->dma_buffer_els; if ((int)req->src.yrgb_addr > 0) { hdl = ion_import_dma_buf(rga2_drvdata->ion_client, req->src.yrgb_addr); if (IS_ERR(hdl)) { ret = PTR_ERR(hdl); pr_err("RGA2 SRC ERROR ion buf handle\n"); return ret; } #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) { vaddr = ion_map_kernel(rga2_drvdata->ion_client, hdl); if (vaddr) rga2_memory_check(vaddr, req->src.vir_w, req->src.vir_h, req->src.format, req->src.yrgb_addr); ion_unmap_kernel(rga2_drvdata->ion_client, hdl); } #endif if (req->mmu_info.src0_mmu_flag) { buffer_src0.sgt = ion_sg_table(rga2_drvdata->ion_client, hdl); req->src.yrgb_addr = req->src.uv_addr; req->src.uv_addr = req->src.yrgb_addr + (src_vir_w * req->src.vir_h); req->src.v_addr = req->src.uv_addr + (src_vir_w * req->src.vir_h) / 4; } else { ion_phys(rga2_drvdata->ion_client, hdl, &phy_addr, &len); req->src.yrgb_addr = phy_addr; req->src.uv_addr = req->src.yrgb_addr + (src_vir_w * req->src.vir_h); req->src.v_addr = req->src.uv_addr + (src_vir_w * req->src.vir_h) / 4; } ion_free(rga2_drvdata->ion_client, hdl); } else { req->src.yrgb_addr = req->src.uv_addr; req->src.uv_addr = req->src.yrgb_addr + (src_vir_w * req->src.vir_h); req->src.v_addr = req->src.uv_addr + (src_vir_w * req->src.vir_h) / 4; } if ((int)req->dst.yrgb_addr > 0) { hdl = ion_import_dma_buf(rga2_drvdata->ion_client, req->dst.yrgb_addr); if (IS_ERR(hdl)) { ret = PTR_ERR(hdl); pr_err("RGA2 DST ERROR ion buf handle\n"); return ret; } #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) { vaddr = ion_map_kernel(rga2_drvdata->ion_client, hdl); if (vaddr) rga2_memory_check(vaddr, req->dst.vir_w, req->dst.vir_h, req->dst.format, req->dst.yrgb_addr); ion_unmap_kernel(rga2_drvdata->ion_client, hdl); } #endif if (req->mmu_info.dst_mmu_flag) { buffer_dst.sgt = ion_sg_table(rga2_drvdata->ion_client, hdl); req->dst.yrgb_addr = req->dst.uv_addr; req->dst.uv_addr = req->dst.yrgb_addr + (dst_vir_w * req->dst.vir_h); req->dst.v_addr = req->dst.uv_addr + (dst_vir_w * req->dst.vir_h) / 4; } else { ion_phys(rga2_drvdata->ion_client, hdl, &phy_addr, &len); req->dst.yrgb_addr = phy_addr; req->dst.uv_addr = req->dst.yrgb_addr + (dst_vir_w * req->dst.vir_h); req->dst.v_addr = req->dst.uv_addr + (dst_vir_w * req->dst.vir_h) / 4; } ion_free(rga2_drvdata->ion_client, hdl); } else { req->dst.yrgb_addr = req->dst.uv_addr; req->dst.uv_addr = req->dst.yrgb_addr + (dst_vir_w * req->dst.vir_h); req->dst.v_addr = req->dst.uv_addr + (dst_vir_w * req->dst.vir_h) / 4; } if ((int)req->src1.yrgb_addr > 0) { hdl = ion_import_dma_buf(rga2_drvdata->ion_client, req->src1.yrgb_addr); if (IS_ERR(hdl)) { ret = PTR_ERR(hdl); pr_err("RGA2 ERROR ion buf handle\n"); return ret; } if (req->mmu_info.dst_mmu_flag) { buffer_src1.sgt = ion_sg_table(rga2_drvdata->ion_client, hdl); req->src1.yrgb_addr = req->src1.uv_addr; req->src1.uv_addr = req->src1.yrgb_addr + (req->src1.vir_w * req->src1.vir_h); req->src1.v_addr = req->src1.uv_addr + (req->src1.vir_w * req->src1.vir_h) / 4; } else { ion_phys(rga2_drvdata->ion_client, hdl, &phy_addr, &len); req->src1.yrgb_addr = phy_addr; req->src1.uv_addr = req->src1.yrgb_addr + (req->src1.vir_w * req->src1.vir_h); req->src1.v_addr = req->src1.uv_addr + (req->src1.vir_w * req->src1.vir_h) / 4; } ion_free(rga2_drvdata->ion_client, hdl); } else { req->src1.yrgb_addr = req->src1.uv_addr; req->src1.uv_addr = req->src1.yrgb_addr + (req->src1.vir_w * req->src1.vir_h); req->src1.v_addr = req->src1.uv_addr + (req->src1.vir_w * req->src1.vir_h) / 4; } if (rga2_is_yuv422p_format(req->src.format)) req->src.v_addr = req->src.uv_addr + (req->src.vir_w * req->src.vir_h) / 2; if (rga2_is_yuv422p_format(req->dst.format)) req->dst.v_addr = req->dst.uv_addr + (req->dst.vir_w * req->dst.vir_h) / 2; if (rga2_is_yuv422p_format(req->src1.format)) req->src1.v_addr = req->src1.uv_addr + (req->src1.vir_w * req->dst.vir_h) / 2; return 0; } /* When the kernel version is lower than 4.4, no put buffer operation is required. */ void rga2_put_dma_info(struct rga2_reg *reg) {} #endif static int rga2_mmu_buf_get(struct rga2_mmu_buf_t *t, uint32_t size) { mutex_lock(&rga2_service.lock); t->front += size; mutex_unlock(&rga2_service.lock); return 0; } static int rga2_mmu_buf_get_try(struct rga2_mmu_buf_t *t, uint32_t size) { int ret = 0; mutex_lock(&rga2_service.lock); if ((t->back - t->front) > t->size) { if (t->front + size > t->back - t->size) { pr_info("front %d, back %d dsize %d size %d", t->front, t->back, t->size, size); ret = -ENOMEM; goto out; } } else { if ((t->front + size) > t->back) { pr_info("front %d, back %d dsize %d size %d", t->front, t->back, t->size, size); ret = -ENOMEM; goto out; } if (t->front + size > t->size) { if (size > (t->back - t->size)) { pr_info("front %d, back %d dsize %d size %d", t->front, t->back, t->size, size); ret = -ENOMEM; goto out; } t->front = 0; } } out: mutex_unlock(&rga2_service.lock); return ret; } static int rga2_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 rga2_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 RGA2_FORMAT_RGBA_8888 : case RGA2_FORMAT_RGBX_8888 : case RGA2_FORMAT_BGRA_8888 : case RGA2_FORMAT_BGRX_8888 : case RGA2_FORMAT_ARGB_8888 : case RGA2_FORMAT_XRGB_8888 : case RGA2_FORMAT_ABGR_8888 : case RGA2_FORMAT_XBGR_8888 : stride = (w * 4 + 3) & (~3); size_yrgb = stride*h; start = yrgb_addr >> PAGE_SHIFT; end = yrgb_addr + size_yrgb; end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; pageCount = end - start; break; case RGA2_FORMAT_RGB_888 : case RGA2_FORMAT_BGR_888 : stride = (w * 3 + 3) & (~3); size_yrgb = stride*h; start = yrgb_addr >> PAGE_SHIFT; end = yrgb_addr + size_yrgb; end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; pageCount = end - start; break; case RGA2_FORMAT_RGB_565 : case RGA2_FORMAT_RGBA_5551 : case RGA2_FORMAT_RGBA_4444 : case RGA2_FORMAT_BGR_565 : case RGA2_FORMAT_BGRA_5551 : case RGA2_FORMAT_BGRA_4444 : case RGA2_FORMAT_ARGB_5551 : case RGA2_FORMAT_ARGB_4444 : case RGA2_FORMAT_ABGR_5551 : case RGA2_FORMAT_ABGR_4444 : stride = (w*2 + 3) & (~3); size_yrgb = stride * h; start = yrgb_addr >> PAGE_SHIFT; end = yrgb_addr + size_yrgb; end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; pageCount = end - start; break; /* YUV FORMAT */ case RGA2_FORMAT_YCbCr_422_SP : case RGA2_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 RGA2_FORMAT_YCbCr_422_P : case RGA2_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 = 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 RGA2_FORMAT_YCbCr_420_SP : case RGA2_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 RGA2_FORMAT_YCbCr_420_P : case RGA2_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; case RGA2_FORMAT_YCbCr_400: stride = (w + 3) & (~3); size_yrgb = stride * h; size_uv = 0; size_v = 0; start = yrgb_addr >> PAGE_SHIFT; end = yrgb_addr + size_yrgb; end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; pageCount = end - start; break; case RGA2_FORMAT_Y4: stride = ((w + 3) & (~3) ) >> 1; size_yrgb = stride * h; size_uv = 0; size_v = 0; start = yrgb_addr >> PAGE_SHIFT; end = yrgb_addr + size_yrgb; end = (end + (PAGE_SIZE - 1)) >> PAGE_SHIFT; pageCount = end - start; break; case RGA2_FORMAT_YVYU_422: case RGA2_FORMAT_VYUY_422: case RGA2_FORMAT_YUYV_422: case RGA2_FORMAT_UYVY_422: 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 RGA2_FORMAT_YVYU_420: case RGA2_FORMAT_VYUY_420: case RGA2_FORMAT_YUYV_420: case RGA2_FORMAT_UYVY_420: 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; #if 0 case RK_FORMAT_BPP1 : break; case RK_FORMAT_BPP2 : break; case RK_FORMAT_BPP4 : break; case RK_FORMAT_BPP8 : break; #endif case RGA2_FORMAT_YCbCr_420_SP_10B: case RGA2_FORMAT_YCrCb_420_SP_10B: 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; default : pageCount = 0; start = 0; break; } *StartAddr = start; return pageCount; } static int rga2_MapUserMemory(struct page **pages, uint32_t *pageTable, unsigned long Memory, uint32_t pageCount, int writeFlag, int map) { struct vm_area_struct *vma; int32_t result; uint32_t i; uint32_t status; unsigned long Address; unsigned long pfn; struct page __maybe_unused *page; spinlock_t * ptl; pte_t * pte; pgd_t * pgd; #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) p4d_t * p4d; #endif pud_t * pud; pmd_t * pmd; status = 0; Address = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) mmap_read_lock(current->mm); #else down_read(¤t->mm->mmap_sem); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 168) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0) result = 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) result = get_user_pages(current, current->mm, Memory << PAGE_SHIFT, pageCount, writeFlag, 0, pages, NULL); #elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) result = get_user_pages_remote(current, current->mm, Memory << PAGE_SHIFT, pageCount, writeFlag, pages, NULL, NULL); #else result = get_user_pages_remote(current->mm, Memory << PAGE_SHIFT, pageCount, writeFlag, pages, NULL, NULL); #endif if (result > 0 && result >= pageCount) { /* Fill the page table. */ for (i = 0; i < pageCount; i++) { /* Get the physical address from page struct. */ pageTable[i] = rga2_dma_flush_page(pages[i], map); } for (i = 0; i < result; i++) put_page(pages[i]); #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) mmap_read_unlock(current->mm); #else up_read(¤t->mm->mmap_sem); #endif return 0; } if (result > 0) { for (i = 0; i < result; i++) put_page(pages[i]); } for (i = 0; i < pageCount; i++) { vma = find_vma(current->mm, (Memory + i) << PAGE_SHIFT); if (!vma) { pr_err("RGA2 failed to get vma, result = %d, pageCount = %d\n", result, pageCount); status = RGA2_OUT_OF_RESOURCES; break; } pgd = pgd_offset(current->mm, (Memory + i) << PAGE_SHIFT); if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) { pr_err("RGA2 failed to get pgd, result = %d, pageCount = %d\n", result, pageCount); status = RGA2_OUT_OF_RESOURCES; 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 = RGA2_OUT_OF_RESOURCES; break; } pud = pud_offset(p4d, (Memory + i) << PAGE_SHIFT); #else pud = pud_offset(pgd, (Memory + i) << PAGE_SHIFT); #endif if (pud_none(*pud) || unlikely(pud_bad(*pud))) { pr_err("RGA2 failed to get pud, result = %d, pageCount = %d\n", result, pageCount); status = RGA2_OUT_OF_RESOURCES; break; } pmd = pmd_offset(pud, (Memory + i) << PAGE_SHIFT); if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) { pr_err("RGA2 failed to get pmd, result = %d, pageCount = %d\n", result, pageCount); status = RGA2_OUT_OF_RESOURCES; break; } pte = pte_offset_map_lock(current->mm, pmd, (Memory + i) << PAGE_SHIFT, &ptl); if (pte_none(*pte)) { pr_err("RGA2 failed to get pte, result = %d, pageCount = %d\n", result, pageCount); pte_unmap_unlock(pte, ptl); status = RGA2_OUT_OF_RESOURCES; break; } pfn = pte_pfn(*pte); Address = ((pfn << PAGE_SHIFT) | (((unsigned long)((Memory + i) << PAGE_SHIFT)) & ~PAGE_MASK)); pageTable[i] = rga2_dma_flush_page(phys_to_page(Address), map); pte_unmap_unlock(pte, ptl); } #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) mmap_read_unlock(current->mm); #else up_read(¤t->mm->mmap_sem); #endif return status; } static int rga2_MapION(struct sg_table *sg, uint32_t *Memory, int32_t pageCount) { uint32_t i; uint32_t status; unsigned long Address; uint32_t mapped_size = 0; uint32_t len; struct scatterlist *sgl = sg->sgl; uint32_t sg_num = 0; uint32_t break_flag = 0; status = 0; Address = 0; do { len = sg_dma_len(sgl) >> PAGE_SHIFT; /* * The fd passed by user space gets sg through dma_buf_map_attachment, * so dma_address can be use here. */ Address = sg_dma_address(sgl); for(i=0; i= pageCount) { break_flag = 1; break; } Memory[mapped_size + i] = (uint32_t)(Address + (i << PAGE_SHIFT)); } if (break_flag) break; mapped_size += len; sg_num += 1; } while((sgl = sg_next(sgl)) && (mapped_size < pageCount) && (sg_num < sg->nents)); return 0; } static int rga2_mmu_flush_cache(struct rga2_reg *reg, struct rga2_req *req) { int DstMemSize; unsigned long DstStart, DstPageCount; uint32_t *MMU_Base, *MMU_Base_phys; int ret; int status; struct page **pages = NULL; struct rga_dma_buffer_t *dma_buffer = NULL; MMU_Base = NULL; DstMemSize = 0; DstPageCount = 0; DstStart = 0; if (reg->MMU_map != true) { status = -EINVAL; goto out; } /* cal dst buf mmu info */ if (req->mmu_info.dst_mmu_flag & 1) { DstPageCount = rga2_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 (DstPageCount == 0) return -EINVAL; } /* Cal out the needed mem size */ DstMemSize = (DstPageCount + 15) & (~15); if (rga2_mmu_buf_get_try(&rga2_mmu_buf, DstMemSize)) { pr_err("RGA2 Get MMU mem failed\n"); status = RGA2_MALLOC_ERROR; goto out; } pages = rga2_mmu_buf.pages; mutex_lock(&rga2_service.lock); MMU_Base = rga2_mmu_buf.buf_virtual + (rga2_mmu_buf.front & (rga2_mmu_buf.size - 1)); MMU_Base_phys = rga2_mmu_buf.buf + (rga2_mmu_buf.front & (rga2_mmu_buf.size - 1)); mutex_unlock(&rga2_service.lock); if (DstMemSize) { dma_buffer = ®->dma_buffer_dst; if (dma_buffer->sgt) { status = -EINVAL; goto out; } else { ret = rga2_MapUserMemory(&pages[0], MMU_Base, DstStart, DstPageCount, 1, MMU_MAP_CLEAN | MMU_MAP_INVALID); #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) rga2_user_memory_check(&pages[0], req->dst.vir_w, req->dst.vir_h, req->dst.format, 2); #endif } if (ret < 0) { pr_err("rga2 unmap dst memory failed\n"); status = ret; goto out; } } rga2_mmu_buf_get(&rga2_mmu_buf, DstMemSize); reg->MMU_len = DstMemSize; status = 0; out: return status; } static int rga2_mmu_info_BitBlt_mode(struct rga2_reg *reg, struct rga2_req *req) { int Src0MemSize, DstMemSize, Src1MemSize; unsigned long Src0Start, Src1Start, DstStart; unsigned long Src0PageCount, Src1PageCount, DstPageCount; uint32_t AllSize; uint32_t *MMU_Base, *MMU_Base_phys; int ret; int status; uint32_t uv_size, v_size; struct page **pages = NULL; struct rga_dma_buffer_t *dma_buffer = NULL; MMU_Base = NULL; Src0MemSize = 0; Src1MemSize = 0; DstMemSize = 0; Src0PageCount = 0; Src1PageCount = 0; DstPageCount = 0; Src0Start = 0; Src1Start = 0; DstStart = 0; /* cal src0 buf mmu info */ if (req->mmu_info.src0_mmu_flag & 1) { Src0PageCount = rga2_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), &Src0Start); if (Src0PageCount == 0) return -EINVAL; } /* cal src1 buf mmu info */ if (req->mmu_info.src1_mmu_flag & 1) { Src1PageCount = rga2_buf_size_cal(req->src1.yrgb_addr, req->src1.uv_addr, req->src1.v_addr, req->src1.format, req->src1.vir_w, (req->src1.vir_h), &Src1Start); if (Src1PageCount == 0) return -EINVAL; } /* cal dst buf mmu info */ if (req->mmu_info.dst_mmu_flag & 1) { DstPageCount = rga2_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 (DstPageCount == 0) return -EINVAL; } /* Cal out the needed mem size */ Src0MemSize = (Src0PageCount + 15) & (~15); Src1MemSize = (Src1PageCount + 15) & (~15); DstMemSize = (DstPageCount + 15) & (~15); AllSize = Src0MemSize + Src1MemSize + DstMemSize; if (rga2_mmu_buf_get_try(&rga2_mmu_buf, AllSize)) { pr_err("RGA2 Get MMU mem failed\n"); status = RGA2_MALLOC_ERROR; goto out; } pages = rga2_mmu_buf.pages; if(pages == NULL) { pr_err("RGA MMU malloc pages mem failed\n"); return -EINVAL; } mutex_lock(&rga2_service.lock); MMU_Base = rga2_mmu_buf.buf_virtual + rga2_mmu_buf.front; MMU_Base_phys = rga2_mmu_buf.buf + rga2_mmu_buf.front; mutex_unlock(&rga2_service.lock); if (Src0MemSize) { dma_buffer = ®->dma_buffer_src0; if (dma_buffer->sgt) { ret = rga2_MapION(dma_buffer->sgt, &MMU_Base[0], Src0MemSize); } else { ret = rga2_MapUserMemory(&pages[0], &MMU_Base[0], Src0Start, Src0PageCount, 0, MMU_MAP_CLEAN); #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) rga2_user_memory_check(&pages[0], req->src.vir_w, req->src.vir_h, req->src.format, 1); #endif /* Save pagetable to unmap. */ reg->MMU_src0_base = MMU_Base; reg->MMU_src0_count = Src0PageCount; } if (ret < 0) { pr_err("rga2 map src0 memory failed\n"); status = ret; goto out; } /* change the buf address in req struct */ req->mmu_info.src0_base_addr = (((unsigned long)MMU_Base_phys)); uv_size = (req->src.uv_addr - (Src0Start << PAGE_SHIFT)) >> PAGE_SHIFT; v_size = (req->src.v_addr - (Src0Start << 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); } if (Src1MemSize) { dma_buffer = ®->dma_buffer_src1; if (dma_buffer->sgt) { ret = rga2_MapION(dma_buffer->sgt, MMU_Base + Src0MemSize, Src1MemSize); } else { ret = rga2_MapUserMemory(&pages[0], MMU_Base + Src0MemSize, Src1Start, Src1PageCount, 0, MMU_MAP_CLEAN); /* Save pagetable to unmap. */ reg->MMU_src1_base = MMU_Base + Src0MemSize; reg->MMU_src1_count = Src1PageCount; } if (ret < 0) { pr_err("rga2 map src1 memory failed\n"); status = ret; goto out; } /* change the buf address in req struct */ req->mmu_info.src1_base_addr = ((unsigned long)(MMU_Base_phys + Src0MemSize)); req->src1.yrgb_addr = (req->src1.yrgb_addr & (~PAGE_MASK)); } if (DstMemSize) { dma_buffer = ®->dma_buffer_dst; if (dma_buffer->sgt) { ret = rga2_MapION(dma_buffer->sgt, MMU_Base + Src0MemSize + Src1MemSize, DstMemSize); } else if (req->alpha_mode_0 != 0 && req->bitblt_mode == 0) { /* The blend mode of src + dst => dst requires clean and invalidate */ ret = rga2_MapUserMemory(&pages[0], MMU_Base + Src0MemSize + Src1MemSize, DstStart, DstPageCount, 1, MMU_MAP_CLEAN | MMU_MAP_INVALID); #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) rga2_user_memory_check(&pages[0], req->dst.vir_w, req->dst.vir_h, req->dst.format, 2); #endif /* Save pagetable to invalid cache and unmap. */ reg->MMU_dst_base = MMU_Base + Src0MemSize + Src1MemSize; reg->MMU_dst_count = DstPageCount; } else { ret = rga2_MapUserMemory(&pages[0], MMU_Base + Src0MemSize + Src1MemSize, DstStart, DstPageCount, 1, MMU_MAP_INVALID); #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) rga2_user_memory_check(&pages[0], req->dst.vir_w, req->dst.vir_h, req->dst.format, 2); #endif /* Save pagetable to invalid cache and unmap. */ reg->MMU_dst_base = MMU_Base + Src0MemSize + Src1MemSize; reg->MMU_dst_count = DstPageCount; } if (ret < 0) { pr_err("rga2 map dst memory failed\n"); status = ret; goto out; } /* change the buf address in req struct */ req->mmu_info.dst_base_addr = ((unsigned long)(MMU_Base_phys + Src0MemSize + Src1MemSize)); req->dst.yrgb_addr = (req->dst.yrgb_addr & (~PAGE_MASK)); uv_size = (req->dst.uv_addr - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; v_size = (req->dst.v_addr - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; req->dst.uv_addr = (req->dst.uv_addr & (~PAGE_MASK)) | ((uv_size) << PAGE_SHIFT); req->dst.v_addr = (req->dst.v_addr & (~PAGE_MASK)) | ((v_size) << PAGE_SHIFT); if (((req->alpha_rop_flag & 1) == 1) && (req->bitblt_mode == 0)) { req->mmu_info.src1_base_addr = req->mmu_info.dst_base_addr; req->mmu_info.src1_mmu_flag = req->mmu_info.dst_mmu_flag; } } /* flush data to DDR */ rga2_dma_flush_range(MMU_Base, (MMU_Base + AllSize)); rga2_mmu_buf_get(&rga2_mmu_buf, AllSize); reg->MMU_len = AllSize; status = 0; out: return status; } static int rga2_mmu_info_color_palette_mode(struct rga2_reg *reg, struct rga2_req *req) { int SrcMemSize, DstMemSize; unsigned long SrcStart, DstStart; unsigned long SrcPageCount, DstPageCount; struct page **pages = NULL; uint32_t uv_size, v_size; uint32_t AllSize; uint32_t *MMU_Base = NULL, *MMU_Base_phys; int ret, status; uint32_t stride; uint8_t shift; uint32_t sw, byte_num; struct rga_dma_buffer_t *dma_buffer = NULL; shift = 3 - (req->palette_mode & 3); sw = req->src.vir_w*req->src.vir_h; byte_num = sw >> shift; stride = (byte_num + 3) & (~3); SrcStart = 0; DstStart = 0; SrcPageCount = 0; DstPageCount = 0; SrcMemSize = 0; DstMemSize = 0; do { if (req->mmu_info.src0_mmu_flag) { if (req->mmu_info.els_mmu_flag & 1) { req->mmu_info.src0_mmu_flag = 0; req->mmu_info.src1_mmu_flag = 0; } else { req->mmu_info.els_mmu_flag = req->mmu_info.src0_mmu_flag; req->mmu_info.src0_mmu_flag = 0; } SrcPageCount = rga2_mem_size_cal(req->src.yrgb_addr, stride, &SrcStart); if(SrcPageCount == 0) { return -EINVAL; } } if (req->mmu_info.dst_mmu_flag) { DstPageCount = rga2_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(DstPageCount == 0) { return -EINVAL; } } SrcMemSize = (SrcPageCount + 15) & (~15); DstMemSize = (DstPageCount + 15) & (~15); AllSize = SrcMemSize + DstMemSize; if (rga2_mmu_buf_get_try(&rga2_mmu_buf, AllSize)) { pr_err("RGA2 Get MMU mem failed\n"); status = RGA2_MALLOC_ERROR; break; } pages = rga2_mmu_buf.pages; if(pages == NULL) { pr_err("RGA MMU malloc pages mem failed\n"); return -EINVAL; } mutex_lock(&rga2_service.lock); MMU_Base = rga2_mmu_buf.buf_virtual + rga2_mmu_buf.front; MMU_Base_phys = rga2_mmu_buf.buf + rga2_mmu_buf.front; mutex_unlock(&rga2_service.lock); if(SrcMemSize) { dma_buffer = ®->dma_buffer_src0; if (dma_buffer->sgt) { ret = rga2_MapION(dma_buffer->sgt, &MMU_Base[0], SrcMemSize); } else { ret = rga2_MapUserMemory(&pages[0], &MMU_Base[0], SrcStart, SrcPageCount, 0, MMU_MAP_CLEAN); #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) rga2_user_memory_check(&pages[0], req->src.vir_w, req->src.vir_h, req->src.format, 1); #endif } if (ret < 0) { pr_err("rga2 map src0 memory failed\n"); status = ret; break; } /* change the buf address in req struct */ req->mmu_info.els_base_addr = (((unsigned long)MMU_Base_phys)); /* *The color palette mode will not have YUV format as input, *so UV component address is not needed */ req->src.yrgb_addr = (req->src.yrgb_addr & (~PAGE_MASK)); } if(DstMemSize) { dma_buffer = ®->dma_buffer_dst; if (dma_buffer->sgt) { ret = rga2_MapION(dma_buffer->sgt, MMU_Base + SrcMemSize, DstMemSize); } else { ret = rga2_MapUserMemory(&pages[0], MMU_Base + SrcMemSize, DstStart, DstPageCount, 1, MMU_MAP_INVALID); #ifdef CONFIG_ROCKCHIP_RGA2_DEBUGGER if (RGA2_CHECK_MODE) rga2_user_memory_check(&pages[0], req->dst.vir_w, req->dst.vir_h, req->dst.format, 1); #endif } if (ret < 0) { pr_err("rga2 map dst memory failed\n"); status = ret; break; } /* change the buf address in req struct */ req->mmu_info.dst_base_addr = ((unsigned long)(MMU_Base_phys + SrcMemSize)); req->dst.yrgb_addr = (req->dst.yrgb_addr & (~PAGE_MASK)); uv_size = (req->dst.uv_addr - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; v_size = (req->dst.v_addr - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; req->dst.uv_addr = (req->dst.uv_addr & (~PAGE_MASK)) | ((uv_size) << PAGE_SHIFT); req->dst.v_addr = (req->dst.v_addr & (~PAGE_MASK)) | ((v_size) << PAGE_SHIFT); } /* flush data to DDR */ rga2_dma_flush_range(MMU_Base, (MMU_Base + AllSize)); rga2_mmu_buf_get(&rga2_mmu_buf, AllSize); reg->MMU_len = AllSize; return 0; } while(0); return 0; } static int rga2_mmu_info_color_fill_mode(struct rga2_reg *reg, struct rga2_req *req) { int DstMemSize; unsigned long DstStart; unsigned long DstPageCount; struct page **pages = NULL; uint32_t uv_size, v_size; uint32_t AllSize; uint32_t *MMU_Base, *MMU_Base_phys; int ret; int status; struct rga_dma_buffer_t *dma_buffer = NULL; DstMemSize = 0; DstPageCount = 0; DstStart = 0; MMU_Base = NULL; do { if(req->mmu_info.dst_mmu_flag & 1) { DstPageCount = rga2_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(DstPageCount == 0) { return -EINVAL; } } DstMemSize = (DstPageCount + 15) & (~15); AllSize = DstMemSize; if(rga2_mmu_buf_get_try(&rga2_mmu_buf, AllSize)) { pr_err("RGA2 Get MMU mem failed\n"); status = RGA2_MALLOC_ERROR; break; } pages = rga2_mmu_buf.pages; if(pages == NULL) { pr_err("RGA MMU malloc pages mem failed\n"); return -EINVAL; } mutex_lock(&rga2_service.lock); MMU_Base_phys = rga2_mmu_buf.buf + rga2_mmu_buf.front; MMU_Base = rga2_mmu_buf.buf_virtual + rga2_mmu_buf.front; mutex_unlock(&rga2_service.lock); if (DstMemSize) { dma_buffer = ®->dma_buffer_dst; if (dma_buffer->sgt) { ret = rga2_MapION(dma_buffer->sgt, &MMU_Base[0], DstMemSize); } else { ret = rga2_MapUserMemory(&pages[0], &MMU_Base[0], DstStart, DstPageCount, 1, MMU_MAP_INVALID); } if (ret < 0) { pr_err("rga2 map dst memory failed\n"); status = ret; break; } /* change the buf address in req struct */ req->mmu_info.dst_base_addr = ((unsigned long)MMU_Base_phys); req->dst.yrgb_addr = (req->dst.yrgb_addr & (~PAGE_MASK)); uv_size = (req->dst.uv_addr - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; v_size = (req->dst.v_addr - (DstStart << PAGE_SHIFT)) >> PAGE_SHIFT; req->dst.uv_addr = (req->dst.uv_addr & (~PAGE_MASK)) | ((uv_size) << PAGE_SHIFT); req->dst.v_addr = (req->dst.v_addr & (~PAGE_MASK)) | ((v_size) << PAGE_SHIFT); } /* flush data to DDR */ rga2_dma_flush_range(MMU_Base, (MMU_Base + AllSize + 1)); rga2_mmu_buf_get(&rga2_mmu_buf, AllSize); reg->MMU_len = AllSize; return 0; } while(0); return status; } static int rga2_mmu_info_update_palette_table_mode(struct rga2_reg *reg, struct rga2_req *req) { int LutMemSize; unsigned long LutStart; unsigned long LutPageCount; struct page **pages = NULL; uint32_t uv_size, v_size; uint32_t AllSize; uint32_t *MMU_Base, *MMU_Base_phys; int ret, status; struct rga_dma_buffer_t *dma_buffer = NULL; MMU_Base = NULL; LutPageCount = 0; LutMemSize = 0; LutStart = 0; do { /* cal lut buf mmu info */ if (req->mmu_info.els_mmu_flag & 1) { req->mmu_info.src0_mmu_flag = req->mmu_info.src0_mmu_flag == 1 ? 0 : req->mmu_info.src0_mmu_flag; req->mmu_info.src1_mmu_flag = req->mmu_info.src1_mmu_flag == 1 ? 0 : req->mmu_info.src1_mmu_flag; req->mmu_info.dst_mmu_flag = req->mmu_info.dst_mmu_flag == 1 ? 0 : req->mmu_info.dst_mmu_flag; LutPageCount = rga2_buf_size_cal(req->pat.yrgb_addr, req->pat.uv_addr, req->pat.v_addr, req->pat.format, req->pat.vir_w, req->pat.vir_h, &LutStart); if(LutPageCount == 0) { return -EINVAL; } } LutMemSize = (LutPageCount + 15) & (~15); AllSize = LutMemSize; if (rga2_mmu_buf_get_try(&rga2_mmu_buf, AllSize)) { pr_err("RGA2 Get MMU mem failed\n"); status = RGA2_MALLOC_ERROR; break; } pages = rga2_mmu_buf.pages; if (pages == NULL) { pr_err("RGA MMU malloc pages mem failed\n"); return -EINVAL; } mutex_lock(&rga2_service.lock); MMU_Base = rga2_mmu_buf.buf_virtual + rga2_mmu_buf.front; MMU_Base_phys = rga2_mmu_buf.buf + rga2_mmu_buf.front; mutex_unlock(&rga2_service.lock); if (LutMemSize) { dma_buffer = ®->dma_buffer_els; if (dma_buffer->sgt) { ret = rga2_MapION(dma_buffer->sgt, &MMU_Base[0], LutMemSize); } else { ret = rga2_MapUserMemory(&pages[0], &MMU_Base[0], LutStart, LutPageCount, 0, MMU_MAP_CLEAN); } if (ret < 0) { pr_err("rga2 map palette memory failed\n"); status = ret; break; } /* change the buf address in req struct */ req->mmu_info.els_base_addr = (((unsigned long)MMU_Base_phys)); req->pat.yrgb_addr = (req->pat.yrgb_addr & (~PAGE_MASK)); uv_size = (req->pat.uv_addr - (LutStart << PAGE_SHIFT)) >> PAGE_SHIFT; v_size = (req->pat.v_addr - (LutStart << PAGE_SHIFT)) >> PAGE_SHIFT; req->pat.uv_addr = (req->pat.uv_addr & (~PAGE_MASK)) | ((uv_size) << PAGE_SHIFT); req->pat.v_addr = (req->pat.v_addr & (~PAGE_MASK)) | ((v_size) << PAGE_SHIFT); } /* flush data to DDR */ rga2_dma_flush_range(MMU_Base, (MMU_Base + AllSize)); rga2_mmu_buf_get(&rga2_mmu_buf, AllSize); reg->MMU_len = AllSize; return 0; } while(0); return status; } /* * yqw: * This function is currently not sure whether rga2 is used, * because invalidate/clean cache occupies the parameter * reg->MMU_base, so block this function first, and re-implement * this function if necessary. */ #if 0 static int rga2_mmu_info_update_patten_buff_mode(struct rga2_reg *reg, struct rga2_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 = rga2_mem_size_cal(req->pat.yrgb_addr, req->pat.act_w * req->pat.act_h * 4, &SrcStart); if(SrcMemSize == 0) { return -EINVAL; } /* cal cmd buf mmu info */ CMDMemSize = rga2_mem_size_cal((unsigned long)rga2_service.cmd_buff, RGA2_CMD_BUF_SIZE, &CMDStart); if(CMDMemSize == 0) { return -EINVAL; } AllSize = SrcMemSize + CMDMemSize; pages = rga2_mmu_buf.pages; MMU_Base = kzalloc(AllSize * sizeof(uint32_t), GFP_KERNEL); if (MMU_Base == NULL) return -EINVAL; for(i=0; isrc.yrgb_addr < KERNEL_SPACE_VALID) { ret = rga2_MapUserMemory(&pages[CMDMemSize], &MMU_Base[CMDMemSize], SrcStart, SrcMemSize, 1, MMU_MAP_CLEAN); if (ret < 0) { pr_err("rga map src memory failed\n"); status = ret; break; } } else { MMU_p = MMU_Base + CMDMemSize; for(i=0; immu_info.src0_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 */ rga2_dma_flush_range(MMU_Base, (MMU_Base + AllSize)); return 0; } while(0); return status; } #endif int rga2_set_mmu_info(struct rga2_reg *reg, struct rga2_req *req) { int ret; if (reg->MMU_map == true) { ret = rga2_mmu_flush_cache(reg, req); return ret; } switch (req->render_mode) { case bitblt_mode : ret = rga2_mmu_info_BitBlt_mode(reg, req); break; case color_palette_mode : ret = rga2_mmu_info_color_palette_mode(reg, req); break; case color_fill_mode : ret = rga2_mmu_info_color_fill_mode(reg, req); break; case update_palette_table_mode : ret = rga2_mmu_info_update_palette_table_mode(reg, req); break; #if 0 case update_patten_buff_mode : ret = rga2_mmu_info_update_patten_buff_mode(reg, req); break; #endif default : ret = -1; break; } return ret; }