From 52943b19e28a8fa42f4f5a55e05f5ee69da9a052 Mon Sep 17 00:00:00 2001 From: hrdl <31923882+hrdl-github@users.noreply.github.com> Date: Mon, 5 May 2025 21:30:00 +0200 Subject: [PATCH] rockchip_ebc: set all pixels to IDLE when changing waveforms and don't allow redraws when redraw_delay <= 0 Previously changing waveforms using redraw_delay=0 could cause pixels to be stuck in what was previously their WAITING state without shrinking clip_ongoing_or_waiting. The display would stay responsive, but the refresh thread would occupy the CPU, causing the kernel to warn about soft lockups. This change resets all pixels to IDLE when modifying the LUT. At this point all pixels are either IDLE or WAITING. Pixels that are intended to be redrawn would become WAITING in the same iteration. --- drivers/gpu/drm/rockchip/rockchip_ebc.c | 33 ++++++++++++------- drivers/gpu/drm/rockchip/rockchip_ebc.h | 1 + .../gpu/drm/rockchip/rockchip_ebc_blit_neon.c | 16 +++++++++ 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.c b/drivers/gpu/drm/rockchip/rockchip_ebc.c index 14ef79a37566..aa10d712bdef 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.c @@ -785,7 +785,7 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, bool skip_advance = false; time_start_advance = ktime_get(); - // All currently scheduled pixels have finished and we have a work item + // All currently scheduled pixels are IDLE or WAITING have finished and we have a work item if (drm_rect_width(&clip_ongoing) <= 0 && work_item) { // Refresh work item spin_lock(&ebc->work_item_lock); @@ -840,6 +840,12 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, if (work_item & ROCKCHIP_EBC_WORK_ITEM_CHANGE_LUT) { rockchip_ebc_change_lut(ebc); print_lut(ebc); + // Reset inner and outer to make sure + // pixels that were WAITING stay + // valid. For simplicity, set to IDLE. + kernel_neon_begin(); + rockchip_ebc_reset_inner_outer_neon(ebc); + kernel_neon_end(); } if (work_item & ROCKCHIP_EBC_WORK_ITEM_INIT) { clip_ongoing_or_waiting = ebc->screen_rect; @@ -912,23 +918,28 @@ static void rockchip_ebc_partial_refresh(struct rockchip_ebc *ebc, pr_debug("%s ebc->driver_mode=%d enabling_mode=%d", __func__, ebc->driver_mode, enabling_mode); if (drm_rect_width(&clip_ongoing_or_waiting) > 0 && !skip_advance) { + u8 force_hint = 0; + // Disable redraws of redraw_delay <= 0 + u8 force_hint_mask = ebc->redraw_delay > 0 ? 0 : ROCKCHIP_EBC_HINT_REDRAW; if (ebc->driver_mode == ROCKCHIP_EBC_DRIVER_MODE_FAST) { kernel_neon_begin(); rockchip_ebc_schedule_advance_fast_neon( - ebc, prelim_target, hints, - phase_buffer, &clip_ongoing, - &clip_ongoing_or_waiting, - early_cancellation_addition, 0, 0, 0, - !no_schedule_until_clip_empty && !work_item); + ebc, prelim_target, hints, phase_buffer, + &clip_ongoing, &clip_ongoing_or_waiting, + early_cancellation_addition, 0, + force_hint, force_hint_mask, + !no_schedule_until_clip_empty && + !work_item); kernel_neon_end(); } else if (ebc->driver_mode == ROCKCHIP_EBC_DRIVER_MODE_NORMAL) { kernel_neon_begin(); rockchip_ebc_schedule_advance_neon( - ebc, prelim_target, hints, - phase_buffer, &clip_ongoing, - &clip_ongoing_or_waiting, - early_cancellation_addition, 0, 0, 0, - !no_schedule_until_clip_empty && !work_item); + ebc, prelim_target, hints, phase_buffer, + &clip_ongoing, &clip_ongoing_or_waiting, + early_cancellation_addition, 0, + force_hint, force_hint_mask, + !no_schedule_until_clip_empty && + !work_item); kernel_neon_end(); } } diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc.h b/drivers/gpu/drm/rockchip/rockchip_ebc.h index 836a06afefa5..88d9d3975171 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc.h +++ b/drivers/gpu/drm/rockchip/rockchip_ebc.h @@ -243,6 +243,7 @@ void rockchip_ebc_blit_fb_r8_y4_hints_neon(const struct rockchip_ebc *ebc, const struct drm_framebuffer *fb, const struct drm_rect *src_clip); +void rockchip_ebc_reset_inner_outer_neon(const struct rockchip_ebc *ebc); #define DRM_RECT_EMPTY_EXTANDABLE DRM_RECT_INIT(100000, 100000, -100000, -100000); diff --git a/drivers/gpu/drm/rockchip/rockchip_ebc_blit_neon.c b/drivers/gpu/drm/rockchip/rockchip_ebc_blit_neon.c index d53624ee30df..76b1b6d7d1bf 100644 --- a/drivers/gpu/drm/rockchip/rockchip_ebc_blit_neon.c +++ b/drivers/gpu/drm/rockchip/rockchip_ebc_blit_neon.c @@ -1231,6 +1231,22 @@ void rockchip_ebc_blit_fb_r8_y4_hints_neon(const struct rockchip_ebc *ebc, } EXPORT_SYMBOL(rockchip_ebc_blit_fb_r8_y4_hints_neon); +void rockchip_ebc_reset_inner_outer_neon(const struct rockchip_ebc *ebc) +{ + u8 *packed_inner_outer_nextprev_line = ebc->packed_inner_outer_nextprev; + uint8x16_t q8_0x00 = vdupq_n_u8(0x00); + for (int i = 0; i < ebc->num_pixels; i += 16) { + uint8x16x3_t q8_inner_outer_nextprev = vld3q_u8(packed_inner_outer_nextprev_line); + uint8x16x3_t q8_inner_outer_nextprev_new = { + { q8_0x00, q8_0x00, q8_inner_outer_nextprev.val[2] } + }; + vst3q_u8(packed_inner_outer_nextprev_line, + q8_inner_outer_nextprev_new); + packed_inner_outer_nextprev_line += 48; + } +} +EXPORT_SYMBOL(rockchip_ebc_reset_inner_outer_neon); + MODULE_AUTHOR("hrdl "); MODULE_DESCRIPTION("Rockchip EBC NEON functions"); MODULE_LICENSE("GPL v2");