diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux')
6 files changed, 829 insertions, 4 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch index 088e1a02b..7a9a5626c 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0001-arm-dts-add-DTS-for-Intel-ast2500-platforms.patch @@ -1,4 +1,4 @@ -From 7ad89fd032d56cc20622d34cf9d0d09adacb2796 Mon Sep 17 00:00:00 2001 +From e82178e44348a8594bc4ae2c3c5473336033483f Mon Sep 17 00:00:00 2001 From: Yuan Li <yuan.li@linux.intel.com> Date: Tue, 19 Sep 2017 15:55:39 +0800 Subject: [PATCH] arm: dts: add DTS for Intel ast2500 platforms @@ -24,7 +24,7 @@ Signed-off-by: Arun P. Mohanan <arun.p.m@linux.intel.com> diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts new file mode 100644 -index 000000000000..7a09ca54f161 +index 000000000000..09198052fdd5 --- /dev/null +++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts @@ -0,0 +1,477 @@ @@ -56,9 +56,9 @@ index 000000000000..7a09ca54f161 + #size-cells = <1>; + ranges; + -+ vga_memory: framebuffer@7f000000 { ++ vga_memory: framebuffer@9f000000 { + no-map; -+ reg = <0x7f000000 0x01000000>; ++ reg = <0x9f000000 0x01000000>; + }; + + gfx_memory: framebuffer { 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 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0121-Add-a-WA-to-defer-flash-writes-on-PS_ALERT_N-asserti.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0121-Add-a-WA-to-defer-flash-writes-on-PS_ALERT_N-asserti.patch new file mode 100644 index 000000000..0c9bae00d --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0121-Add-a-WA-to-defer-flash-writes-on-PS_ALERT_N-asserti.patch @@ -0,0 +1,191 @@ +From 90035d4ef6ffb7893f629fa427db77c79e1e50e7 Mon Sep 17 00:00:00 2001 +From: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +Date: Sat, 24 Oct 2020 13:43:23 -0700 +Subject: [PATCH] Add a WA to defer flash writes on PS_ALERT_N assertion + +To prevent SPI flash corruption, this commit adds a WA which monitors +PS_ALERT_N signal for detecting AC loss and it defers flash writes +when the signal is asserted. Actually, the PS_ALERT_N is asserted +even when PSU is in an unhealthy state so it also adds 10 seconds +of timeout for the deferring that covers AC loss case effectively. +If PSU gets back to healthy state, flash writes will be continued +immediately. + +Note: This would be a customization for some specific platforms +and this is a WA to cover a defect of H/W design. Do not try +upstream it. + +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> +--- + .../arm/boot/dts/aspeed-bmc-intel-ast2500.dts | 7 ++- + .../arm/boot/dts/aspeed-bmc-intel-ast2600.dts | 4 ++ + drivers/mtd/spi-nor/aspeed-smc.c | 61 +++++++++++++++++++ + 3 files changed, 71 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts +index e4ac4e3696f5..74fd5c52d7e3 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2500.dts +@@ -3,6 +3,7 @@ + #include "aspeed-g5.dtsi" + #include <dt-bindings/gpio/aspeed-gpio.h> + #include <dt-bindings/i2c/i2c.h> ++#include <dt-bindings/interrupt-controller/irq.h> + + / { + model = "Intel AST2500 BMC"; +@@ -92,6 +93,10 @@ + }; + + &fmc { ++ /delete-property/ interrupts; ++ interrupts-extended = <&vic 19>, ++ <&gpio ASPEED_GPIO(AA, 1) IRQ_TYPE_EDGE_BOTH>; ++ ps-alert-gpio = <&gpio ASPEED_GPIO(AA, 1) GPIO_ACTIVE_HIGH>; + status = "okay"; + flash@0 { + status = "okay"; +@@ -185,7 +190,7 @@ + /*X0-X7*/ "","","","","","","","", + /*Y0-Y7*/ "SIO_S3","SIO_S5","","SIO_ONCONTROL","","","","", + /*Z0-Z7*/ "","SIO_POWER_GOOD","","","","","","", +- /*AA0-AA7*/ "P3VBAT_BRIDGE_EN","","","","PREQ_N","TCK_MUX_SEL","SMI","POST_COMPLETE", ++ /*AA0-AA7*/ "P3VBAT_BRIDGE_EN","IRQ_SML1_PMBUS_BMC_ALERT_N","","","PREQ_N","TCK_MUX_SEL","SMI","POST_COMPLETE", + /*AB0-AB7*/ "","NMI_BUTTON","ID_BUTTON","PS_PWROK","","","","", + /*AC0-AC7*/ "","","","","","","",""; + }; +diff --git a/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts +index e9cea7b63836..0ff929a68dd4 100644 +--- a/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts ++++ b/arch/arm/boot/dts/aspeed-bmc-intel-ast2600.dts +@@ -85,6 +85,10 @@ + }; + + &fmc { ++ /delete-property/ interrupts; ++ interrupts-extended = <&gic GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>, ++ <&gpio0 ASPEED_GPIO(Y, 3) IRQ_TYPE_EDGE_BOTH>; ++ ps-alert-gpio = <&gpio0 ASPEED_GPIO(Y, 3) GPIO_ACTIVE_HIGH>; + status = "okay"; + flash@0 { + status = "okay"; +diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c +index 6e2f3802d162..397c2998e620 100644 +--- a/drivers/mtd/spi-nor/aspeed-smc.c ++++ b/drivers/mtd/spi-nor/aspeed-smc.c +@@ -9,12 +9,14 @@ + #include <linux/clk.h> + #include <linux/device.h> + #include <linux/io.h> ++#include <linux/gpio.h> + #include <linux/module.h> + #include <linux/mutex.h> + #include <linux/mtd/mtd.h> + #include <linux/mtd/partitions.h> + #include <linux/mtd/spi-nor.h> + #include <linux/of.h> ++#include <linux/of_gpio.h> + #include <linux/of_platform.h> + #include <linux/sizes.h> + #include <linux/slab.h> +@@ -216,10 +218,16 @@ struct aspeed_smc_controller { + u32 ahb_window_size; /* full mapping window size */ + + unsigned long clk_frequency; ++ unsigned int ps_alert_gpio; + + struct aspeed_smc_chip *chips[0]; /* pointers to attached chips */ + }; + ++static unsigned long aspeed_smc_flags = 0; ++#define FLAG_DEFER_WRITE 0 ++#define WRITE_DEFER_MSEC 100 /* 100ms */ ++#define WRITE_DEFER_MAX_COUNT 100 /* 100 x 100 = 10secs */ ++ + #define ASPEED_SPI_DEFAULT_FREQ 50000000 + + /* +@@ -411,6 +419,17 @@ static int aspeed_smc_write_to_ahb(void __iomem *dst, const void *buf, + size_t len) + { + size_t offset = 0; ++ int defer_cnt = 0; ++ ++ while (test_bit(FLAG_DEFER_WRITE, &aspeed_smc_flags)) { ++ pr_warn("%s deferring write, count: %d\n", DEVICE_NAME, ++ defer_cnt); ++ msleep(WRITE_DEFER_MSEC); ++ if (defer_cnt++ > WRITE_DEFER_MAX_COUNT) { ++ clear_bit(FLAG_DEFER_WRITE, &aspeed_smc_flags); ++ break; ++ } ++ } + + if (IS_ALIGNED((uintptr_t)dst, sizeof(uintptr_t)) && + IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) { +@@ -1363,6 +1382,21 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller, + return ret; + } + ++static irqreturn_t aspeed_smc_ps_alert_irq(int irq, void *arg) ++{ ++ struct aspeed_smc_controller *controller = arg; ++ ++ if (gpio_get_value(controller->ps_alert_gpio)) { ++ clear_bit(FLAG_DEFER_WRITE, &aspeed_smc_flags); ++ dev_warn(controller->dev, "clear FLAG_DEFER_WRITE\n"); ++ } else { ++ set_bit(FLAG_DEFER_WRITE, &aspeed_smc_flags); ++ dev_warn(controller->dev, "set FLAG_DEFER_WRITE\n"); ++ } ++ ++ return IRQ_HANDLED; ++} ++ + static int aspeed_smc_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +@@ -1373,6 +1407,7 @@ static int aspeed_smc_probe(struct platform_device *pdev) + struct clk *clk; + struct resource *res; + int ret; ++ int irq; + + match = of_match_device(aspeed_smc_matches, &pdev->dev); + if (!match || !match->data) +@@ -1409,6 +1444,32 @@ static int aspeed_smc_probe(struct platform_device *pdev) + controller->clk_frequency = clk_get_rate(clk); + devm_clk_put(&pdev->dev, clk); + ++ controller->ps_alert_gpio = of_get_named_gpio(np, "ps-alert-gpio", 0); ++ if (!gpio_is_valid(controller->ps_alert_gpio)) { ++ dev_err(dev, "No valid ps-alert-gpio\n"); ++ ret = controller->ps_alert_gpio; ++ return ret; ++ } ++ ++ ret = devm_gpio_request_one(dev, controller->ps_alert_gpio, ++ GPIOF_DIR_IN, "ps-alert-gpio"); ++ if (ret) { ++ dev_err(dev, "request gpio failed %d\n", ret); ++ return ret; ++ } ++ ++ irq = platform_get_irq(pdev, 1); ++ if (irq < 0) ++ return irq; ++ ++ ret = devm_request_irq(&pdev->dev, irq, aspeed_smc_ps_alert_irq, ++ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, ++ "ps-alert-irq", controller); ++ if (ret) { ++ dev_err(dev, "request irq failed %d\n", ret); ++ return ret; ++ } ++ + ret = aspeed_smc_setup_flash(controller, np, res); + if (ret) + dev_err(dev, "Aspeed SMC probe failed %d\n", ret); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0123-peci-fix-error-handling-in-peci_dev_ioctl.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0123-peci-fix-error-handling-in-peci_dev_ioctl.patch new file mode 100644 index 000000000..f82a08a1f --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0123-peci-fix-error-handling-in-peci_dev_ioctl.patch @@ -0,0 +1,43 @@ +From f0a37caf96a1583ed190abd7837f124dfadd5743 Mon Sep 17 00:00:00 2001 +From: Zev Weiss <zev@bewilderbeest.net> +Date: Sun, 27 Sep 2020 07:27:33 +1000 +Subject: [PATCH] peci: fix error-handling in peci_dev_ioctl() + +peci_get_xfer_msg() returns NULL on failure, not an ERR_PTR. Also +avoid calling kfree() on an ERR_PTR. + +Signed-off-by: Zev Weiss <zev@bewilderbeest.net> +Reviewed-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> +--- + drivers/peci/peci-dev.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/drivers/peci/peci-dev.c b/drivers/peci/peci-dev.c +index c574d13213af..8104468864bf 100644 +--- a/drivers/peci/peci-dev.c ++++ b/drivers/peci/peci-dev.c +@@ -122,8 +122,8 @@ static long peci_dev_ioctl(struct file *file, uint iocmd, ulong arg) + } + + xmsg = peci_get_xfer_msg(uxmsg.tx_len, uxmsg.rx_len); +- if (IS_ERR(xmsg)) { +- ret = PTR_ERR(xmsg); ++ if (!xmsg) { ++ ret = -ENOMEM; + break; + } + +@@ -172,7 +172,8 @@ static long peci_dev_ioctl(struct file *file, uint iocmd, ulong arg) + } + + peci_put_xfer_msg(xmsg); +- kfree(msg); ++ if (!IS_ERR(msg)) ++ kfree(msg); + + return (long)ret; + } +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/1001-Igore-0x3FF-in-aspeed_adc-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/1001-Igore-0x3FF-in-aspeed_adc-driver.patch new file mode 100644 index 000000000..5f74d6993 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/1001-Igore-0x3FF-in-aspeed_adc-driver.patch @@ -0,0 +1,75 @@ +From d1fb9431676f37ddf2a8673f84368793e5a88ab0 Mon Sep 17 00:00:00 2001 +From: Zhikui Ren <zhikui.ren@intel.com> +Date: Mon, 14 Sep 2020 12:02:03 -0700 +Subject: [PATCH] Igore 0x3FF in aspeed_adc driver + +ADC are 10 bits, 0x3FF means voltage exceeded reference voltage +Several ADC voltages reported rare transient events corresponding +to this value. Aspeed was consulted and did not identify possible +root causes. As a work around, igore these valuse and return +previous readings. If there were real issues, a slightly different +reading like 0x3FE will still be returned and resulted in a sensor +event. + +Signed-off-by: Zhikui Ren <zhikui.ren@intel.com> +--- + drivers/iio/adc/aspeed_adc.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c +index 1dd5a97a16bc..c115797c4cc5 100644 +--- a/drivers/iio/adc/aspeed_adc.c ++++ b/drivers/iio/adc/aspeed_adc.c +@@ -53,6 +53,9 @@ + #define ASPEED_ADC_INIT_POLLING_TIME 500 + #define ASPEED_ADC_INIT_TIMEOUT 500000 + ++#define ASPEED_ADC_CHANNELS_MAX 16 ++#define ASPEED_ADC_RAW_VALUE_MAX 0x3ff ++ + struct aspeed_adc_model_data { + const char *model_name; + unsigned int min_sampling_rate; // Hz +@@ -71,6 +74,7 @@ struct aspeed_adc_data { + struct clk_hw *clk_scaler; + struct reset_control *rst; + int cv; ++ int channel_raw_value[ASPEED_ADC_CHANNELS_MAX]; + }; + + #define ASPEED_CHAN(_idx, _data_reg_addr) { \ +@@ -124,6 +128,13 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev, + switch (mask) { + case IIO_CHAN_INFO_RAW: + *val = readw(data->base + chan->address); ++ if (*val == ASPEED_ADC_RAW_VALUE_MAX) { ++ *val = data->channel_raw_value[chan->channel]; ++ pr_err("aspeed_adc: channel %d drop invalid raw reading 0x3FF %d\n", ++ chan->channel, ASPEED_ADC_RAW_VALUE_MAX); ++ } else { ++ data->channel_raw_value[chan->channel] = *val; ++ } + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: +@@ -206,6 +217,7 @@ static int aspeed_adc_probe(struct platform_device *pdev) + int ret; + u32 eng_ctrl = 0; + u32 adc_engine_control_reg_val; ++ int i; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data)); + if (!indio_dev) +@@ -298,6 +310,9 @@ static int aspeed_adc_probe(struct platform_device *pdev) + + data->cv = 0x200 - (readl(data->base + 0x10) & GENMASK(9, 0)); + ++ for (i = 0; i < ASPEED_ADC_CHANNELS_MAX; i++) ++ data->channel_raw_value[i] = ASPEED_ADC_RAW_VALUE_MAX; ++ + writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL | + ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL); + printk(KERN_INFO "aspeed_adc: cv %d \n", data->cv); +-- +2.17.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend index 271b6035e..908dc0a8d 100644 --- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend +++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed_%.bbappend @@ -90,6 +90,10 @@ SRC_URI += " \ file://0117-Copy-raw-PECI-response-to-user-space-on-timeout.patch \ file://0118-Recalculate-AW-FCS-on-WrEndPointConfig-command.patch \ file://0119-Handle-pending-eSPI-HOST-OOB-RESET-VW-events.patch \ + file://0123-peci-fix-error-handling-in-peci_dev_ioctl.patch \ + file://1001-Igore-0x3FF-in-aspeed_adc-driver.patch \ + file://0120-media-aspeed-adjust-irq-enabling-timing-and-resource.patch \ + file://0121-Add-a-WA-to-defer-flash-writes-on-PS_ALERT_N-asserti.patch \ " # CVE-2020-16166 vulnerability fix |