From e8bf4a1bdaeadb28d13b9a2bcfd5910fda06eede Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 8 Apr 2025 11:17:05 +0200 Subject: [PATCH 01/16] drm/sysfb: efidrm: Support module builds Make CONFIG_DRM_EFIDRM a tristate to enable module builds. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20250408091837.407401-3-tzimmermann@suse.de --- drivers/gpu/drm/sysfb/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/sysfb/Kconfig b/drivers/gpu/drm/sysfb/Kconfig index 5ac71d5ff8ed..9c9884c7efc6 100644 --- a/drivers/gpu/drm/sysfb/Kconfig +++ b/drivers/gpu/drm/sysfb/Kconfig @@ -8,8 +8,8 @@ config DRM_SYSFB_HELPER depends on DRM config DRM_EFIDRM - bool "EFI framebuffer driver" - depends on (DRM=y) && MMU && EFI && (!SYSFB_SIMPLEFB || COMPILE_TEST) + tristate "EFI framebuffer driver" + depends on DRM && MMU && EFI && (!SYSFB_SIMPLEFB || COMPILE_TEST) select APERTURE_HELPERS select DRM_CLIENT_SELECTION select DRM_GEM_SHMEM_HELPER -- 2.51.0 From bcdc354a0a545e0e78c6f068e5a11c0285e06eeb Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 7 Feb 2025 19:22:46 +0100 Subject: [PATCH 02/16] drm/rockchip: vop: remove redundant condition check Instead of checking the same thing twice in a row, fold the second condition into the first clause. Signed-off-by: Lucas Stach Reviewed-by: Andy Yan Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250207182247.215537-1-l.stach@pengutronix.de --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index e3596e2b557d..ba6b0528d1e5 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -733,11 +733,10 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, WARN_ON(vop->event); - if (crtc->state->self_refresh_active) + if (crtc->state->self_refresh_active) { rockchip_drm_set_win_enabled(crtc, false); - - if (crtc->state->self_refresh_active) goto out; + } mutex_lock(&vop->vop_lock); -- 2.51.0 From c5996e4ab109c8bb5541453b20647eaaf9350f41 Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Tue, 18 Mar 2025 14:20:17 +0800 Subject: [PATCH 03/16] drm/rockchip: vop2: Make overlay layer select register configuration take effect by vsync Because the layer/window enable/disable is take effect by vsync, if the overlay configuration of these layers does not follow vsync and takes effect immediately instead, when multiple layers are dynamically enable/disable, inconsistent display contents may be seen on the screen. Signed-off-by: Andy Yan Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250318062024.4555-1-andyshrk@163.com --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.h | 1 + drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h index 680bedbb770e..fc3ecb9fcd95 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.h @@ -710,6 +710,7 @@ enum dst_factor_mode { #define VOP2_COLOR_KEY_MASK BIT(31) +#define RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL GENMASK(31, 30) #define RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD BIT(28) #define RK3568_OVL_CTRL__YUV_MODE(vp) BIT(vp) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 14958d6b3d2e..c5bcf8e2f30e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -2070,7 +2070,10 @@ static void rk3568_vop2_setup_layer_mixer(struct vop2_video_port *vp) struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state); ovl_ctrl = vop2_readl(vop2, RK3568_OVL_CTRL); - ovl_ctrl |= RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD; + ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_IMD; + ovl_ctrl &= ~RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL; + ovl_ctrl |= FIELD_PREP(RK3568_OVL_CTRL__LAYERSEL_REGDONE_SEL, vp->id); + if (vcstate->yuv_overlay) ovl_ctrl |= RK3568_OVL_CTRL__YUV_MODE(vp->id); else -- 2.51.0 From 64e6121dc1b18a8208faf5b26efb50206722fd8e Mon Sep 17 00:00:00 2001 From: "Rob Herring (Arm)" Date: Fri, 4 Apr 2025 16:40:29 -0500 Subject: [PATCH 04/16] dt-bindings: display: rockchip,vop: Drop assigned-clocks assigned-clock properties are implicitly allowed in any node with 'clocks' and don't have to be specified. The max here also appears to be wrong as there's a case with 4 entries. Signed-off-by: "Rob Herring (Arm)" Reviewed-by: Krzysztof Kozlowski Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250404214030.401629-1-robh@kernel.org --- .../devicetree/bindings/display/rockchip/rockchip-vop.yaml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml index b339b7e708c6..8b5f58103dda 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip-vop.yaml @@ -73,12 +73,6 @@ properties: port: $ref: /schemas/graph.yaml#/properties/port - assigned-clocks: - maxItems: 2 - - assigned-clock-rates: - maxItems: 2 - iommus: maxItems: 1 -- 2.51.0 From d74cc229cfbbc5a96139825c297f34accd670bce Mon Sep 17 00:00:00 2001 From: Konstantin Shabanov Date: Thu, 3 Apr 2025 06:47:39 +0000 Subject: [PATCH 05/16] drm/rockchip: vop: Consistently use rk3399 registers consts As rk3399 has its own registers definitions, update related structs to use them. There are no changes in behaviour as updated constants values are the for rk3288/rk3368/rk3399 chips. Signed-off-by: Konstantin Shabanov Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250403064740.4016-1-mail@etehtsea.me --- drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 94 ++++++++++----------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index 4e2099d86517..d1f788763318 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -906,21 +906,21 @@ static const struct vop_data rk3366_vop = { static const struct vop_output rk3399_output = { .dp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19), - .rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19), - .hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23), - .edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27), - .mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31), + .rgb_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19), + .hdmi_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 23), + .edp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 27), + .mipi_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 31), .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16), - .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16), - .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20), - .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24), - .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28), + .rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16), + .hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 20), + .edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 24), + .mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 28), .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11), - .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12), - .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13), - .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14), - .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15), - .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3), + .rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12), + .hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13), + .edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14), + .mipi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 15), + .mipi_dual_channel_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 3), }; static const struct vop_common rk3399_common = { @@ -975,23 +975,23 @@ static const struct vop_win_phy rk3399_win0_data = { .data_formats = formats_win_full_10, .nformats = ARRAY_SIZE(formats_win_full_10), .format_modifiers = format_modifiers_win_full_afbc, - .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), - .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), - .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), - .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), - .uv_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 15), - .x_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 21), - .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22), - .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), - .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), - .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), - .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), - .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), - .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), - .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), - .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), - .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), - .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), + .enable = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3399_WIN0_CTRL0, 0x7, 1), + .fmt_10 = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 12), + .uv_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 15), + .x_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3399_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3399_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3399_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3399_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3399_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 0), + .uv_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 16), + .src_alpha_ctl = VOP_REG(RK3399_WIN0_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3399_WIN0_DST_ALPHA_CTRL, 0xff, 0), + .channel = VOP_REG(RK3399_WIN0_CTRL2, 0xff, 0), }; static const struct vop_win_phy rk3399_win1_data = { @@ -999,23 +999,23 @@ static const struct vop_win_phy rk3399_win1_data = { .data_formats = formats_win_full_10, .nformats = ARRAY_SIZE(formats_win_full_10), .format_modifiers = format_modifiers_win_full, - .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0), - .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1), - .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 4), - .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12), - .uv_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 15), - .x_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 21), - .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22), - .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0), - .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0), - .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0), - .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0), - .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0), - .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0), - .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16), - .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0), - .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0), - .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0), + .enable = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 0), + .format = VOP_REG(RK3399_WIN0_CTRL0, 0x7, 1), + .fmt_10 = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 4), + .rb_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 12), + .uv_swap = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 15), + .x_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 21), + .y_mir_en = VOP_REG(RK3399_WIN0_CTRL0, 0x1, 22), + .act_info = VOP_REG(RK3399_WIN0_ACT_INFO, 0x1fff1fff, 0), + .dsp_info = VOP_REG(RK3399_WIN0_DSP_INFO, 0x0fff0fff, 0), + .dsp_st = VOP_REG(RK3399_WIN0_DSP_ST, 0x1fff1fff, 0), + .yrgb_mst = VOP_REG(RK3399_WIN0_YRGB_MST, 0xffffffff, 0), + .uv_mst = VOP_REG(RK3399_WIN0_CBR_MST, 0xffffffff, 0), + .yrgb_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 0), + .uv_vir = VOP_REG(RK3399_WIN0_VIR, 0x3fff, 16), + .src_alpha_ctl = VOP_REG(RK3399_WIN0_SRC_ALPHA_CTRL, 0xff, 0), + .dst_alpha_ctl = VOP_REG(RK3399_WIN0_DST_ALPHA_CTRL, 0xff, 0), + .channel = VOP_REG(RK3399_WIN0_CTRL2, 0xff, 0), }; /* -- 2.51.0 From 8702048bb8313a21ec9179e9ce7ad3c5cb2ef072 Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Mon, 7 Apr 2025 15:42:25 +0200 Subject: [PATCH 06/16] mm/kmap: Add kmap_local_page_try_from_panic() kmap_local_page() can be unsafe to call from a panic handler, if CONFIG_HIGHMEM is set, and the page is in the highmem zone. So add kmap_local_page_try_from_panic() to handle this case. Suggested-by: Simona Vetter Reviewed-by: Thomas Gleixner Signed-off-by: Jocelyn Falempe Link: https://lore.kernel.org/r/20250407140138.162383-2-jfalempe@redhat.com --- include/linux/highmem-internal.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/linux/highmem-internal.h b/include/linux/highmem-internal.h index dd100e849f5e..9a7683d79a4b 100644 --- a/include/linux/highmem-internal.h +++ b/include/linux/highmem-internal.h @@ -73,6 +73,14 @@ static inline void *kmap_local_page(struct page *page) return __kmap_local_page_prot(page, kmap_prot); } +static inline void *kmap_local_page_try_from_panic(struct page *page) +{ + if (!PageHighMem(page)) + return page_address(page); + /* If the page is in HighMem, it's not safe to kmap it.*/ + return NULL; +} + static inline void *kmap_local_folio(struct folio *folio, size_t offset) { struct page *page = folio_page(folio, offset / PAGE_SIZE); @@ -180,6 +188,11 @@ static inline void *kmap_local_page(struct page *page) return page_address(page); } +static inline void *kmap_local_page_try_from_panic(struct page *page) +{ + return page_address(page); +} + static inline void *kmap_local_folio(struct folio *folio, size_t offset) { return page_address(&folio->page) + offset; -- 2.51.0 From c9ff2808790f0fd4ca16f30f63abe70914a5a292 Mon Sep 17 00:00:00 2001 From: Jocelyn Falempe Date: Mon, 7 Apr 2025 15:42:26 +0200 Subject: [PATCH 07/16] drm/panic: Add support to scanout buffer as array of pages Some drivers like virtio-gpu, don't map the scanout buffer in the kernel. Calling vmap() in a panic handler is not safe, and writing an atomic_vmap() API is more complex than expected [1]. So instead, pass the array of pages of the scanout buffer to the panic handler, and map only one page at a time to draw the pixels. This is obviously slow, but acceptable for a panic handler. [1] https://lore.kernel.org/dri-devel/20250305152555.318159-1-ryasuoka@redhat.com/ Acked-by: Thomas Zimmermann Acked-by: Simona Vetter Signed-off-by: Jocelyn Falempe Link: https://lore.kernel.org/r/20250407140138.162383-3-jfalempe@redhat.com --- drivers/gpu/drm/drm_panic.c | 142 ++++++++++++++++++++++++++++++++++-- include/drm/drm_panic.h | 12 ++- 2 files changed, 147 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_panic.c b/drivers/gpu/drm/drm_panic.c index b47ea25fdfaa..b4de79583805 100644 --- a/drivers/gpu/drm/drm_panic.c +++ b/drivers/gpu/drm/drm_panic.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -154,6 +155,90 @@ static void drm_panic_blit_pixel(struct drm_scanout_buffer *sb, struct drm_rect sb->set_pixel(sb, clip->x1 + x, clip->y1 + y, fg_color); } +static void drm_panic_write_pixel16(void *vaddr, unsigned int offset, u16 color) +{ + u16 *p = vaddr + offset; + + *p = color; +} + +static void drm_panic_write_pixel24(void *vaddr, unsigned int offset, u32 color) +{ + u8 *p = vaddr + offset; + + *p++ = color & 0xff; + color >>= 8; + *p++ = color & 0xff; + color >>= 8; + *p = color & 0xff; +} + +static void drm_panic_write_pixel32(void *vaddr, unsigned int offset, u32 color) +{ + u32 *p = vaddr + offset; + + *p = color; +} + +static void drm_panic_write_pixel(void *vaddr, unsigned int offset, u32 color, unsigned int cpp) +{ + switch (cpp) { + case 2: + drm_panic_write_pixel16(vaddr, offset, color); + break; + case 3: + drm_panic_write_pixel24(vaddr, offset, color); + break; + case 4: + drm_panic_write_pixel32(vaddr, offset, color); + break; + default: + pr_debug_once("Can't blit with pixel width %d\n", cpp); + } +} + +/* + * The scanout buffer pages are not mapped, so for each pixel, + * use kmap_local_page_try_from_panic() to map the page, and write the pixel. + * Try to keep the map from the previous pixel, to avoid too much map/unmap. + */ +static void drm_panic_blit_page(struct page **pages, unsigned int dpitch, + unsigned int cpp, const u8 *sbuf8, + unsigned int spitch, struct drm_rect *clip, + unsigned int scale, u32 fg32) +{ + unsigned int y, x; + unsigned int page = ~0; + unsigned int height = drm_rect_height(clip); + unsigned int width = drm_rect_width(clip); + void *vaddr = NULL; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + if (drm_draw_is_pixel_fg(sbuf8, spitch, x / scale, y / scale)) { + unsigned int new_page; + unsigned int offset; + + offset = (y + clip->y1) * dpitch + (x + clip->x1) * cpp; + new_page = offset >> PAGE_SHIFT; + offset = offset % PAGE_SIZE; + if (new_page != page) { + if (!pages[new_page]) + continue; + if (vaddr) + kunmap_local(vaddr); + page = new_page; + vaddr = kmap_local_page_try_from_panic(pages[page]); + } + if (vaddr) + drm_panic_write_pixel(vaddr, offset, fg32, cpp); + } + } + } + if (vaddr) + kunmap_local(vaddr); +} + /* * drm_panic_blit - convert a monochrome image to a linear framebuffer * @sb: destination scanout buffer @@ -177,6 +262,10 @@ static void drm_panic_blit(struct drm_scanout_buffer *sb, struct drm_rect *clip, if (sb->set_pixel) return drm_panic_blit_pixel(sb, clip, sbuf8, spitch, scale, fg_color); + if (sb->pages) + return drm_panic_blit_page(sb->pages, sb->pitch[0], sb->format->cpp[0], + sbuf8, spitch, clip, scale, fg_color); + map = sb->map[0]; iosys_map_incr(&map, clip->y1 * sb->pitch[0] + clip->x1 * sb->format->cpp[0]); @@ -209,6 +298,35 @@ static void drm_panic_fill_pixel(struct drm_scanout_buffer *sb, sb->set_pixel(sb, clip->x1 + x, clip->y1 + y, color); } +static void drm_panic_fill_page(struct page **pages, unsigned int dpitch, + unsigned int cpp, struct drm_rect *clip, + u32 color) +{ + unsigned int y, x; + unsigned int page = ~0; + void *vaddr = NULL; + + for (y = clip->y1; y < clip->y2; y++) { + for (x = clip->x1; x < clip->x2; x++) { + unsigned int new_page; + unsigned int offset; + + offset = y * dpitch + x * cpp; + new_page = offset >> PAGE_SHIFT; + offset = offset % PAGE_SIZE; + if (new_page != page) { + if (vaddr) + kunmap_local(vaddr); + page = new_page; + vaddr = kmap_local_page_try_from_panic(pages[page]); + } + drm_panic_write_pixel(vaddr, offset, color, cpp); + } + } + if (vaddr) + kunmap_local(vaddr); +} + /* * drm_panic_fill - Fill a rectangle with a color * @sb: destination scanout buffer @@ -225,6 +343,10 @@ static void drm_panic_fill(struct drm_scanout_buffer *sb, struct drm_rect *clip, if (sb->set_pixel) return drm_panic_fill_pixel(sb, clip, color); + if (sb->pages) + return drm_panic_fill_page(sb->pages, sb->pitch[0], sb->format->cpp[0], + clip, color); + map = sb->map[0]; iosys_map_incr(&map, clip->y1 * sb->pitch[0] + clip->x1 * sb->format->cpp[0]); @@ -709,16 +831,24 @@ static void draw_panic_plane(struct drm_plane *plane, const char *description) if (!drm_panic_trylock(plane->dev, flags)) return; + ret = plane->helper_private->get_scanout_buffer(plane, &sb); + + if (ret || !drm_panic_is_format_supported(sb.format)) + goto unlock; + + /* One of these should be set, or it can't draw pixels */ + if (!sb.set_pixel && !sb.pages && iosys_map_is_null(&sb.map[0])) + goto unlock; + drm_panic_set_description(description); - ret = plane->helper_private->get_scanout_buffer(plane, &sb); + draw_panic_dispatch(&sb); + if (plane->helper_private->panic_flush) + plane->helper_private->panic_flush(plane); - if (!ret && drm_panic_is_format_supported(sb.format)) { - draw_panic_dispatch(&sb); - if (plane->helper_private->panic_flush) - plane->helper_private->panic_flush(plane); - } drm_panic_clear_description(); + +unlock: drm_panic_unlock(plane->dev, flags); } diff --git a/include/drm/drm_panic.h b/include/drm/drm_panic.h index ff78d00c3da5..310c88c4d336 100644 --- a/include/drm/drm_panic.h +++ b/include/drm/drm_panic.h @@ -39,6 +39,16 @@ struct drm_scanout_buffer { */ struct iosys_map map[DRM_FORMAT_MAX_PLANES]; + /** + * @pages: Optional, if the scanout buffer is not mapped, set this field + * to the array of pages of the scanout buffer. The panic code will use + * kmap_local_page_try_from_panic() to map one page at a time to write + * all the pixels. This array shouldn't be allocated from the + * get_scanoutbuffer() callback. + * The scanout buffer should be in linear format. + */ + struct page **pages; + /** * @width: Width of the scanout buffer, in pixels. */ @@ -57,7 +67,7 @@ struct drm_scanout_buffer { /** * @set_pixel: Optional function, to set a pixel color on the * framebuffer. It allows to handle special tiling format inside the - * driver. + * driver. It takes precedence over the @map and @pages fields. */ void (*set_pixel)(struct drm_scanout_buffer *sb, unsigned int x, unsigned int y, u32 color); -- 2.51.0 From 0ac7ad5e352dcf18a4d42a4671f7cda69847712b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Thu, 10 Apr 2025 11:50:03 +0200 Subject: [PATCH 08/16] drm: Mark CONFIG_DRM_HEADER_TEST as BROKEN The flag got lost during a merge. Add it back. Signed-off-by: Thomas Zimmermann Reported-by: Simona Vetter Closes: https://people.freedesktop.org/~cbrill/dri-log/?channel=dri-devel&highlight_names=&date=2025-04-10&show_html=true Fixes: 1afba39f9305 ("Merge drm/drm-next into drm-misc-next") Acked-by: Simona Vetter Link: https://lore.kernel.org/r/20250410095014.20471-1-tzimmermann@suse.de --- drivers/gpu/drm/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/Kconfig.debug b/drivers/gpu/drm/Kconfig.debug index c493743e8aca..fa6ee76f4d3c 100644 --- a/drivers/gpu/drm/Kconfig.debug +++ b/drivers/gpu/drm/Kconfig.debug @@ -27,7 +27,7 @@ config DRM_WERROR config DRM_HEADER_TEST bool "Ensure DRM headers are self-contained and pass kernel-doc" - depends on DRM && EXPERT + depends on DRM && EXPERT && BROKEN default n help Ensure the DRM subsystem headers both under drivers/gpu/drm and -- 2.51.0 From d1df2907fb69df56aad8e4a0734dac0778c234a7 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 4 Apr 2025 10:09:29 +0200 Subject: [PATCH 09/16] drm/panthor: Fix GPU_COHERENCY_ACE[_LITE] definitions GPU_COHERENCY_ACE and GPU_COHERENCY_ACE_LITE definitions have been swapped. Changes in v2: - New patch Changes in v3: - Add Steve's R-b Reported-by: Liviu Dudau Fixes: 546b366600ef ("drm/panthor: Add GPU register definitions") Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Link: https://lore.kernel.org/r/20250404080933.2912674-2-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_regs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_regs.h b/drivers/gpu/drm/panthor/panthor_regs.h index b7b3b3add166..a7a323dc5cf9 100644 --- a/drivers/gpu/drm/panthor/panthor_regs.h +++ b/drivers/gpu/drm/panthor/panthor_regs.h @@ -133,8 +133,8 @@ #define GPU_COHERENCY_PROT_BIT(name) BIT(GPU_COHERENCY_ ## name) #define GPU_COHERENCY_PROTOCOL 0x304 -#define GPU_COHERENCY_ACE 0 -#define GPU_COHERENCY_ACE_LITE 1 +#define GPU_COHERENCY_ACE_LITE 0 +#define GPU_COHERENCY_ACE 1 #define GPU_COHERENCY_NONE 31 #define MCU_CONTROL 0x700 -- 2.51.0 From 7d5a3b22f5b58ef89ab8770d7a44c24eecde8d66 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 4 Apr 2025 10:09:30 +0200 Subject: [PATCH 10/16] drm/panthor: Call panthor_gpu_coherency_init() after PM resume() When the device is coherent, panthor_gpu_coherency_init() will read GPU_COHERENCY_FEATURES to make sure the GPU supports the ACE-Lite coherency protocol, which will fail if the clocks/power-domains are not enabled when the read is done. Move the panthor_gpu_coherency_init() call after the device has been resumed to prevent that. Changes in v2: - Add Liviu's R-b Changes in v3: - Add Steve's R-b Fixes: dd7db8d911a1 ("drm/panthor: Explicitly set the coherency mode") Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://lore.kernel.org/r/20250404080933.2912674-3-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_device.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index a9da1d1eeb70..c73c1608d6e6 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -171,10 +171,6 @@ int panthor_device_init(struct panthor_device *ptdev) struct page *p; int ret; - ret = panthor_gpu_coherency_init(ptdev); - if (ret) - return ret; - init_completion(&ptdev->unplug.done); ret = drmm_mutex_init(&ptdev->base, &ptdev->unplug.lock); if (ret) @@ -247,6 +243,10 @@ int panthor_device_init(struct panthor_device *ptdev) if (ret) goto err_rpm_put; + ret = panthor_gpu_coherency_init(ptdev); + if (ret) + return ret; + ret = panthor_mmu_init(ptdev); if (ret) goto err_unplug_gpu; -- 2.51.0 From 8ba64cf2f358079d09faba7529aad2b0a46c7903 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 4 Apr 2025 10:09:31 +0200 Subject: [PATCH 11/16] drm/panthor: Update panthor_mmu::irq::mask when needed When we clear the faulty bits in the AS mask, we also need to update the panthor_mmu::irq::mask field otherwise our IRQ handler won't get called again until the GPU is reset. Changes in v2: - Add Liviu's R-b Changes in v3: - Add Steve's R-b Fixes: 647810ec2476 ("drm/panthor: Add the MMU/VM logical block") Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://lore.kernel.org/r/20250404080933.2912674-4-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index 12a02e28f50f..7cca97d298ea 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -781,6 +781,7 @@ out_enable_as: if (ptdev->mmu->as.faulty_mask & panthor_mmu_as_fault_mask(ptdev, as)) { gpu_write(ptdev, MMU_INT_CLEAR, panthor_mmu_as_fault_mask(ptdev, as)); ptdev->mmu->as.faulty_mask &= ~panthor_mmu_as_fault_mask(ptdev, as); + ptdev->mmu->irq.mask |= panthor_mmu_as_fault_mask(ptdev, as); gpu_write(ptdev, MMU_INT_MASK, ~ptdev->mmu->as.faulty_mask); } -- 2.51.0 From 50b0639b575c0725a190926d17222193bdf027c9 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 4 Apr 2025 10:09:32 +0200 Subject: [PATCH 12/16] drm/panthor: Let IRQ handlers clear the interrupts themselves MMU handler needs to be in control of the job interrupt clears because clearing the interrupt also unblocks the writer/reader that triggered the fault, and we don't want it to be unblocked until we've had a chance to process the IRQ. Since clearing the clearing is just one line, let's make it explicit instead of doing it in the generic code path. Note that this commit changes the existing behavior in that the MMU COMPLETED irqs are no longer cleared, which is fine because they are masked, so we're not risking an interrupt flood. Changes in v3: - Mention the fact we no longer clear MMU COMPLETED irqs - Add Liviu's R-b Changes in v2: - Move the MMU_INT_CLEAR around Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://lore.kernel.org/r/20250404080933.2912674-5-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_device.h | 2 -- drivers/gpu/drm/panthor/panthor_fw.c | 2 ++ drivers/gpu/drm/panthor/panthor_gpu.c | 2 ++ drivers/gpu/drm/panthor/panthor_mmu.c | 7 +++++++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h index da6574021664..4c27b6d85f46 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -383,8 +383,6 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da if (!status) \ break; \ \ - gpu_write(ptdev, __reg_prefix ## _INT_CLEAR, status); \ - \ __handler(ptdev, status); \ ret = IRQ_HANDLED; \ } \ diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index 0f52766a3120..446bb377b953 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -1008,6 +1008,8 @@ static void panthor_fw_init_global_iface(struct panthor_device *ptdev) static void panthor_job_irq_handler(struct panthor_device *ptdev, u32 status) { + gpu_write(ptdev, JOB_INT_CLEAR, status); + if (!ptdev->fw->booted && (status & JOB_INT_GLOBAL_IF)) ptdev->fw->booted = true; diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c index 671049020afa..32d678a0114e 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.c +++ b/drivers/gpu/drm/panthor/panthor_gpu.c @@ -150,6 +150,8 @@ static void panthor_gpu_init_info(struct panthor_device *ptdev) static void panthor_gpu_irq_handler(struct panthor_device *ptdev, u32 status) { + gpu_write(ptdev, GPU_INT_CLEAR, status); + if (status & GPU_IRQ_FAULT) { u32 fault_status = gpu_read(ptdev, GPU_FAULT_STATUS); u64 address = ((u64)gpu_read(ptdev, GPU_FAULT_ADDR_HI) << 32) | diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index 7cca97d298ea..0ba76982d45b 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1710,6 +1710,13 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) access_type, access_type_name(ptdev, fault_status), source_id); + /* We don't handle VM faults at the moment, so let's just clear the + * interrupt and let the writer/reader crash. + * Note that COMPLETED irqs are never cleared, but this is fine + * because they are always masked. + */ + gpu_write(ptdev, MMU_INT_CLEAR, mask); + /* Ignore MMU interrupts on this AS until it's been * re-enabled. */ -- 2.51.0 From 6c4a3fa26799785c1873aacabcfd9b2d27e8dc97 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 4 Apr 2025 10:09:33 +0200 Subject: [PATCH 13/16] drm/panthor: Don't update MMU_INT_MASK in panthor_mmu_irq_handler() Interrupts are automatically unmasked in panthor_mmu_irq_threaded_handler() when the handler returns. Unmasking prematurely might generate spurious interrupts if the IRQ line is shared. Changes in v2: - New patch Changes in v3: - Add R-bs Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://lore.kernel.org/r/20250404080933.2912674-6-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_mmu.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index 0ba76982d45b..dc173c6edde0 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -1721,7 +1721,6 @@ static void panthor_mmu_irq_handler(struct panthor_device *ptdev, u32 status) * re-enabled. */ ptdev->mmu->irq.mask = new_int_mask; - gpu_write(ptdev, MMU_INT_MASK, new_int_mask); if (ptdev->mmu->as.slots[as].vm) ptdev->mmu->as.slots[as].vm->unhandled_fault = true; -- 2.51.0 From dca4ee84a8bb6ec7cb2a1463f14983c2e0d614a7 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 8 Apr 2025 13:31:26 +0200 Subject: [PATCH 14/16] accel/ivpu: Test for imported buffers with drm_gem_is_imported() Instead of testing import_attach for imported GEM buffers, invoke drm_gem_is_imported() to do the test. The helper tests the dma_buf itself while import_attach is just an artifact of the import. Prepares to make import_attach optional. Signed-off-by: Thomas Zimmermann Reviewed-by: Jacek Lawrynowicz Signed-off-by: Jacek Lawrynowicz Link: https://lore.kernel.org/r/20250408113247.418007-1-tzimmermann@suse.de --- drivers/accel/ivpu/ivpu_gem.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_gem.c b/drivers/accel/ivpu/ivpu_gem.c index 212d21ad2bbd..e0d242d9f3e5 100644 --- a/drivers/accel/ivpu/ivpu_gem.c +++ b/drivers/accel/ivpu/ivpu_gem.c @@ -30,7 +30,7 @@ static inline void ivpu_dbg_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, con "%6s: bo %8p vpu_addr %9llx size %8zu ctx %d has_pages %d dma_mapped %d mmu_mapped %d wc %d imported %d\n", action, bo, bo->vpu_addr, ivpu_bo_size(bo), bo->ctx ? bo->ctx->id : 0, (bool)bo->base.pages, (bool)bo->base.sgt, bo->mmu_mapped, bo->base.map_wc, - (bool)bo->base.base.import_attach); + (bool)drm_gem_is_imported(&bo->base.base)); } /* @@ -122,7 +122,7 @@ static void ivpu_bo_unbind_locked(struct ivpu_bo *bo) bo->ctx = NULL; } - if (bo->base.base.import_attach) + if (drm_gem_is_imported(&bo->base.base)) return; dma_resv_lock(bo->base.base.resv, NULL); @@ -461,7 +461,7 @@ static void ivpu_bo_print_info(struct ivpu_bo *bo, struct drm_printer *p) if (bo->mmu_mapped) drm_printf(p, " mmu_mapped"); - if (bo->base.base.import_attach) + if (drm_gem_is_imported(&bo->base.base)) drm_printf(p, " imported"); drm_printf(p, "\n"); -- 2.51.0 From b82f66c76b8e3d9cabc06a68c8e0401e3f96fecf Mon Sep 17 00:00:00 2001 From: Antonin Godard Date: Tue, 18 Mar 2025 08:58:28 +0100 Subject: [PATCH 15/16] dt-bindings: display: simple: Add NLT NL13676BC25-03F panel Add NLT NL13676BC25-03F 15.6" LCD-TFT LVDS panel compatible string. Signed-off-by: Antonin Godard Acked-by: Krzysztof Kozlowski Link: https://patchwork.freedesktop.org/patch/msgid/20250318-b4-add-nlt-nl13676bc25-03f-v1-1-67e0f8cf2e6f@bootlin.com Signed-off-by: Louis Chauvet --- .../devicetree/bindings/display/panel/panel-simple.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index b5c8eb4fa2d1..b71ad32270d4 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -226,6 +226,8 @@ properties: - netron-dy,e231732 # Newhaven Display International 480 x 272 TFT LCD panel - newhaven,nhd-4.3-480272ef-atxl + # NLT Technologies, Ltd. 15.6" WXGA (1366×768) LVDS TFT LCD panel + - nlt,nl13676bc25-03f # New Vision Display 7.0" 800 RGB x 480 TFT LCD panel - nvd,9128 # OKAYA Electric America, Inc. RS800480T-7X0GP 7" WVGA LCD panel -- 2.51.0 From c180b00366d99911f4573dca5ac97a8633f2e8f9 Mon Sep 17 00:00:00 2001 From: Antonin Godard Date: Tue, 18 Mar 2025 08:58:29 +0100 Subject: [PATCH 16/16] drm/panel: simple: Add NLT NL13676BC25-03F panel entry Add support for the NLT NL13676BC25-03F 15.6" LCD-TFT LVDS panel. Signed-off-by: Antonin Godard Reviewed-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20250318-b4-add-nlt-nl13676bc25-03f-v1-2-67e0f8cf2e6f@bootlin.com Signed-off-by: Louis Chauvet --- drivers/gpu/drm/panel/panel-simple.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index df718c4a86cb..02ab960e35e9 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -3526,6 +3526,30 @@ static const struct panel_desc newhaven_nhd_43_480272ef_atxl = { .connector_type = DRM_MODE_CONNECTOR_DPI, }; +static const struct drm_display_mode nlt_nl13676bc25_03f_mode = { + .clock = 75400, + .hdisplay = 1366, + .hsync_start = 1366 + 14, + .hsync_end = 1366 + 14 + 56, + .htotal = 1366 + 14 + 56 + 64, + .vdisplay = 768, + .vsync_start = 768 + 1, + .vsync_end = 768 + 1 + 3, + .vtotal = 768 + 1 + 3 + 22, +}; + +static const struct panel_desc nlt_nl13676bc25_03f = { + .modes = &nlt_nl13676bc25_03f_mode, + .num_modes = 1, + .bpc = 8, + .size = { + .width = 363, + .height = 215, + }, + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + .connector_type = DRM_MODE_CONNECTOR_LVDS, +}; + static const struct display_timing nlt_nl192108ac18_02d_timing = { .pixelclock = { 130000000, 148350000, 163000000 }, .hactive = { 1920, 1920, 1920 }, @@ -5145,6 +5169,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "newhaven,nhd-4.3-480272ef-atxl", .data = &newhaven_nhd_43_480272ef_atxl, + }, { + .compatible = "nlt,nl13676bc25-03f", + .data = &nlt_nl13676bc25_03f, }, { .compatible = "nlt,nl192108ac18-02d", .data = &nlt_nl192108ac18_02d, -- 2.51.0