From 768c10065d3b79b1eaa755efb3e6ac44ccf5a8ba Mon Sep 17 00:00:00 2001 From: "zhiwei.yuan" Date: Wed, 3 Apr 2019 17:18:25 +0800 Subject: [PATCH] vdin: add new interface for passing dma-buf to vdin [1/1] PD#TV-3863 Problem: gpu cann't get vdin buf directly Solution: vdin write data to the addr passed by upper layer Verify: verified by t962x2_x301 Change-Id: I495b78c419e10a6dacb9b9f29c0f8e87339ac195 Signed-off-by: zhiwei.yuan --- arch/arm/boot/dts/amlogic/tl1_pxp.dts | 6 +- arch/arm/boot/dts/amlogic/tl1_t962x2_skt.dts | 6 +- arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts | 6 +- .../boot/dts/amlogic/tl1_t962x2_x301_1g.dts | 6 +- .../boot/dts/amlogic/tl1_t962x2_x301_2g.dts | 6 +- .../boot/dts/amlogic/tl1_t962x2_t309.dts | 6 +- .../boot/dts/amlogic/tl1_t962x2_x301_1g.dts | 6 +- .../boot/dts/amlogic/tl1_t962x2_x301_2g.dts | 6 +- .../amlogic/media/vin/tvin/vdin/vdin_canvas.c | 33 +++ .../amlogic/media/vin/tvin/vdin/vdin_ctl.c | 35 ++- .../amlogic/media/vin/tvin/vdin/vdin_ctl.h | 4 +- .../amlogic/media/vin/tvin/vdin/vdin_debug.c | 21 +- .../amlogic/media/vin/tvin/vdin/vdin_drv.c | 242 +++++++++++++++--- .../amlogic/media/vin/tvin/vdin/vdin_drv.h | 21 +- drivers/amlogic/media/vin/tvin/viu/viuin.c | 10 +- .../amlogic/media/frame_provider/tvin/tvin.h | 4 +- 16 files changed, 350 insertions(+), 68 deletions(-) diff --git a/arch/arm/boot/dts/amlogic/tl1_pxp.dts b/arch/arm/boot/dts/amlogic/tl1_pxp.dts index 76ea74ab3c1fb..1b80c60b48fcd 100644 --- a/arch/arm/boot/dts/amlogic/tl1_pxp.dts +++ b/arch/arm/boot/dts/amlogic/tl1_pxp.dts @@ -99,8 +99,10 @@ vdin1_cma_reserved:linux,vdin1_cma { compatible = "shared-dma-pool"; reusable; - /* 1920x1080x2x4 =16 M */ - size = <0x1400000>; + /*keystone need 4 buffers,each has 1920*1080*3 + *for keystone, change to 0x1800000(24M) + */ + size = <0x1400000>;/*20M*/ alignment = <0x400000>; }; diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_skt.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_skt.dts index bb6ff2e282afb..6d35261c26ed3 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_skt.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_skt.dts @@ -114,8 +114,10 @@ vdin1_cma_reserved:linux,vdin1_cma { compatible = "shared-dma-pool"; reusable; - /* 1920x1080x2x4 =16 M */ - size = <0x1400000>; + /*keystone need 4 buffers,each has 1920*1080*3 + *for keystone, change to 0x1800000(24M) + */ + size = <0x1400000>;/*20M*/ alignment = <0x400000>; }; diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts index 5a406b03b8092..3478e76fd7520 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts @@ -122,8 +122,10 @@ vdin1_cma_reserved:linux,vdin1_cma { compatible = "shared-dma-pool"; reusable; - /* 1920x1080x2x4 =16 M */ - size = <0x1400000>; + /*keystone need 4 buffers,each has 1920*1080*3 + *for keystone, change to 0x1800000(24M) + */ + size = <0x1400000>;/*20M*/ alignment = <0x400000>; }; diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts index 48383fd25d25f..085849091e735 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_1g.dts @@ -125,8 +125,10 @@ vdin1_cma_reserved:linux,vdin1_cma { compatible = "shared-dma-pool"; reusable; - /* 1920x1080x2x4 =16 M */ - size = <0x1400000>; + /*keystone need 4 buffers,each has 1920*1080*3 + *for keystone, change to 0x1800000(24M) + */ + size = <0x1400000>;/*20M*/ alignment = <0x400000>; alloc-ranges = <0x30000000 0x10000000>; }; diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_2g.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_2g.dts index 5f80bbc2f591f..77d864cd7f813 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_2g.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301_2g.dts @@ -124,8 +124,10 @@ vdin1_cma_reserved:linux,vdin1_cma { compatible = "shared-dma-pool"; reusable; - /* 1920x1080x2x4 =16 M */ - size = <0x1400000>; + /*keystone need 4 buffers,each has 1920*1080*3 + *for keystone, change to 0x1800000(24M) + */ + size = <0x1400000>;/*20M*/ alignment = <0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/tl1_t962x2_t309.dts b/arch/arm64/boot/dts/amlogic/tl1_t962x2_t309.dts index 9f00292b77c0a..eb6c0fd0a928d 100644 --- a/arch/arm64/boot/dts/amlogic/tl1_t962x2_t309.dts +++ b/arch/arm64/boot/dts/amlogic/tl1_t962x2_t309.dts @@ -121,8 +121,10 @@ vdin1_cma_reserved:linux,vdin1_cma { compatible = "shared-dma-pool"; reusable; - /* 1920x1080x2x4 =16 M */ - size = <0x0 0x1400000>; + /*keystone need 4 buffers,each has 1920*1080*3 + *for keystone, change to 0x1800000(24M) + */ + size = <0x0 0x1400000>;/*20M*/ alignment = <0x0 0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts index ce567e941894e..77e9ece5ae2fc 100644 --- a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts +++ b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_1g.dts @@ -123,8 +123,10 @@ vdin1_cma_reserved:linux,vdin1_cma { compatible = "shared-dma-pool"; reusable; - /* 1920x1080x2x4 =16 M */ - size = <0x0 0x1400000>; + /*keystone need 4 buffers,each has 1920*1080*3 + *for keystone, change to 0x1800000(24M) + */ + size = <0x0 0x1400000>;/*20M*/ alignment = <0x0 0x400000>; alloc-ranges = <0x0 0x30000000 0x0 0x10000000>; }; diff --git a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts index 98ec97e5e0926..87a899122106c 100644 --- a/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts +++ b/arch/arm64/boot/dts/amlogic/tl1_t962x2_x301_2g.dts @@ -121,8 +121,10 @@ vdin1_cma_reserved:linux,vdin1_cma { compatible = "shared-dma-pool"; reusable; - /* 1920x1080x2x4 =16 M */ - size = <0x0 0x1400000>; + /*keystone need 4 buffers,each has 1920*1080*3 + *for keystone, change to 0x1800000(24M) + */ + size = <0x0 0x1400000>;/*20M*/ alignment = <0x0 0x400000>; }; diff --git a/drivers/amlogic/media/vin/tvin/vdin/vdin_canvas.c b/drivers/amlogic/media/vin/tvin/vdin/vdin_canvas.c index 0d32bfc9fd451..1cfa6b1a3e26d 100644 --- a/drivers/amlogic/media/vin/tvin/vdin/vdin_canvas.c +++ b/drivers/amlogic/media/vin/tvin/vdin/vdin_canvas.c @@ -332,6 +332,23 @@ void vdin_canvas_auto_config(struct vdin_dev_s *devp) pr_err("\nvdin%d canvas_max_num %d less than vfmem_max_cnt %d\n", devp->index, devp->canvas_max_num, devp->vfmem_max_cnt); } + + if (devp->set_canvas_manual == 1) { + for (i = 0; i < 4; i++) { + canvas_id = + vdin_canvas_ids[devp->index][i * canvas_step]; + canvas_addr = vdin_set_canvas_addr[i].paddr; + canvas_config(canvas_id, canvas_addr, + devp->canvas_w, devp->canvas_h, + CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR); + pr_info("canvas index=%d- %3d: 0x%lx-0x%lx %ux%u\n", + i, canvas_id, canvas_addr, + canvas_addr + devp->canvas_max_size, + devp->canvas_w, devp->canvas_h); + } + return; + } + if ((devp->cma_config_en != 1) || !(devp->cma_config_flag & 0x100)) { /*use_reserved_mem or alloc_from_contiguous*/ devp->mem_start = roundup(devp->mem_start, devp->canvas_align); @@ -503,9 +520,25 @@ unsigned int vdin_cma_alloc(struct vdin_dev_s *devp) devp->vfmem_size = PAGE_ALIGN(mem_size) + dolby_size_byte; devp->vfmem_size = (devp->vfmem_size/PAGE_SIZE + 1)*PAGE_SIZE; + if (devp->set_canvas_manual == 1) { + for (i = 0; i < VDIN_CANVAS_MAX_CNT; i++) { + if (vdin_set_canvas_addr[i].dmabuff == NULL) + break; + + vdin_set_canvas_addr[i].paddr = + roundup(vdin_set_canvas_addr[i].paddr, + devp->canvas_align); + } + + devp->canvas_max_num = max_buffer_num = i; + devp->vfmem_max_cnt = max_buffer_num; + } + + mem_size = PAGE_ALIGN(mem_size) * max_buffer_num + dolby_size_byte * max_buffer_num; mem_size = (mem_size/PAGE_SIZE + 1)*PAGE_SIZE; + if (mem_size > devp->cma_mem_size) { mem_size = devp->cma_mem_size; pr_err("\nvdin%d cma_mem_size is not enough!!!\n", devp->index); diff --git a/drivers/amlogic/media/vin/tvin/vdin/vdin_ctl.c b/drivers/amlogic/media/vin/tvin/vdin/vdin_ctl.c index 4c67d9c11f374..a4e9bcb63fdaa 100644 --- a/drivers/amlogic/media/vin/tvin/vdin/vdin_ctl.c +++ b/drivers/amlogic/media/vin/tvin/vdin/vdin_ctl.c @@ -750,7 +750,7 @@ static void vdin_set_meas_mux(unsigned int offset, enum tvin_port_e port_, b.BT_PATH_GPIO_B:gxtvbb & gxbb c.txl and txlx don't support bt656 */ -void vdin_set_top(unsigned int offset, +void vdin_set_top(struct vdin_dev_s *devp, unsigned int offset, enum tvin_port_e port, enum tvin_color_fmt_e input_cfmt, unsigned int h, enum bt_path_e bt_path) @@ -873,6 +873,7 @@ void vdin_set_top(unsigned int offset, vdin_mux = VDIN_MUX_NULL; break; } + switch (input_cfmt) { case TVIN_YVYU422: vdin_data_bus_1 = VDIN_MAP_RCR; @@ -888,6 +889,14 @@ void vdin_set_top(unsigned int offset, vdin_data_bus_1 = VDIN_MAP_RCR; vdin_data_bus_2 = VDIN_MAP_Y_G; break; + case TVIN_RGB444: + /*RGB mapping*/ + if (devp->set_canvas_manual == 1) { + vdin_data_bus_0 = VDIN_MAP_RCR; + vdin_data_bus_1 = VDIN_MAP_BPB; + vdin_data_bus_2 = VDIN_MAP_Y_G; + } + break; default: break; } @@ -1996,7 +2005,14 @@ static inline void vdin_set_wr_ctrl(struct vdin_dev_s *devp, VDIN_WRCTRLREG_PAUSE_BIT, 1); /* swap the 2 64bits word in 128 words */ /*if (is_meson_gxbb_cpu())*/ - wr_bits(offset, VDIN_WR_CTRL, 1, 19, 1); + if (devp->set_canvas_manual == 1) { + /*not swap 2 64bits words in 128 words */ + wr_bits(offset, VDIN_WR_CTRL, 0, 19, 1); + /*little endian*/ + wr_bits(offset, VDIN_WR_H_START_END, 1, 30, 1); + } else + wr_bits(offset, VDIN_WR_CTRL, 1, 19, 1); + } void vdin_set_wr_ctrl_vsync(struct vdin_dev_s *devp, unsigned int offset, enum vdin_format_convert_e format_convert, @@ -2577,7 +2593,7 @@ void vdin_set_all_regs(struct vdin_dev_s *devp) devp->color_depth_mode, devp->source_bitdepth); /* top sub-module */ - vdin_set_top(devp->addr_offset, devp->parm.port, + vdin_set_top(devp, devp->addr_offset, devp->parm.port, devp->prop.color_format, devp->h_active, devp->bt_path); @@ -2585,7 +2601,6 @@ void vdin_set_all_regs(struct vdin_dev_s *devp) vdin_set_meas_mux(devp->addr_offset, devp->parm.port, devp->bt_path); - } static void vdin_delay_line(unsigned short num, unsigned int offset) @@ -2969,6 +2984,18 @@ unsigned int vdin_get_field_type(unsigned int offset) { return rd_bits(offset, VDIN_COM_STATUS0, 0, 1); } + +bool vdin_check_vdi6_afifo_overflow(unsigned int offset) +{ + return rd_bits(offset, VDIN_COM_STATUS2, 15, 1); +} + +void vdin_clear_vdi6_afifo_overflow_flg(unsigned int offset) +{ + wr_bits(offset, VDIN_ASFIFO_CTRL3, 0x1, 1, 1); + wr_bits(offset, VDIN_ASFIFO_CTRL3, 0x0, 1, 1); +} + static unsigned int vdin_reset_flag; inline int vdin_vsync_reset_mif(int index) { diff --git a/drivers/amlogic/media/vin/tvin/vdin/vdin_ctl.h b/drivers/amlogic/media/vin/tvin/vdin/vdin_ctl.h index fcdf2974d4394..93ff0b3e37f8d 100644 --- a/drivers/amlogic/media/vin/tvin/vdin/vdin_ctl.h +++ b/drivers/amlogic/media/vin/tvin/vdin/vdin_ctl.h @@ -145,6 +145,8 @@ extern void vdin_hw_enable(unsigned int offset); extern void vdin_hw_disable(unsigned int offset); extern unsigned int vdin_get_field_type(unsigned int offset); extern int vdin_vsync_reset_mif(int index); +extern bool vdin_check_vdi6_afifo_overflow(unsigned int offset); +extern void vdin_clear_vdi6_afifo_overflow_flg(unsigned int offset); extern void vdin_set_cutwin(struct vdin_dev_s *devp); extern void vdin_set_decimation(struct vdin_dev_s *devp); extern void vdin_fix_nonstd_vsync(struct vdin_dev_s *devp); @@ -187,7 +189,7 @@ extern void vdin_dolby_addr_alloc(struct vdin_dev_s *devp, unsigned int size); extern void vdin_dolby_addr_release(struct vdin_dev_s *devp, unsigned int size); extern int vdin_event_cb(int type, void *data, void *op_arg); extern void vdin_hdmiin_patch(struct vdin_dev_s *devp); -extern void vdin_set_top(unsigned int offset, +extern void vdin_set_top(struct vdin_dev_s *devp, unsigned int offset, enum tvin_port_e port, enum tvin_color_fmt_e input_cfmt, unsigned int h, enum bt_path_e bt_path); diff --git a/drivers/amlogic/media/vin/tvin/vdin/vdin_debug.c b/drivers/amlogic/media/vin/tvin/vdin/vdin_debug.c index c9927f100ac17..475106b5634a5 100644 --- a/drivers/amlogic/media/vin/tvin/vdin/vdin_debug.c +++ b/drivers/amlogic/media/vin/tvin/vdin/vdin_debug.c @@ -2101,15 +2101,9 @@ static ssize_t vdin_attr_store(struct device *dev, pr_info("urgent_en (%d):%d\n", devp->index, devp->urgent_en); } - } else if (!strcmp(parm[0], "irq_flag")) { - if (!parm[1]) - pr_err("miss parameters .\n"); - else if (kstrtoul(parm[1], 10, &val) == 0) { - devp->vdin_irq_flag = val; - pr_info("vdin(%d) irq_flag: %d\n", devp->index, - devp->vdin_irq_flag); - } - } else if (!strcmp(parm[0], "skip_vf_num")) { + } else if (!strcmp(parm[0], "irq_cnt")) + pr_info("vdin(%d) irq_cnt: %d\n", devp->index, devp->irq_cnt); + else if (!strcmp(parm[0], "skip_vf_num")) { if (!parm[1]) pr_err("miss parameters .\n"); else if ((kstrtoul(parm[1], 10, &val) == 0) && (devp->vfp)) { @@ -2198,9 +2192,14 @@ static ssize_t vdin_attr_store(struct device *dev, } else { pr_info("vdin_afbce_mode: %d\n", devp->afbce_mode); } - } else { + } else if (!strcmp(parm[0], "vdi6_afifo_overflow")) + pr_info("%d\n", + vdin_check_vdi6_afifo_overflow(devp->addr_offset)); + else if (!strcmp(parm[0], "vdi6_afifo_clear")) + vdin_clear_vdi6_afifo_overflow_flg(devp->addr_offset); + else pr_info("unknown command\n"); - } + kfree(buf_orig); return len; } diff --git a/drivers/amlogic/media/vin/tvin/vdin/vdin_drv.c b/drivers/amlogic/media/vin/tvin/vdin/vdin_drv.c index c2f3cb493f75f..a0dd165822c38 100644 --- a/drivers/amlogic/media/vin/tvin/vdin/vdin_drv.c +++ b/drivers/amlogic/media/vin/tvin/vdin/vdin_drv.c @@ -41,9 +41,13 @@ #include #include #include +#include +#include +#include #include #include #include +#include /* Amlogic Headers */ #include #include @@ -80,6 +84,8 @@ static unsigned long mem_start, mem_end; static unsigned int use_reserved_mem; static unsigned int pr_times; +struct vdin_set_canvas_addr_s vdin_set_canvas_addr[VDIN_CANVAS_MAX_CNT]; +static DECLARE_WAIT_QUEUE_HEAD(vframe_waitq); /* * canvas_config_mode * 0: canvas_config in driver probe @@ -874,6 +880,7 @@ int start_tvin_service(int no, struct vdin_parm_s *para) fe = tvin_get_frontend(para->port, 1); } else fe = tvin_get_frontend(para->port, 0); + if (fe) { fe->private_data = para; fe->port = para->port; @@ -901,6 +908,7 @@ int start_tvin_service(int no, struct vdin_parm_s *para) (viu_hw_irq != 0)) { ret = request_irq(devp->irq, vdin_v4l2_isr, IRQF_SHARED, devp->irq_name, (void *)devp); + if (ret != 0) { pr_info("vdin_v4l2_isr request irq error.\n"); return -1; @@ -1615,7 +1623,7 @@ irqreturn_t vdin_isr(int irq, void *dev_id) devp->format_convert, devp->color_depth_mode, devp->source_bitdepth, devp->flags&VDIN_FLAG_RDMA_ENABLE); - vdin_set_top(devp->addr_offset, devp->parm.port, + vdin_set_top(devp, devp->addr_offset, devp->parm.port, devp->prop.color_format, devp->h_active, devp->bt_path); @@ -1970,6 +1978,15 @@ module_param(skip_ratio, ushort, 0664); MODULE_PARM_DESC(skip_ratio, "\n vdin skip frame ratio 1/ratio will reserved.\n"); +static struct vf_entry *check_vdin_readlist(struct vdin_dev_s *devp) +{ + struct vf_entry *vfe; + + vfe = receiver_vf_peek(devp->vfp); + + return vfe; +} + irqreturn_t vdin_v4l2_isr(int irq, void *dev_id) { ulong flags; @@ -1981,7 +1998,7 @@ irqreturn_t vdin_v4l2_isr(int irq, void *dev_id) struct tvin_decoder_ops_s *decops; struct tvin_state_machine_ops_s *sm_ops; int ret = 0; - int offset; + unsigned int offset; if (!devp) return IRQ_HANDLED; @@ -1996,6 +2013,7 @@ irqreturn_t vdin_v4l2_isr(int irq, void *dev_id) spin_lock_irqsave(&devp->isr_lock, flags); devp->vdin_reset_flag = vdin_vsync_reset_mif(devp->index); offset = devp->addr_offset; + if (devp) /* avoid null pointer oops */ stamp = vdin_get_meas_vstamp(offset); @@ -2019,12 +2037,21 @@ irqreturn_t vdin_v4l2_isr(int irq, void *dev_id) } } + if ((devp->set_canvas_manual == 1) && check_vdin_readlist(devp)) { + devp->keystone_vframe_ready = 1; + wake_up_interruptible(&vframe_waitq); + } + if (devp->last_wr_vfe) { provider_vf_put(devp->last_wr_vfe, devp->vfp); devp->last_wr_vfe = NULL; - vf_notify_receiver(devp->name, + + if (devp->set_canvas_manual != 1) { + vf_notify_receiver(devp->name, VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); + } } + /*check vs is valid base on the time during continuous vs*/ vdin_check_cycle(devp); @@ -2101,6 +2128,7 @@ irqreturn_t vdin_v4l2_isr(int irq, void *dev_id) goto irq_handled; } } + if (curr_wr_vfe) { curr_wr_vfe->flag |= VF_FLAG_NORMAL_FRAME; /* provider_vf_put(curr_wr_vfe, devp->vfp); */ @@ -2124,8 +2152,10 @@ irqreturn_t vdin_v4l2_isr(int irq, void *dev_id) } devp->curr_wr_vfe = next_wr_vfe; - vf_notify_receiver(devp->name, VFRAME_EVENT_PROVIDER_VFRAME_READY, - NULL); + + if (devp->set_canvas_manual != 1) + vf_notify_receiver(devp->name, + VFRAME_EVENT_PROVIDER_VFRAME_READY, NULL); irq_handled: spin_unlock_irqrestore(&devp->isr_lock, flags); @@ -2188,6 +2218,9 @@ static int vdin_open(struct inode *inode, struct file *file) devp = container_of(inode->i_cdev, struct vdin_dev_s, cdev); file->private_data = devp; + if (devp->set_canvas_manual == 1) + return 0; + if (devp->index >= VDIN_MAX_DEVS) return -ENXIO; @@ -2293,12 +2326,17 @@ static int vdin_release(struct inode *inode, struct file *file) static long vdin_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret = 0; + int i; int callmaster_status = 0; struct vdin_dev_s *devp = NULL; void __user *argp = (void __user *)arg; struct vdin_parm_s param; ulong flags; struct vdin_hist_s vdin1_hist_temp; + struct page *page; + struct vdin_set_canvas_s vdinsetcanvas[VDIN_CANVAS_MAX_CNT]; + unsigned int idx = 0; + unsigned int recov_idx = 0; /* Get the per-device structure that contains this cdev */ devp = file->private_data; @@ -2415,6 +2453,7 @@ static long vdin_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } case TVIN_IOC_STOP_DEC: { struct tvin_parm_s *parm = &devp->parm; + mutex_lock(&devp->fe_lock); if (!(devp->flags & VDIN_FLAG_DEC_STARTED)) { pr_err("TVIN_IOC_STOP_DEC(%d) decode havn't started\n", @@ -2471,6 +2510,7 @@ static long vdin_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TVIN_IOC_CLOSE: { struct tvin_parm_s *parm = &devp->parm; enum tvin_port_e port = parm->port; + mutex_lock(&devp->fe_lock); if (!(devp->flags & VDIN_FLAG_DEC_OPENED)) { pr_err("TVIN_IOC_CLOSE(%d) you have not opened port\n", @@ -2772,25 +2812,34 @@ static long vdin_ioctl(struct file *file, unsigned int cmd, unsigned long arg) param.port = TVIN_PORT_VIU1_WB0_VPP; else param.port = TVIN_PORT_VIU1; - param.reserved |= PARAM_STATE_HISTGRAM; + param.h_active = vdin_v4l2_param.width; param.v_active = vdin_v4l2_param.height; - /* use 1280X720 for histgram*/ - if ((vdin_v4l2_param.width > 1280) && - (vdin_v4l2_param.height > 720)) { - devp->debug.scaler4w = 1280; - devp->debug.scaler4h = 720; - devp->debug.dest_cfmt = TVIN_YUV422; - devp->flags |= VDIN_FLAG_MANUAL_CONVERSION; + + if (devp->set_canvas_manual != 1) { + param.reserved |= PARAM_STATE_HISTGRAM; + /* use 1280X720 for histgram*/ + if ((vdin_v4l2_param.width > 1280) && + (vdin_v4l2_param.height > 720)) { + devp->debug.scaler4w = 1280; + devp->debug.scaler4h = 720; + devp->debug.dest_cfmt = TVIN_YUV422; + devp->flags |= VDIN_FLAG_MANUAL_CONVERSION; + } } + param.frame_rate = vdin_v4l2_param.fps; param.cfmt = TVIN_YUV422; - param.dfmt = TVIN_YUV422; + + if (devp->set_canvas_manual == 1) + param.dfmt = TVIN_RGB444; + else + param.dfmt = TVIN_YUV422; + param.scan_mode = TVIN_SCAN_MODE_PROGRESSIVE; param.fmt = TVIN_SIG_FMT_MAX; //devp->flags |= VDIN_FLAG_V4L2_DEBUG; devp->hist_bar_enable = 1; - devp->index = 1; start_tvin_service(devp->index, ¶m); break; @@ -2803,7 +2852,101 @@ static long vdin_ioctl(struct file *file, unsigned int cmd, unsigned long arg) devp->flags &= (~VDIN_FLAG_ISR_REQ); devp->flags &= (~VDIN_FLAG_FS_OPENED); stop_tvin_service(devp->index); + + /*release manual set dma-bufs*/ + if (devp->set_canvas_manual == 1) { + for (i = 0; i < 4; i++) { + if (vdin_set_canvas_addr[i].dmabuff == 0) + continue; + + dma_buf_unmap_attachment( + vdin_set_canvas_addr[i].dmabufattach, + vdin_set_canvas_addr[i].sgtable, + DMA_BIDIRECTIONAL); + dma_buf_detach( + vdin_set_canvas_addr[i].dmabuff, + vdin_set_canvas_addr[i].dmabufattach); + dma_buf_put(vdin_set_canvas_addr[i].dmabuff); + devp->keystone_entry[i] = NULL; + } + memset(vdin_set_canvas_addr, 0, + sizeof(struct vdin_set_canvas_addr_s) * + VDIN_CANVAS_MAX_CNT); + } break; + + case TVIN_IOC_S_CANVAS_ADDR: + if (devp->index == 0) { + pr_info("TVIN_IOC_S_CANVAS_ADDR can't be used at vdin0\n"); + break; + } + + if (copy_from_user(vdinsetcanvas, argp, + sizeof(struct vdin_set_canvas_s) * 4)) { + pr_info("TVIN_IOC_S_CANVAS_ADDR copy fail\n"); + return -EFAULT; + } + + for (i = 0; i < 4; i++) { + /*when fd means, the canvas list reaches end*/ + if (vdinsetcanvas[i].fd < 0) + break; + + if (vdinsetcanvas[i].index >= VDIN_CANVAS_MAX_CNT) { + pr_err("vdin buf idx range (0 ~ %d), current idx is too big.\n ", + VDIN_CANVAS_MAX_CNT - 1); + continue; + } + + idx = vdinsetcanvas[i].index; + + vdin_set_canvas_addr[idx].dmabuff = + dma_buf_get(vdinsetcanvas[i].fd); + + vdin_set_canvas_addr[idx].dmabufattach = + dma_buf_attach( + vdin_set_canvas_addr[idx].dmabuff, + devp->dev); + vdin_set_canvas_addr[idx].sgtable = + dma_buf_map_attachment( + vdin_set_canvas_addr[idx].dmabufattach, + DMA_BIDIRECTIONAL); + + page = sg_page(vdin_set_canvas_addr[idx].sgtable->sgl); + vdin_set_canvas_addr[idx].paddr = + PFN_PHYS(page_to_pfn(page)); + vdin_set_canvas_addr[idx].size = + vdin_set_canvas_addr[idx].dmabuff->size; + + pr_info("TVIN_IOC_S_CANVAS_ADDR[%d] addr=0x%lx, len=0x%x.\n", + i, + vdin_set_canvas_addr[idx].paddr, + vdin_set_canvas_addr[idx].size); + + __close_fd(current->files, vdinsetcanvas[i].fd); + } + break; + + case TVIN_IOC_S_CANVAS_RECOVERY: + if (devp->index == 0) { + pr_info("TVIN_IOC_S_CANVAS_RECOVERY can't be used at vdin0\n"); + break; + } + + if (copy_from_user(&recov_idx, argp, sizeof(unsigned int))) { + pr_info("TVIN_IOC_S_CANVAS_RECOVERY copy fail\n"); + return -EFAULT; + } + + if (devp->keystone_entry[recov_idx]) { + receiver_vf_put(&devp->keystone_entry[recov_idx]->vf, + devp->vfp); + devp->keystone_entry[recov_idx] = NULL; + } else + pr_err("[vdin.%d] idx %d RECOVERY error\n", + devp->index, recov_idx); + break; + default: ret = -ENOIOCTLCMD; /* pr_info("%s %d is not supported command\n", __func__, cmd); */ @@ -2865,22 +3008,57 @@ static unsigned int vdin_poll(struct file *file, poll_table *wait) struct vdin_dev_s *devp = file->private_data; unsigned int mask = 0; - poll_wait(file, &devp->queue, wait); - mask = (POLLIN | POLLRDNORM); + if (devp->set_canvas_manual == 1) { + poll_wait(file, &vframe_waitq, wait); + + if (devp->keystone_vframe_ready == 1) + mask = (POLLIN | POLLRDNORM); + } else { + poll_wait(file, &devp->queue, wait); + mask = (POLLIN | POLLRDNORM); + } return mask; } +static ssize_t vdin_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int index; + long ret; + struct vf_entry *vfe; + struct vdin_dev_s *devp = file->private_data; + + vfe = receiver_vf_peek(devp->vfp); + if (!vfe) + return 0; + + vfe = receiver_vf_get(devp->vfp); + /*index = report_canvas_index;*/ + index = vfe->vf.index; + devp->keystone_entry[index] = vfe; + ret = copy_to_user(buf, (void *)(&index), sizeof(int)); + if (ret) { + pr_info("vdin_read copy_to_user error\n"); + return -1; + } + + devp->keystone_vframe_ready = 0; + + return sizeof(int); +} + static const struct file_operations vdin_fops = { - .owner = THIS_MODULE, - .open = vdin_open, - .release = vdin_release, - .unlocked_ioctl = vdin_ioctl, + .owner = THIS_MODULE, + .open = vdin_open, + .read = vdin_read, + .release = vdin_release, + .unlocked_ioctl = vdin_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = vdin_compat_ioctl, #endif - .mmap = vdin_mmap, - .poll = vdin_poll, + .mmap = vdin_mmap, + .poll = vdin_poll, }; @@ -3068,6 +3246,16 @@ static int vdin_drv_probe(struct platform_device *pdev) } } + ret = of_property_read_u32(pdev->dev.of_node, + "set_canvas_manual", &vdevp->set_canvas_manual); + + if (ret) { + vdevp->set_canvas_manual = 0; + pr_info("set_canvas_manual = 0\n"); + } else { + pr_info("set_canvas_manual = %d\n", vdevp->set_canvas_manual); + } + /*vdin urgent en*/ ret = of_property_read_u32(pdev->dev.of_node, "urgent_en", &urgent_en); @@ -3087,16 +3275,12 @@ static int vdin_drv_probe(struct platform_device *pdev) /* @todo vdin_addr_offset */ if (is_meson_gxbb_cpu() && vdevp->index) vdin_addr_offset[vdevp->index] = 0x70; - else if ((is_meson_g12a_cpu() || is_meson_g12b_cpu() || - is_meson_tl1_cpu() || is_meson_sm1_cpu() || - is_meson_tm2_cpu()) && vdevp->index) + else if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A) && vdevp->index) vdin_addr_offset[vdevp->index] = 0x100; vdevp->addr_offset = vdin_addr_offset[vdevp->index]; vdevp->flags = 0; /*canvas align number*/ - if (is_meson_g12a_cpu() || is_meson_g12b_cpu() || - is_meson_tl1_cpu() || is_meson_sm1_cpu() || - is_meson_tm2_cpu()) + if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) vdevp->canvas_align = 64; else vdevp->canvas_align = 32; diff --git a/drivers/amlogic/media/vin/tvin/vdin/vdin_drv.h b/drivers/amlogic/media/vin/tvin/vdin/vdin_drv.h index 74d809d6f91ee..c5cc7b64d3d72 100644 --- a/drivers/amlogic/media/vin/tvin/vdin/vdin_drv.h +++ b/drivers/amlogic/media/vin/tvin/vdin/vdin_drv.h @@ -157,6 +157,21 @@ static inline const char *vdin_fmt_convert_str( } } +struct vdin_set_canvas_s { + int fd; + int index; +}; + +struct vdin_set_canvas_addr_s { + long paddr; + int size; + + struct dma_buf *dmabuff; + struct dma_buf_attachment *dmabufattach; + struct sg_table *sgtable; +}; +extern struct vdin_set_canvas_addr_s vdin_set_canvas_addr[VDIN_CANVAS_MAX_CNT]; + /*******for debug **********/ struct vdin_debug_s { struct tvin_cutwin_s cutwin; @@ -351,6 +366,11 @@ struct vdin_dev_s { unsigned int afbce_mode_pre; unsigned int afbce_mode; unsigned int afbce_valid; + + /*fot 'T correction' on projector*/ + unsigned int set_canvas_manual; + unsigned int keystone_vframe_ready; + struct vf_entry *keystone_entry[VDIN_CANVAS_MAX_CNT]; unsigned int canvas_config_mode; bool prehsc_en; bool vshrk_en; @@ -368,7 +388,6 @@ struct vdin_dev_s { unsigned int vdin_reset_flag; unsigned int vdin_dev_ssize; wait_queue_head_t queue; - struct dentry *dbg_root; /*dbg_fs*/ }; diff --git a/drivers/amlogic/media/vin/tvin/viu/viuin.c b/drivers/amlogic/media/vin/tvin/viu/viuin.c index 5b17e7a9c3c70..e8121760f92d3 100644 --- a/drivers/amlogic/media/vin/tvin/viu/viuin.c +++ b/drivers/amlogic/media/vin/tvin/viu/viuin.c @@ -217,9 +217,7 @@ static int viuin_open(struct tvin_frontend_s *fe, enum tvin_port_e port) wr_viu(VPU_VIU2VDIN_HDN_CTRL, 0x40f00); } else wr_bits_viu(VPU_VIU2VDIN_HDN_CTRL, devp->parm.h_active, 0, 14); - if (is_meson_g12a_cpu() || is_meson_g12b_cpu() || - is_meson_tl1_cpu() || is_meson_sm1_cpu() || - is_meson_tm2_cpu()) { + if (cpu_after_eq(MESON_CPU_MAJOR_ID_G12A)) { if (((port >= TVIN_PORT_VIU1_WB0_VD1) && (port <= TVIN_PORT_VIU1_WB0_POST_BLEND)) || ((port >= TVIN_PORT_VIU2_WB0_VD1) && @@ -263,9 +261,11 @@ static int viuin_open(struct tvin_frontend_s *fe, enum tvin_port_e port) (port == TVIN_PORT_VIU2_WB0_POST_BLEND)) wr_bits_viu(VPP_WRBAK_CTRL, 5, 0, 3); else if ((port == TVIN_PORT_VIU1_WB0_VPP) || - (port == TVIN_PORT_VIU2_WB0_VPP)) + (port == TVIN_PORT_VIU2_WB0_VPP)) { wr_bits_viu(VPP_WRBAK_CTRL, 6, 0, 3); - else + /*increase h banking in case vdin afifo overflow*/ + wr_bits_viu(VPP_WRBAK_CTRL, 0xff, 16, 8); + } else wr_bits_viu(VPP_WRBAK_CTRL, 0, 4, 3); if ((port == TVIN_PORT_VIU1_WB1_VD1) || diff --git a/include/linux/amlogic/media/frame_provider/tvin/tvin.h b/include/linux/amlogic/media/frame_provider/tvin/tvin.h index fe41e165f1e68..25f5421b84b9e 100644 --- a/include/linux/amlogic/media/frame_provider/tvin/tvin.h +++ b/include/linux/amlogic/media/frame_provider/tvin/tvin.h @@ -449,7 +449,9 @@ struct tvafe_pin_mux_s { struct tvin_latency_s) #define TVIN_IOC_G_FRONTEND_INFO _IOR(_TM_T, 0x4e,\ struct tvin_frontend_info_s) - +#define TVIN_IOC_S_CANVAS_ADDR _IOW(_TM_T, 0x4f,\ + struct vdin_set_canvas_s) +#define TVIN_IOC_S_CANVAS_RECOVERY _IO(_TM_T, 0x0a) /* TVAFE */ #define TVIN_IOC_S_AFE_VGA_PARM _IOW(_TM_T, 0x16, struct tvafe_vga_parm_s) #define TVIN_IOC_G_AFE_VGA_PARM _IOR(_TM_T, 0x17, struct tvafe_vga_parm_s)