From 1d1833aac7b329cb55fd8e5e573c55d68c42add4 Mon Sep 17 00:00:00 2001 From: Guosong Zhou Date: Thu, 22 Nov 2018 08:33:58 -0500 Subject: [PATCH] picdec: add mmap interface for picdec [2/2] PD#SWPL-2280 Problem: play picture crash Solution: add mmap interface for picdec Verify: verify by p321 Change-Id: Ib278de80035b0404884315e29fe933cd8f4b6cfe Signed-off-by: Guosong Zhou --- .../amlogic/media/video_processor/pic_dev/picdec.c | 206 ++++++++++++++++++--- .../amlogic/media/video_processor/pic_dev/picdec.h | 6 + 2 files changed, 184 insertions(+), 28 deletions(-) diff --git a/drivers/amlogic/media/video_processor/pic_dev/picdec.c b/drivers/amlogic/media/video_processor/pic_dev/picdec.c index e96758f..c52e2ca 100644 --- a/drivers/amlogic/media/video_processor/pic_dev/picdec.c +++ b/drivers/amlogic/media/video_processor/pic_dev/picdec.c @@ -60,6 +60,7 @@ static int dump_file_flag; static int p2p_mode = 2; static int output_format_mode = 1; static int txlx_output_format_mode = 1; +static int cma_layout_flag = 1; #define NO_TASK_MODE @@ -548,7 +549,8 @@ static int picdec_start(void) map_start, picdec_device.mapping, map_size); } else{ picdec_device.mapping = NULL; - picdec_device.vir_addr = phys_to_virt(map_start); + if (!cma_layout_flag) + picdec_device.vir_addr = phys_to_virt(map_start); } vf_provider_init(&picdec_vf_prov, PROVIDER_NAME, &picdec_vf_provider, NULL); @@ -761,6 +763,24 @@ int fill_black_color_by_ge2d(struct vframe_s *vf, return 0; } +static int picdec_memset_phyaddr(ulong phys, u32 size, u32 val) +{ + u32 i, span = SZ_1M; + u32 count = size / PAGE_ALIGN(span); + ulong addr = phys; + u8 *p; + + for (i = 0; i < count; i++) { + addr = phys + i * span; + p = codec_mm_vmap(addr, span); + if (!p) + return -1; + memset(p, val, span); + codec_mm_unmap_phyaddr(p); + } + return 0; +} + int fill_color(struct vframe_s *vf, struct ge2d_context_s *context, struct config_para_ex_s *ge2d_config) { @@ -795,10 +815,17 @@ int fill_color(struct vframe_s *vf, struct ge2d_context_s *context, if (ret < 0) pr_err("fill black color by ge2d failed\n"); } else { - p = phys_to_virt(cs0.addr); - memset(p, 0, cs0.width * cs0.height); - p = phys_to_virt(cs1.addr); - memset(p, 0x80, cs1.width * cs1.height); + if (!cma_layout_flag) { + p = phys_to_virt(cs0.addr); + memset(p, 0, cs0.width * cs0.height); + p = phys_to_virt(cs1.addr); + memset(p, 0x80, cs1.width * cs1.height); + } else { + picdec_memset_phyaddr(cs0.addr, + (cs0.width * cs0.height), 0); + picdec_memset_phyaddr(cs1.addr, + (cs1.width * cs1.height), 0x80); + } } } do_gettimeofday(&end); @@ -845,6 +872,27 @@ static void rotate_adjust(int w_in, int h_in, int *w_out, int *h_out, int angle) *h_out = h; } +static int copy_phybuf_to_file(ulong phys, u32 size, + struct file *fp, loff_t pos) +{ + u32 i, span = SZ_1M; + u32 count = size / PAGE_ALIGN(span); + ulong addr = phys; + u8 *p; + + for (i = 0; i < count; i++) { + addr = phys + i * span; + p = codec_mm_vmap(addr, span); + if (!p) + return -1; + vfs_write(fp, (char *)p, + span, &pos); + pos += span; + codec_mm_unmap_phyaddr(p); + } + return 0; +} + int picdec_fill_buffer(struct vframe_s *vf, struct ge2d_context_s *context, struct config_para_ex_s *ge2d_config) { @@ -857,6 +905,7 @@ int picdec_fill_buffer(struct vframe_s *vf, struct ge2d_context_s *context, int dst_top, dst_left, dst_width, dst_height; struct file *filp = NULL; loff_t pos = 0; + int ret = 0; void __iomem *p; mm_segment_t old_fs = get_fs(); @@ -865,9 +914,14 @@ int picdec_fill_buffer(struct vframe_s *vf, struct ge2d_context_s *context, (ulong)(picdec_device.assit_buf_start), canvas_width * 3, canvas_height, CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); - aml_pr_info(1, "picdec_pre_process start\n"); - picdec_pre_process(); - aml_pr_info(1, "picdec_pre_process finish\n"); + if (!cma_layout_flag) { + aml_pr_info(1, "picdec_pre_process start\n"); + picdec_pre_process(); + aml_pr_info(1, "picdec_pre_process finish\n"); + } else { + dma_flush(picdec_device.assit_buf_start, + (canvas_width * picdec_device.origin_height * 3)); + } ge2d_config->alu_const_color = 0; /* 0x000000ff; */ ge2d_config->bitmask_en = 0; ge2d_config->src1_gb_alpha = 0; /* 0xff; */ @@ -998,9 +1052,17 @@ int picdec_fill_buffer(struct vframe_s *vf, struct ge2d_context_s *context, if (IS_ERR(filp)) { aml_pr_info(0, "open file failed\n"); } else { - p = phys_to_virt(cs0.addr); - vfs_write(filp, (char *)p, - cs0.width * cs0.height, &pos); + if (!cma_layout_flag) { + p = phys_to_virt(cs0.addr); + vfs_write(filp, (char *)p, + cs0.width * cs0.height, &pos); + } else { + ret = copy_phybuf_to_file(cs0.addr, + cs0.width * cs0.height, + filp, 0); + if (ret < 0) + pr_err("write yuv444 file failed.\n"); + } vfs_fsync(filp, 0); filp_close(filp, NULL); set_fs(old_fs); @@ -1012,13 +1074,29 @@ int picdec_fill_buffer(struct vframe_s *vf, struct ge2d_context_s *context, if (IS_ERR(filp)) { aml_pr_info(0, "open file failed\n"); } else { - p = phys_to_virt(cs0.addr); - vfs_write(filp, (char *)p, - cs0.width * cs0.height, &pos); + if (!cma_layout_flag) { + p = phys_to_virt(cs0.addr); + vfs_write(filp, (char *)p, + cs0.width * cs0.height, &pos); + } else { + ret = copy_phybuf_to_file(cs0.addr, + cs0.width * cs0.height, + filp, 0); + if (ret < 0) + pr_err("write NV21 Y to file failed\n"); + } pos = cs0.width * cs0.height; - p = phys_to_virt(cs1.addr); - vfs_write(filp, (char *)p, - cs1.width * cs1.height, &pos); + if (!cma_layout_flag) { + p = phys_to_virt(cs1.addr); + vfs_write(filp, (char *)p, + cs1.width * cs1.height, &pos); + } else { + ret = copy_phybuf_to_file(cs1.addr, + cs1.width * cs1.height, + filp, pos); + if (ret < 0) + pr_err("write NV21 UV to file failed\n"); + } vfs_fsync(filp, 0); filp_close(filp, NULL); set_fs(old_fs); @@ -1109,7 +1187,7 @@ int picdec_cma_buf_init(void) picdec_device.cma_pages); picdec_device.buffer_size = (72*SZ_1M); } else{ - flags = CODEC_MM_FLAGS_DMA_CPU | + flags = CODEC_MM_FLAGS_DMA | CODEC_MM_FLAGS_CMA_CLEAR; picdec_device.buffer_start = codec_mm_alloc_for_dma("picdec", @@ -1126,7 +1204,7 @@ int picdec_cma_buf_init(void) picdec_device.cma_pages); picdec_device.buffer_size = (48*SZ_1M); } else{ - flags = CODEC_MM_FLAGS_DMA_CPU | + flags = CODEC_MM_FLAGS_DMA | CODEC_MM_FLAGS_CMA_CLEAR; picdec_device.buffer_start = codec_mm_alloc_for_dma("picdec", @@ -1267,6 +1345,7 @@ int picdec_buffer_init(void) vfbuf_use[i] = 0; } } + if (picdec_device.output_format_mode) picdec_device.assit_buf_start = buf_start + canvas_width * canvas_height * 6; @@ -1364,24 +1443,82 @@ void get_picdec_buf_info(resource_size_t *start, unsigned int *size, static int picdec_open(struct inode *inode, struct file *file) { - struct ge2d_context_s *context = NULL; int ret = 0; + if (!cma_layout_flag) { + struct ge2d_context_s *context = NULL; + + aml_pr_info(1, "open one picdec device\n"); + file->private_data = context; + picdec_device.open_count++; + ret = picdec_start(); + } else { + struct picdec_private_s *priv; - aml_pr_info(1, "open one picdec device\n"); - file->private_data = context; - picdec_device.open_count++; - ret = picdec_start(); + aml_pr_info(1, "open one picdec device\n"); + priv = kmalloc(sizeof(struct picdec_private_s), GFP_KERNEL); + if (!priv) { + pr_err("alloc memory failed for amvideo cap\n"); + return -ENOMEM; + } + memset(priv, 0, sizeof(struct picdec_private_s)); + picdec_device.open_count++; + ret = picdec_start(); + priv->context = NULL; + priv->phyaddr = (unsigned long)picdec_device.assit_buf_start; + priv->buf_len = (picdec_device.buffer_size/3); + file->private_data = priv; + } return ret; } +static int picdec_mmap(struct file *file, + struct vm_area_struct *vma) +{ + struct picdec_private_s *priv = file->private_data; + unsigned long off = vma->vm_pgoff << PAGE_SHIFT; + unsigned int vm_size = vma->vm_end - vma->vm_start; + + if (!priv->phyaddr) + return -EIO; + + aml_pr_info(1, "priv->phyaddr = %lx , vm_size = %d\n", + priv->phyaddr, vm_size); + + if (vm_size == 0) + return -EAGAIN; + + off += priv->phyaddr; + + if ((off + vm_size) > (priv->phyaddr + priv->buf_len)) + return -ENOMEM; + + /*vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);*/ + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO; + + if (remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) { + pr_err("set_cached: failed remap_pfn_range\n"); + return -EAGAIN; + } + aml_pr_info(1, "picdec_mmap ok\n"); + return 0; +} + static long picdec_ioctl(struct file *filp, unsigned int cmd, unsigned long args) { int ret = 0; - struct ge2d_context_s *context; void __user *argp; + struct ge2d_context_s *context; + struct picdec_private_s *priv; - context = (struct ge2d_context_s *) filp->private_data; + if (!cma_layout_flag) { + context = (struct ge2d_context_s *) filp->private_data; + } else { + priv = filp->private_data; + context = (struct ge2d_context_s *) priv->context; + } argp = (void __user *)args; switch (cmd) { #ifdef CONFIG_COMPAT @@ -1445,8 +1582,13 @@ static long picdec_compat_ioctl(struct file *filp, static int picdec_release(struct inode *inode, struct file *file) { - struct ge2d_context_s *context = - (struct ge2d_context_s *) file->private_data; + struct ge2d_context_s *context; + struct picdec_private_s *priv = file->private_data; + + if (!cma_layout_flag) + context = (struct ge2d_context_s *) file->private_data; + else + context = (struct ge2d_context_s *) priv->context; aml_pr_info(1, "picdec stop start"); picdec_stop(); @@ -1454,6 +1596,10 @@ static int picdec_release(struct inode *inode, struct file *file) picdec_device.open_count--; return 0; } + if (cma_layout_flag) { + kfree(priv); + priv = NULL; + } aml_pr_info(0, "release one picdec device\n"); return -1; } @@ -1472,6 +1618,7 @@ static long picdec_compat_ioctl(struct file *filp, unsigned int cmd, static const struct file_operations picdec_fops = { .owner = THIS_MODULE, .open = picdec_open, + .mmap = picdec_mmap, .unlocked_ioctl = picdec_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = picdec_compat_ioctl, @@ -1823,6 +1970,9 @@ MODULE_PARM_DESC(output_format_mode, "\n picdec output fomat mode\n"); module_param(txlx_output_format_mode, uint, 0664); MODULE_PARM_DESC(txlx_output_format_mode, "\n txlx picdec output fomat mode\n"); +module_param(cma_layout_flag, uint, 0664); +MODULE_PARM_DESC(cma_layout_flag, "\n cma layout change flag\n"); + MODULE_DESCRIPTION("Amlogic picture decoder driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Simon Zheng "); diff --git a/drivers/amlogic/media/video_processor/pic_dev/picdec.h b/drivers/amlogic/media/video_processor/pic_dev/picdec.h index b619d37..1f058bf 100644 --- a/drivers/amlogic/media/video_processor/pic_dev/picdec.h +++ b/drivers/amlogic/media/video_processor/pic_dev/picdec.h @@ -97,6 +97,12 @@ struct compat_source_input_s) #endif +struct picdec_private_s { + struct ge2d_context_s *context; + unsigned long phyaddr; + unsigned int buf_len; +}; + #define PICDEC_IOC_MAGIC 'P' #define PICDEC_IOC_FRAME_RENDER _IOW(PICDEC_IOC_MAGIC, 0x00, \ struct source_input_s) -- 2.7.4