diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0120-media-aspeed-adjust-irq-enabling-timing-and-resource.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0120-media-aspeed-adjust-irq-enabling-timing-and-resource.patch | 512 |
1 files changed, 512 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0120-media-aspeed-adjust-irq-enabling-timing-and-resource.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0120-media-aspeed-adjust-irq-enabling-timing-and-resource.patch new file mode 100644 index 000000000..3474f0c8b --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0120-media-aspeed-adjust-irq-enabling-timing-and-resource.patch @@ -0,0 +1,512 @@ +From 82109f3a6a9d044e7244f186eff53dac0bbe87fe Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Tue, 29 Sep 2020 16:29:28 -0700 +Subject: [PATCH] media: aspeed: adjust irq enabling timing and resource + handling + +This commit makes irq enabling to be after video engine +initialization to avoid any garbage interrupt handling in +uninitialized state. Also, this commit changes behavior of DMA +memory allocation for frame buffers and JPEG header buffer from +dynamic to static for better performance and to avoid any potential +memory corruption issue caused by invalid DMA address or length. +This commit also changes VR004[5] bit handling logic to set the bit +only when capture and compression is triggered. + +Also, it fixes the clock enabling flow to give a sufficient delay +to the video engine hardware to make it get stablized itself. +Currently, only eclk is coupled with SCU04[6] reset flag for +video engine so 10ms of delay will be made by the clk-aspeed module +when this driver enables eclk. Thus, clock enabling order should +be vclk and then eclk to get sufficient delay after enabling +clocks and resetting the hardware. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + drivers/media/platform/aspeed-video.c | 245 ++++++++++++++++---------- + 1 file changed, 151 insertions(+), 94 deletions(-) + +diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c +index a09cdb148c53..cf49c52fa5f0 100644 +--- a/drivers/media/platform/aspeed-video.c ++++ b/drivers/media/platform/aspeed-video.c +@@ -52,9 +52,12 @@ + + #define VE_MAX_SRC_BUFFER_SIZE 0x8ca000 /* 1920 * 1200, 32bpp */ + #define VE_JPEG_HEADER_SIZE 0x006000 /* 512 * 12 * 4 */ ++#define VE_MAX_COMP_BUFFER_SIZE 0x400000 /* 128KB * 32 */ ++#define VE_MAX_BCD_FLAG_BUFFER_SIZE 0x008ca0 /* (1920 / 4) * (1200 / 4) */ + + #define VE_PROTECTION_KEY 0x000 + #define VE_PROTECTION_KEY_UNLOCK 0x1a038aa8 ++#define VE_PROTECTION_KEY_LOCK 0x0 + + #define VE_SEQ_CTRL 0x004 + #define VE_SEQ_CTRL_TRIG_MODE_DET BIT(0) +@@ -105,6 +108,8 @@ + #define VE_SCALING_FILTER2 0x020 + #define VE_SCALING_FILTER3 0x024 + ++#define VE_BCD_CTRL 0x02c ++ + #define VE_CAP_WINDOW 0x030 + #define VE_COMP_WINDOW 0x034 + #define VE_COMP_PROC_OFFSET 0x038 +@@ -113,6 +118,7 @@ + #define VE_SRC0_ADDR 0x044 + #define VE_SRC_SCANLINE_OFFSET 0x048 + #define VE_SRC1_ADDR 0x04c ++#define VE_BCD_ADDR 0x050 + #define VE_COMP_ADDR 0x054 + + #define VE_STREAM_BUF_SIZE 0x058 +@@ -168,6 +174,9 @@ + #define VE_SYNC_STATUS_VSYNC_SHF 16 + #define VE_SYNC_STATUS_VSYNC GENMASK(27, VE_SYNC_STATUS_VSYNC_SHF) + ++#define VE_VM_SRC_ADDR 0x244 ++#define VE_VM_COMP_ADDR 0x254 ++ + #define VE_INTERRUPT_CTRL 0x304 + #define VE_INTERRUPT_STATUS 0x308 + #define VE_INTERRUPT_MODE_DETECT_WD BIT(0) +@@ -234,8 +243,11 @@ struct aspeed_video { + unsigned int sequence; + + unsigned int max_compressed_size; ++ struct reserved_mem *rsvd_mem; + struct aspeed_video_addr srcs[2]; +- struct aspeed_video_addr jpeg; ++ struct aspeed_video_addr jpeg_hdr; ++ struct aspeed_video_addr comp; ++ struct aspeed_video_addr bcd; + + bool yuv420; + unsigned int frame_rate; +@@ -439,6 +451,7 @@ static int aspeed_video_start_frame(struct aspeed_video *video) + unsigned long flags; + struct aspeed_video_buffer *buf; + u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL); ++ u32 comp_ctrl; + + if (video->v4l2_input_status) { + dev_dbg(video->dev, "No signal; don't start frame\n"); +@@ -467,12 +480,23 @@ static int aspeed_video_start_frame(struct aspeed_video *video) + aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0); + aspeed_video_write(video, VE_COMP_OFFSET, 0); + aspeed_video_write(video, VE_COMP_ADDR, addr); ++ comp_ctrl = VE_COMP_CTRL_RSVD | ++ FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) | ++ FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10); ++ aspeed_video_update(video, VE_COMP_CTRL, ++ VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR, ++ comp_ctrl); + + aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, + VE_INTERRUPT_COMP_COMPLETE); + ++ /* VE_SEQ_CTRL_AUTO_COMP should be set before VE_SEQ_CTRL_TRIG_COMP */ ++ aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_AUTO_COMP); ++ if (video->yuv420) ++ aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_YUV420); + aspeed_video_update(video, VE_SEQ_CTRL, 0, +- VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP); ++ VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP | ++ VE_SEQ_CTRL_JPEG_MODE); + + return 0; + } +@@ -497,8 +521,8 @@ static void aspeed_video_off(struct aspeed_video *video) + aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); + + /* Turn off the relevant clocks */ +- clk_disable(video->vclk); + clk_disable(video->eclk); ++ clk_disable(video->vclk); + + clear_bit(VIDEO_CLOCKS_ON, &video->flags); + } +@@ -509,8 +533,8 @@ static void aspeed_video_on(struct aspeed_video *video) + return; + + /* Turn on the relevant clocks */ +- clk_enable(video->eclk); + clk_enable(video->vclk); ++ clk_enable(video->eclk); + + set_bit(VIDEO_CLOCKS_ON, &video->flags); + } +@@ -602,7 +626,10 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) + aspeed_video_update(video, VE_SEQ_CTRL, + VE_SEQ_CTRL_TRIG_CAPTURE | + VE_SEQ_CTRL_FORCE_IDLE | +- VE_SEQ_CTRL_TRIG_COMP, 0); ++ VE_SEQ_CTRL_TRIG_COMP | ++ VE_SEQ_CTRL_AUTO_COMP | ++ VE_SEQ_CTRL_YUV420 | ++ VE_SEQ_CTRL_JPEG_MODE, 0); + aspeed_video_update(video, VE_INTERRUPT_CTRL, + VE_INTERRUPT_COMP_COMPLETE, 0); + aspeed_video_write(video, VE_INTERRUPT_STATUS, +@@ -686,6 +713,9 @@ static bool aspeed_video_alloc_buf(struct aspeed_video *video, + static void aspeed_video_free_buf(struct aspeed_video *video, + struct aspeed_video_addr *addr) + { ++ if (!addr->virt) ++ return; ++ + dma_free_coherent(video->dev, addr->size, addr->virt, addr->dma); + addr->size = 0; + addr->dma = 0ULL; +@@ -824,14 +854,10 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) + det->width = (video->frame_right - video->frame_left) + 1; + video->v4l2_input_status = 0; + +- /* +- * Enable mode-detect watchdog, resolution-change watchdog and +- * automatic compression after frame capture. +- */ ++ /* Enable mode-detect watchdog and resolution-change watchdog */ + aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, + VE_INTERRUPT_MODE_DETECT_WD); +- aspeed_video_update(video, VE_SEQ_CTRL, 0, +- VE_SEQ_CTRL_AUTO_COMP | VE_SEQ_CTRL_EN_WATCHDOG); ++ aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_EN_WATCHDOG); + + dev_dbg(video->dev, "Got resolution: %dx%d\n", det->width, + det->height); +@@ -880,64 +906,38 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) + } else { + aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH); + } +- +- size *= 4; +- +- if (size != video->srcs[0].size) { +- if (video->srcs[0].size) +- aspeed_video_free_buf(video, &video->srcs[0]); +- if (video->srcs[1].size) +- aspeed_video_free_buf(video, &video->srcs[1]); +- +- if (!aspeed_video_alloc_buf(video, &video->srcs[0], size)) +- goto err_mem; +- if (!aspeed_video_alloc_buf(video, &video->srcs[1], size)) +- goto err_mem; +- +- aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma); +- aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma); +- } +- +- return; +- +-err_mem: +- dev_err(video->dev, "Failed to allocate source buffers\n"); +- +- if (video->srcs[0].size) +- aspeed_video_free_buf(video, &video->srcs[0]); + } + + static void aspeed_video_init_regs(struct aspeed_video *video) + { +- u32 comp_ctrl = VE_COMP_CTRL_RSVD | +- FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) | +- FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10); + u32 ctrl = VE_CTRL_AUTO_OR_CURSOR; +- u32 seq_ctrl = VE_SEQ_CTRL_JPEG_MODE; + + if (video->frame_rate) + ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate); + +- if (video->yuv420) +- seq_ctrl |= VE_SEQ_CTRL_YUV420; +- + /* Unlock VE registers */ + aspeed_video_write(video, VE_PROTECTION_KEY, VE_PROTECTION_KEY_UNLOCK); + ++ /* Set buffer addresses */ ++ aspeed_video_write(video, VE_MEM_RESTRICT_START, video->rsvd_mem->base); ++ aspeed_video_write(video, VE_MEM_RESTRICT_END, ++ video->rsvd_mem->base + video->rsvd_mem->size); ++ aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg_hdr.dma); ++ aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma); ++ aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma); ++ aspeed_video_write(video, VE_BCD_ADDR, video->bcd.dma); ++ aspeed_video_write(video, VE_VM_SRC_ADDR, video->srcs[0].dma); ++ aspeed_video_write(video, VE_VM_COMP_ADDR, video->comp.dma); ++ + /* Disable interrupts */ + aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); + aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); + +- /* Clear the offset */ +- aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0); +- aspeed_video_write(video, VE_COMP_OFFSET, 0); +- +- aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma); +- + /* Set control registers */ +- aspeed_video_write(video, VE_SEQ_CTRL, seq_ctrl); ++ aspeed_video_write(video, VE_SEQ_CTRL, 0); ++ aspeed_video_write(video, VE_COMP_CTRL, 0); ++ aspeed_video_write(video, VE_BCD_CTRL, 0); + aspeed_video_write(video, VE_CTRL, ctrl); +- aspeed_video_write(video, VE_COMP_CTRL, comp_ctrl); + + /* Don't downscale */ + aspeed_video_write(video, VE_SCALING_FACTOR, 0x10001000); +@@ -975,11 +975,8 @@ static void aspeed_video_stop(struct aspeed_video *video) + + aspeed_video_off(video); + +- if (video->srcs[0].size) +- aspeed_video_free_buf(video, &video->srcs[0]); +- +- if (video->srcs[1].size) +- aspeed_video_free_buf(video, &video->srcs[1]); ++ /* Lock VE registers */ ++ aspeed_video_write(video, VE_PROTECTION_KEY, VE_PROTECTION_KEY_LOCK); + + video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + video->flags = 0; +@@ -1275,8 +1272,9 @@ static void aspeed_video_update_jpeg_quality(struct aspeed_video *video) + + static void aspeed_video_update_subsampling(struct aspeed_video *video) + { +- if (video->jpeg.virt) +- aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420); ++ if (video->jpeg_hdr.virt) ++ aspeed_video_init_jpeg_table(video->jpeg_hdr.virt, ++ video->yuv420); + + if (video->yuv420) + aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_YUV420); +@@ -1511,6 +1509,8 @@ static int aspeed_video_setup_video(struct aspeed_video *video) + struct v4l2_device *v4l2_dev = &video->v4l2_dev; + struct vb2_queue *vbq = &video->queue; + struct video_device *vdev = &video->vdev; ++ struct device *dev = video->dev; ++ int irq; + int rc; + + video->pix_fmt.pixelformat = V4L2_PIX_FMT_JPEG; +@@ -1535,12 +1535,9 @@ static int aspeed_video_setup_video(struct aspeed_video *video) + V4L2_JPEG_CHROMA_SUBSAMPLING_444); + + if (video->ctrl_handler.error) { +- v4l2_ctrl_handler_free(&video->ctrl_handler); +- v4l2_device_unregister(v4l2_dev); +- + dev_err(video->dev, "Failed to init controls: %d\n", + video->ctrl_handler.error); +- return rc; ++ goto err_release_v4l2_dev; + } + + v4l2_dev->ctrl_handler = &video->ctrl_handler; +@@ -1558,11 +1555,8 @@ static int aspeed_video_setup_video(struct aspeed_video *video) + + rc = vb2_queue_init(vbq); + if (rc) { +- v4l2_ctrl_handler_free(&video->ctrl_handler); +- v4l2_device_unregister(v4l2_dev); +- + dev_err(video->dev, "Failed to init vb2 queue\n"); +- return rc; ++ goto err_release_v4l2_dev; + } + + vdev->queue = vbq; +@@ -1580,36 +1574,41 @@ static int aspeed_video_setup_video(struct aspeed_video *video) + video_set_drvdata(vdev, video); + rc = video_register_device(vdev, VFL_TYPE_GRABBER, 0); + if (rc) { +- vb2_queue_release(vbq); +- v4l2_ctrl_handler_free(&video->ctrl_handler); +- v4l2_device_unregister(v4l2_dev); +- + dev_err(video->dev, "Failed to register video device\n"); +- return rc; ++ goto err_release_vb2_queue; + } + +- return 0; +-} +- +-static int aspeed_video_init(struct aspeed_video *video) +-{ +- int irq; +- int rc; +- struct device *dev = video->dev; +- + irq = irq_of_parse_and_map(dev->of_node, 0); + if (!irq) { + dev_err(dev, "Unable to find IRQ\n"); +- return -ENODEV; ++ rc = -ENODEV; ++ goto err_release_vb2_queue; + } + + rc = devm_request_threaded_irq(dev, irq, NULL, aspeed_video_irq, + IRQF_ONESHOT, DEVICE_NAME, video); +- if (rc < 0) { ++ if (rc) { + dev_err(dev, "Unable to request IRQ %d\n", irq); +- return rc; ++ goto err_release_vb2_queue; + } + ++ return 0; ++ ++err_release_vb2_queue: ++ vb2_queue_release(vbq); ++err_release_v4l2_dev: ++ v4l2_ctrl_handler_free(&video->ctrl_handler); ++ v4l2_device_unregister(v4l2_dev); ++ ++ return rc; ++} ++ ++static int aspeed_video_init(struct aspeed_video *video) ++{ ++ int rc; ++ struct device *dev = video->dev; ++ struct device_node *node; ++ + video->eclk = devm_clk_get(dev, "eclk"); + if (IS_ERR(video->eclk)) { + dev_err(dev, "Unable to get ECLK\n"); +@@ -1631,7 +1630,24 @@ static int aspeed_video_init(struct aspeed_video *video) + if (rc) + goto err_unprepare_eclk; + +- of_reserved_mem_device_init(dev); ++ rc = of_reserved_mem_device_init(dev); ++ if (rc) { ++ dev_err(dev, "Unable to get reserved memory %d\n", rc); ++ goto err_unprepare_eclk; ++ } ++ ++ node = of_parse_phandle(dev->of_node, "memory-region", 0); ++ if (!node) { ++ rc = -ENOENT; ++ goto err_unprepare_eclk; ++ } ++ ++ video->rsvd_mem = of_reserved_mem_lookup(node); ++ of_node_put(node); ++ if (!video->rsvd_mem) { ++ rc = -ENOENT; ++ goto err_unprepare_eclk; ++ } + + rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (rc) { +@@ -1639,17 +1655,55 @@ static int aspeed_video_init(struct aspeed_video *video) + goto err_release_reserved_mem; + } + +- if (!aspeed_video_alloc_buf(video, &video->jpeg, ++ if (!aspeed_video_alloc_buf(video, &video->jpeg_hdr, + VE_JPEG_HEADER_SIZE)) { + dev_err(dev, "Failed to allocate DMA for JPEG header\n"); + rc = -ENOMEM; + goto err_release_reserved_mem; + } + +- aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420); ++ if (!aspeed_video_alloc_buf(video, &video->srcs[0], ++ VE_MAX_SRC_BUFFER_SIZE)) { ++ dev_err(dev, "Failed to allocate DMA for SRCS[0]\n"); ++ rc = -ENOMEM; ++ goto err_release_dma_mem; ++ } ++ ++ if (!aspeed_video_alloc_buf(video, &video->srcs[1], ++ VE_MAX_SRC_BUFFER_SIZE)) { ++ dev_err(dev, "Failed to allocate DMA for SRCS[1]\n"); ++ rc = -ENOMEM; ++ goto err_release_dma_mem; ++ } ++ ++ if (!aspeed_video_alloc_buf(video, &video->comp, ++ VE_MAX_COMP_BUFFER_SIZE)) { ++ dev_err(dev, "Failed to allocate DMA for compressed video\n"); ++ rc = -ENOMEM; ++ goto err_release_dma_mem; ++ } ++ ++ if (!aspeed_video_alloc_buf(video, &video->bcd, ++ VE_MAX_BCD_FLAG_BUFFER_SIZE)) { ++ dev_err(dev, "Failed to allocate DMA for BCD flag\n"); ++ rc = -ENOMEM; ++ goto err_release_dma_mem; ++ } ++ ++ aspeed_video_init_jpeg_table(video->jpeg_hdr.virt, video->yuv420); ++ ++ aspeed_video_on(video); ++ aspeed_video_init_regs(video); ++ aspeed_video_off(video); + + return 0; + ++err_release_dma_mem: ++ aspeed_video_free_buf(video, &video->comp); ++ aspeed_video_free_buf(video, &video->bcd); ++ aspeed_video_free_buf(video, &video->jpeg_hdr); ++ aspeed_video_free_buf(video, &video->srcs[0]); ++ aspeed_video_free_buf(video, &video->srcs[1]); + err_release_reserved_mem: + of_reserved_mem_device_release(dev); + clk_unprepare(video->vclk); +@@ -1662,7 +1716,6 @@ static int aspeed_video_init(struct aspeed_video *video) + static int aspeed_video_probe(struct platform_device *pdev) + { + int rc; +- struct resource *res; + struct aspeed_video *video = + devm_kzalloc(&pdev->dev, sizeof(*video), GFP_KERNEL); + +@@ -1677,10 +1730,7 @@ static int aspeed_video_probe(struct platform_device *pdev) + INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work); + INIT_LIST_HEAD(&video->buffers); + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- +- video->base = devm_ioremap_resource(video->dev, res); +- ++ video->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(video->base)) + return PTR_ERR(video->base); + +@@ -1689,8 +1739,12 @@ static int aspeed_video_probe(struct platform_device *pdev) + return rc; + + rc = aspeed_video_setup_video(video); +- if (rc) ++ if (rc) { ++ of_reserved_mem_device_release(video->dev); ++ clk_unprepare(video->vclk); ++ clk_unprepare(video->eclk); + return rc; ++ } + + return 0; + } +@@ -1714,8 +1768,11 @@ static int aspeed_video_remove(struct platform_device *pdev) + + v4l2_device_unregister(v4l2_dev); + +- dma_free_coherent(video->dev, VE_JPEG_HEADER_SIZE, video->jpeg.virt, +- video->jpeg.dma); ++ aspeed_video_free_buf(video, &video->comp); ++ aspeed_video_free_buf(video, &video->bcd); ++ aspeed_video_free_buf(video, &video->jpeg_hdr); ++ aspeed_video_free_buf(video, &video->srcs[0]); ++ aspeed_video_free_buf(video, &video->srcs[1]); + + of_reserved_mem_device_release(dev); + +-- +2.17.1 + |