From: Jammy Huang Date: Mon, 24 Nov 2025 03:05:14 +0000 (+0800) Subject: media: aspeed: Fix dram hang at res-change X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e83f8dd668eaf18f408169e1006f61dc5ebaa00e;p=thirdparty%2Fkernel%2Flinux.git media: aspeed: Fix dram hang at res-change Dram hang could happen in the steps below: 1. start capture/compression 2. out-of-lock watchdog raise irq because of res-change. 3. aspeed_video_irq_res_change do clk-off At step3, capture/compression could be not accomplished yet. If clk-off in the middle of video operation, dram controller could hang at ast2500. Use reset rather than clk-off/on to avoid this problem. Signed-off-by: Jammy Huang Signed-off-by: Hans Verkuil --- diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c index b83e43245277b..41cb96f601102 100644 --- a/drivers/media/platform/aspeed/aspeed-video.c +++ b/drivers/media/platform/aspeed/aspeed-video.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -310,6 +311,7 @@ struct aspeed_video { void __iomem *base; struct clk *eclk; struct clk *vclk; + struct reset_control *reset; struct device *dev; struct v4l2_ctrl_handler ctrl_handler; @@ -720,6 +722,13 @@ static void aspeed_video_on(struct aspeed_video *video) set_bit(VIDEO_CLOCKS_ON, &video->flags); } +static void aspeed_video_reset(struct aspeed_video *v) +{ + reset_control_assert(v->reset); + usleep_range(100, 150); + reset_control_deassert(v->reset); +} + static void aspeed_video_bufs_done(struct aspeed_video *video, enum vb2_buffer_state state) { @@ -742,7 +751,9 @@ static void aspeed_video_irq_res_change(struct aspeed_video *video, ulong delay) video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; - aspeed_video_off(video); + aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); + aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); + aspeed_video_reset(video); aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR); schedule_delayed_work(&video->res_work, delay); @@ -1984,8 +1995,7 @@ static void aspeed_video_stop_streaming(struct vb2_queue *q) * Need to force stop any DMA and try and get HW into a good * state for future calls to start streaming again. */ - aspeed_video_off(video); - aspeed_video_on(video); + aspeed_video_reset(video); aspeed_video_init_regs(video); @@ -2230,6 +2240,12 @@ static int aspeed_video_init(struct aspeed_video *video) } dev_info(video->dev, "irq %d\n", irq); + video->reset = devm_reset_control_get(dev, NULL); + if (IS_ERR(video->reset)) { + dev_err(dev, "Unable to get reset\n"); + return PTR_ERR(video->reset); + } + video->eclk = devm_clk_get(dev, "eclk"); if (IS_ERR(video->eclk)) { dev_err(dev, "Unable to get ECLK\n");