From 4aa8961b1b9c7498550b41168a91cf1558133dd3 Mon Sep 17 00:00:00 2001 From: Val Packett Date: Sun, 6 Jul 2025 17:42:24 -0300 Subject: [PATCH 01/32] drm/dp: drm_edp_backlight_set_level: do not always send 3-byte commands At least some panels using the LSB register are not happy with the unconditional increase of the command buffer to 3 bytes. With the BOE NE14QDM in my Dell Latitude 7455, the recent patches for luminance based brightness have introduced a regression: the brightness range stopped being contiguous and became nonsensical (it probably was interpreting the last 2 bytes of the buffer and not the first 2). Change from using a fixed sizeof() to a length variable that's only set to 3 when luminance is used. Let's leave the default as 2 even for the single-byte version, since that's how it worked before. Fixes: f2db78e37fe7 ("drm/dp: Modify drm_edp_backlight_set_level") Signed-off-by: Val Packett Tested-by: Abel Vesa Reviewed-by: Suraj Kandpal Link: https://lore.kernel.org/r/20250706204446.8918-1-val@packett.cool Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/display/drm_dp_helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index 1ecc3df7e316..4aaeae4fa03c 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -3962,6 +3962,7 @@ int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_bac int ret; unsigned int offset = DP_EDP_BACKLIGHT_BRIGHTNESS_MSB; u8 buf[3] = { 0 }; + size_t len = 2; /* The panel uses the PWM for controlling brightness levels */ if (!(bl->aux_set || bl->luminance_set)) @@ -3974,6 +3975,7 @@ int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_bac buf[1] = (level & 0x00ff00) >> 8; buf[2] = (level & 0xff0000) >> 16; offset = DP_EDP_PANEL_TARGET_LUMINANCE_VALUE; + len = 3; } else if (bl->lsb_reg_used) { buf[0] = (level & 0xff00) >> 8; buf[1] = (level & 0x00ff); @@ -3981,7 +3983,7 @@ int drm_edp_backlight_set_level(struct drm_dp_aux *aux, const struct drm_edp_bac buf[0] = level; } - ret = drm_dp_dpcd_write_data(aux, offset, buf, sizeof(buf)); + ret = drm_dp_dpcd_write_data(aux, offset, buf, len); if (ret < 0) { drm_err(aux->drm_dev, "%s: Failed to write aux backlight level: %d\n", From 96481012628c2d9a03fb758763ad7bff786203eb Mon Sep 17 00:00:00 2001 From: Raphael Gallais-Pou Date: Fri, 28 Mar 2025 12:41:48 +0100 Subject: [PATCH 02/32] drm: of: fix documentation reference Documentation/devicetree/bindings/graph.txt content has move directly to the dt-schema repo in commit 4b52be0ce6ad ("dt-bindings: Remove plain text OF graph binding"). Point to the YAML of the official repo instead of the old file. Signed-off-by: Raphael Gallais-Pou Reviewed-by: Maxime Ripard Link: https://lore.kernel.org/r/20250328114148.260322-1-rgallaispou@gmail.com Signed-off-by: Raphael Gallais-Pou --- drivers/gpu/drm/drm_of.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index d0183dea7703..4f65ce729a47 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -55,7 +55,8 @@ EXPORT_SYMBOL(drm_of_crtc_port_mask); * and generate the DRM mask of CRTCs which may be attached to this * encoder. * - * See Documentation/devicetree/bindings/graph.txt for the bindings. + * See https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/graph.yaml + * for the bindings. */ uint32_t drm_of_find_possible_crtcs(struct drm_device *dev, struct device_node *port) @@ -106,7 +107,9 @@ EXPORT_SYMBOL_GPL(drm_of_component_match_add); * Parse the platform device OF node and bind all the components associated * with the master. Interface ports are added before the encoders in order to * satisfy their .bind requirements - * See Documentation/devicetree/bindings/graph.txt for the bindings. + * + * See https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/graph.yaml + * for the bindings. * * Returns zero if successful, or one of the standard error codes if it fails. */ From 61ce50fd8196c8782b9620bb60d33649ec429f64 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 21 Aug 2025 15:30:54 +0300 Subject: [PATCH 03/32] drm/panel: jdi-lpm102a188a: Fix error code in jdi_panel_prepare() If the mipi_dsi_dual() macro fails, the error code is stored in dsi_ctx.accum_err. Propagate that error back to the caller instead of returning success as the current code does. Fixes: a6adf47d30cc ("drm/panel: jdi-lpm102a188a: Fix bug and clean up driver") Signed-off-by: Dan Carpenter Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/aKcRfq8xBrFmhqmO@stanley.mountain --- drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c index 83656bb4b0b2..23462065d726 100644 --- a/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c +++ b/drivers/gpu/drm/panel/panel-jdi-lpm102a188a.c @@ -233,8 +233,10 @@ static int jdi_panel_prepare(struct drm_panel *panel) mipi_dsi_dual(mipi_dsi_dcs_set_display_on_multi, &dsi_ctx, jdi->link1, jdi->link2); - if (dsi_ctx.accum_err < 0) + if (dsi_ctx.accum_err < 0) { + err = dsi_ctx.accum_err; goto poweroff; + } jdi->link1->mode_flags &= ~MIPI_DSI_MODE_LPM; jdi->link2->mode_flags &= ~MIPI_DSI_MODE_LPM; From 3f13bcc886fc034113cb75cb32b8d9db1216b846 Mon Sep 17 00:00:00 2001 From: Lizhi Hou Date: Wed, 20 Aug 2025 16:38:17 -0700 Subject: [PATCH 04/32] Documentation: accel: amdxdna: Update compiler information The compiler information is outdated. Update it to the latest. Reviewed-by: Maciej Falkowski Reviewed-by: Alex Deucher Signed-off-by: Lizhi Hou Link: https://lore.kernel.org/r/20250820233817.4050006-1-lizhi.hou@amd.com --- Documentation/accel/amdxdna/amdnpu.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/accel/amdxdna/amdnpu.rst b/Documentation/accel/amdxdna/amdnpu.rst index fbe0a7585345..42e54904f9a8 100644 --- a/Documentation/accel/amdxdna/amdnpu.rst +++ b/Documentation/accel/amdxdna/amdnpu.rst @@ -223,13 +223,13 @@ Userspace components Compiler -------- -Peano is an LLVM based open-source compiler for AMD XDNA Array compute tile -available at: +Peano is an LLVM based open-source single core compiler for AMD XDNA Array +compute tile. Peano is available at: https://github.com/Xilinx/llvm-aie -The open-source IREE compiler supports graph compilation of ML models for AMD -NPU and uses Peano underneath. It is available at: -https://github.com/nod-ai/iree-amd-aie +IRON is an open-source array compiler for AMD XDNA Array based NPU which uses +Peano underneath. IRON is available at: +https://github.com/Xilinx/mlir-aie Usermode Driver (UMD) --------------------- From b065bd213caf6d35b57c5089d6507d7e8598a586 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Fri, 22 Aug 2025 17:28:49 +0200 Subject: [PATCH 05/32] drm: re-allow no-op changes on non-primary planes in async flips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit fd40a63c63a1 ("drm/atomic: Let drivers decide which planes to async flip") unintentionally disallowed no-op changes on non-primary planes that the driver doesn't allow async flips on. This broke async flips for compositors that disable the cursor plane in every async atomic commit. To fix that, change drm_atomic_set_property to again only run atomic_async_check if the plane would actually be changed by the atomic commit. Fixes: fd40a63c63a1 ("drm/atomic: Let drivers decide which planes to async flip") Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4263 Signed-off-by: Xaver Hugl Reviewed-by: André Almeida Link: https://lore.kernel.org/r/20250822152849.87843-1-xaver.hugl@kde.org [andrealmeid: fix checkpatch warning] Signed-off-by: André Almeida --- drivers/gpu/drm/drm_atomic_uapi.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index ecc73d52bfae..85dbdaa4a2e2 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -1078,19 +1078,20 @@ int drm_atomic_set_property(struct drm_atomic_state *state, } if (async_flip) { - /* check if the prop does a nop change */ - if ((prop != config->prop_fb_id && - prop != config->prop_in_fence_fd && - prop != config->prop_fb_damage_clips)) { - ret = drm_atomic_plane_get_property(plane, plane_state, - prop, &old_val); - ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop); + /* no-op changes are always allowed */ + ret = drm_atomic_plane_get_property(plane, plane_state, + prop, &old_val); + ret = drm_atomic_check_prop_changes(ret, old_val, prop_value, prop); + + /* fail everything that isn't no-op or a pure flip */ + if (ret && prop != config->prop_fb_id && + prop != config->prop_in_fence_fd && + prop != config->prop_fb_damage_clips) { + break; } - /* ask the driver if this non-primary plane is supported */ - if (plane->type != DRM_PLANE_TYPE_PRIMARY) { - ret = -EINVAL; - + if (ret && plane->type != DRM_PLANE_TYPE_PRIMARY) { + /* ask the driver if this non-primary plane is supported */ if (plane_funcs && plane_funcs->atomic_async_check) ret = plane_funcs->atomic_async_check(plane, state, true); From 480a76c64f4f6a7f8d4aa2ac86cd2178687716b9 Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 22 Aug 2025 14:39:49 +0800 Subject: [PATCH 06/32] dt-bindings: display: simple-bridge: Add ra620 compatible RA620 is a DP to HDMI bridge converter from RADXA, which first found be used on ROCK 5 ITX. This chip can be used without involving software. Signed-off-by: Andy Yan Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20250822063959.692098-6-andyshrk@163.com Signed-off-by: Dmitry Baryshkov --- .../devicetree/bindings/display/bridge/simple-bridge.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml index 43cf4df9811a..421f99ca42d9 100644 --- a/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml +++ b/Documentation/devicetree/bindings/display/bridge/simple-bridge.yaml @@ -28,6 +28,7 @@ properties: - enum: - adi,adv7123 - dumb-vga-dac + - radxa,ra620 - ti,opa362 - ti,ths8134 - ti,ths8135 From 73b81fcb12df1051bd169e488245f8bf4c37bc93 Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Fri, 22 Aug 2025 14:39:50 +0800 Subject: [PATCH 07/32] drm/bridge: simple-bridge: Add support for radxa ra620 The RA620 is an active DP to HDMI converter chip, basically no software is involved to drive it. Add it to simple bridge to make it can be find by the drm bridge chain. Signed-off-by: Andy Yan Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250822063959.692098-7-andyshrk@163.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/bridge/simple-bridge.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c index 3d15ddd39470..1f16d568bcc4 100644 --- a/drivers/gpu/drm/bridge/simple-bridge.c +++ b/drivers/gpu/drm/bridge/simple-bridge.c @@ -261,6 +261,11 @@ static const struct of_device_id simple_bridge_match[] = { .timings = &default_bridge_timings, .connector_type = DRM_MODE_CONNECTOR_VGA, }, + }, { + .compatible = "radxa,ra620", + .data = &(const struct simple_bridge_info) { + .connector_type = DRM_MODE_CONNECTOR_HDMIA, + }, }, { .compatible = "ti,opa362", .data = &(const struct simple_bridge_info) { From 6c66eba502709a78281333187c1add7b71f7201f Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 7 Jul 2025 18:48:54 +0200 Subject: [PATCH 08/32] drm/panel: ilitek-ili9881c: turn off power-supply when init fails The prepare function turns on the power-supply regulator first, when preparing the display. But in an error case, just returns the error code, but does not power off the regulator again, fix that. Reviewed-by: Neil Armstrong Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250707164906.1445288-2-heiko@sntech.de --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index ac433345a179..3af22a5f5700 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -1486,7 +1486,7 @@ static int ili9881c_prepare(struct drm_panel *panel) instr->arg.cmd.data); if (ret) - return ret; + goto disable_power; } ret = ili9881c_switch_page(ctx, 0); @@ -1498,18 +1498,22 @@ static int ili9881c_prepare(struct drm_panel *panel) &ctx->address_mode, sizeof(ctx->address_mode)); if (ret < 0) - return ret; + goto disable_power; } ret = mipi_dsi_dcs_set_tear_on(ctx->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); if (ret) - return ret; + goto disable_power; ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi); if (ret) - return ret; + goto disable_power; return 0; + +disable_power: + regulator_disable(ctx->power); + return ret; } static int ili9881c_enable(struct drm_panel *panel) From 5efa82492066fcb32308210fb3f0b752af74334f Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 7 Jul 2025 18:48:55 +0200 Subject: [PATCH 09/32] drm/panel: ilitek-ili9881c: move display_on/_off dcs calls to (un-)prepare At least for panel-bridges, the atomic_enable call is defined as being called right after the preceding element in the display pipe is enabled. It is also stated that "The bridge can assume that the display pipe (i.e. clocks and timing signals) feeding it is running when this callback is called" This means the DSI controller driving this display would have already switched over to video-mode from command mode and thus dcs functions should not be called anymore at this point. This caused a non-working display for me, when trying to enable the rk3576 dsi controller using a display using this controller. Therefore move the display_on/off calls the more appropriate prepare/unprepare callbacks. Reviewed-by: Neil Armstrong Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250707164906.1445288-3-heiko@sntech.de --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 27 +++++-------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 3af22a5f5700..7ed65d6762d8 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -1509,6 +1509,12 @@ static int ili9881c_prepare(struct drm_panel *panel) if (ret) goto disable_power; + msleep(120); + + ret = mipi_dsi_dcs_set_display_on(ctx->dsi); + if (ret) + goto disable_power; + return 0; disable_power: @@ -1516,28 +1522,11 @@ static int ili9881c_prepare(struct drm_panel *panel) return ret; } -static int ili9881c_enable(struct drm_panel *panel) -{ - struct ili9881c *ctx = panel_to_ili9881c(panel); - - msleep(120); - - mipi_dsi_dcs_set_display_on(ctx->dsi); - - return 0; -} - -static int ili9881c_disable(struct drm_panel *panel) -{ - struct ili9881c *ctx = panel_to_ili9881c(panel); - - return mipi_dsi_dcs_set_display_off(ctx->dsi); -} - static int ili9881c_unprepare(struct drm_panel *panel) { struct ili9881c *ctx = panel_to_ili9881c(panel); + mipi_dsi_dcs_set_display_off(ctx->dsi); mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); regulator_disable(ctx->power); gpiod_set_value_cansleep(ctx->reset, 1); @@ -1710,8 +1699,6 @@ static enum drm_panel_orientation ili9881c_get_orientation(struct drm_panel *pan static const struct drm_panel_funcs ili9881c_funcs = { .prepare = ili9881c_prepare, .unprepare = ili9881c_unprepare, - .enable = ili9881c_enable, - .disable = ili9881c_disable, .get_modes = ili9881c_get_modes, .get_orientation = ili9881c_get_orientation, }; From 9002f55ee4480f23bd2ce91fb5fca536ce31717e Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 7 Jul 2025 18:48:56 +0200 Subject: [PATCH 10/32] drm/panel: ilitek-ili9881c: convert (un-)prepare to mipi_dsi_multi_context This saves some lines for error handling. For the address mode change, that value is always an u8, so switching to dcs_write_buffer function should be appropriate. Reviewed-by: Neil Armstrong Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250707164906.1445288-4-heiko@sntech.de --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 66 ++++++------------- 1 file changed, 21 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 7ed65d6762d8..8b208f5701f6 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -1433,33 +1433,24 @@ static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) * So before any attempt at sending a command or data, we have to be * sure if we're in the right page or not. */ -static int ili9881c_switch_page(struct ili9881c *ctx, u8 page) +static void ili9881c_switch_page(struct mipi_dsi_multi_context *mctx, u8 page) { u8 buf[4] = { 0xff, 0x98, 0x81, page }; - int ret; - ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf)); - if (ret < 0) - return ret; - - return 0; + mipi_dsi_dcs_write_buffer_multi(mctx, buf, sizeof(buf)); } -static int ili9881c_send_cmd_data(struct ili9881c *ctx, u8 cmd, u8 data) +static void ili9881c_send_cmd_data(struct mipi_dsi_multi_context *mctx, u8 cmd, u8 data) { u8 buf[2] = { cmd, data }; - int ret; - ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf)); - if (ret < 0) - return ret; - - return 0; + mipi_dsi_dcs_write_buffer_multi(mctx, buf, sizeof(buf)); } static int ili9881c_prepare(struct drm_panel *panel) { struct ili9881c *ctx = panel_to_ili9881c(panel); + struct mipi_dsi_multi_context mctx = { .dsi = ctx->dsi }; unsigned int i; int ret; @@ -1480,54 +1471,39 @@ static int ili9881c_prepare(struct drm_panel *panel) const struct ili9881c_instr *instr = &ctx->desc->init[i]; if (instr->op == ILI9881C_SWITCH_PAGE) - ret = ili9881c_switch_page(ctx, instr->arg.page); + ili9881c_switch_page(&mctx, instr->arg.page); else if (instr->op == ILI9881C_COMMAND) - ret = ili9881c_send_cmd_data(ctx, instr->arg.cmd.cmd, - instr->arg.cmd.data); - - if (ret) - goto disable_power; + ili9881c_send_cmd_data(&mctx, instr->arg.cmd.cmd, + instr->arg.cmd.data); } - ret = ili9881c_switch_page(ctx, 0); - if (ret) - return ret; + ili9881c_switch_page(&mctx, 0); - if (ctx->address_mode) { - ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_ADDRESS_MODE, - &ctx->address_mode, - sizeof(ctx->address_mode)); - if (ret < 0) - goto disable_power; - } + if (ctx->address_mode) + ili9881c_send_cmd_data(&mctx, MIPI_DCS_SET_ADDRESS_MODE, + ctx->address_mode); - ret = mipi_dsi_dcs_set_tear_on(ctx->dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); - if (ret) - goto disable_power; - - ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi); - if (ret) - goto disable_power; - - msleep(120); - - ret = mipi_dsi_dcs_set_display_on(ctx->dsi); - if (ret) + mipi_dsi_dcs_set_tear_on_multi(&mctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); + mipi_dsi_dcs_exit_sleep_mode_multi(&mctx); + mipi_dsi_msleep(&mctx, 120); + mipi_dsi_dcs_set_display_on_multi(&mctx); + if (mctx.accum_err) goto disable_power; return 0; disable_power: regulator_disable(ctx->power); - return ret; + return mctx.accum_err; } static int ili9881c_unprepare(struct drm_panel *panel) { struct ili9881c *ctx = panel_to_ili9881c(panel); + struct mipi_dsi_multi_context mctx = { .dsi = ctx->dsi }; - mipi_dsi_dcs_set_display_off(ctx->dsi); - mipi_dsi_dcs_enter_sleep_mode(ctx->dsi); + mipi_dsi_dcs_set_display_off_multi(&mctx); + mipi_dsi_dcs_enter_sleep_mode_multi(&mctx); regulator_disable(ctx->power); gpiod_set_value_cansleep(ctx->reset, 1); From 8e484ff181b177ea2e86e537fd7a5c8f9d7532ad Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 7 Jul 2025 18:48:57 +0200 Subject: [PATCH 11/32] dt-bindings: vendor-prefixes: Add prefix for Shenzhen Bestar Electronic Add the prefix for Bestar, named in full both on Panelook.com and their display datasheets as Shenzhen Bestar Electronic Technology Co., Ltd. which produces at least DSI displays and maybe more. Acked-by: "Rob Herring (Arm)" Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250707164906.1445288-5-heiko@sntech.de --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 77160cd47f54..abc43c43813a 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -221,6 +221,8 @@ patternProperties: description: BeagleBoard.org Foundation "^belling,.*": description: Shanghai Belling Co., Ltd. + "^bestar,.*": + description: Shenzhen Bestar Electronic Technology Co., Ltd. "^bhf,.*": description: Beckhoff Automation GmbH & Co. KG "^bigtreetech,.*": From 157ba8c6742931a617a34555c27dd10b36385cf3 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 7 Jul 2025 18:48:58 +0200 Subject: [PATCH 12/32] dt-bindings: display: ili9881c: Add Bestar BSD1218-A101KL68 LCD panel Document the compatible value for Bestar BSD1218-A101KL68 LCD panels that are based around the ili9881c controller. Acked-by: "Rob Herring (Arm)" Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250707164906.1445288-6-heiko@sntech.de --- .../devicetree/bindings/display/panel/ilitek,ili9881c.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml index a51af61d4846..434cc6af9c95 100644 --- a/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml +++ b/Documentation/devicetree/bindings/display/panel/ilitek,ili9881c.yaml @@ -18,6 +18,7 @@ properties: - enum: - ampire,am8001280g - bananapi,lhr050h41 + - bestar,bsd1218-a101kl68 - feixin,k101-im2byl02 - raspberrypi,dsi-7inch - startek,kd050hdfia020 From 38dbbbb41c515d72b0a82fde3cec450d068f5e94 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 7 Jul 2025 18:48:59 +0200 Subject: [PATCH 13/32] drm/panel: ilitek-ili9881c: Add Bestar BSD1218-A101KL68 support Add support for the Bestar BSD1218-A101KL68 panel. The init table comes from the Firefly BSP ([1]). [1] https://gitlab.com/firefly-linux/kernel/-/blob/rk3588/firefly/arch/arm64/boot/dts/rockchip/aio-3588l-mipi101-BSD1218-A101KL68.dtsi Reviewed-by: Neil Armstrong Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250707164906.1445288-7-heiko@sntech.de --- drivers/gpu/drm/panel/panel-ilitek-ili9881c.c | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c index 8b208f5701f6..ad4993b2f92a 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9881c.c @@ -1417,6 +1417,200 @@ static const struct ili9881c_instr rpi_7inch_init[] = { ILI9881C_COMMAND_INSTR(0xD3, 0x39), }; +static const struct ili9881c_instr bsd1218_a101kl68_init[] = { + ILI9881C_SWITCH_PAGE_INSTR(3), + ILI9881C_COMMAND_INSTR(0x01, 0x00), + ILI9881C_COMMAND_INSTR(0x02, 0x00), + ILI9881C_COMMAND_INSTR(0x03, 0x55), + ILI9881C_COMMAND_INSTR(0x04, 0x55), + ILI9881C_COMMAND_INSTR(0x05, 0x03), + ILI9881C_COMMAND_INSTR(0x06, 0x06), + ILI9881C_COMMAND_INSTR(0x07, 0x00), + ILI9881C_COMMAND_INSTR(0x08, 0x07), + ILI9881C_COMMAND_INSTR(0x09, 0x00), + ILI9881C_COMMAND_INSTR(0x0a, 0x00), + ILI9881C_COMMAND_INSTR(0x0b, 0x00), + ILI9881C_COMMAND_INSTR(0x0c, 0x00), + ILI9881C_COMMAND_INSTR(0x0d, 0x00), + ILI9881C_COMMAND_INSTR(0x0e, 0x00), + ILI9881C_COMMAND_INSTR(0x0f, 0x00), + ILI9881C_COMMAND_INSTR(0x10, 0x00), + ILI9881C_COMMAND_INSTR(0x11, 0x00), + ILI9881C_COMMAND_INSTR(0x12, 0x00), + ILI9881C_COMMAND_INSTR(0x13, 0x00), + ILI9881C_COMMAND_INSTR(0x14, 0x00), + ILI9881C_COMMAND_INSTR(0x15, 0x00), + ILI9881C_COMMAND_INSTR(0x16, 0x00), + ILI9881C_COMMAND_INSTR(0x17, 0x00), + ILI9881C_COMMAND_INSTR(0x18, 0x00), + ILI9881C_COMMAND_INSTR(0x19, 0x00), + ILI9881C_COMMAND_INSTR(0x1a, 0x00), + ILI9881C_COMMAND_INSTR(0x1b, 0x00), + ILI9881C_COMMAND_INSTR(0x1c, 0x00), + ILI9881C_COMMAND_INSTR(0x1d, 0x00), + ILI9881C_COMMAND_INSTR(0x1e, 0xc0), + ILI9881C_COMMAND_INSTR(0x1f, 0x80), + ILI9881C_COMMAND_INSTR(0x20, 0x04), + ILI9881C_COMMAND_INSTR(0x21, 0x03), + ILI9881C_COMMAND_INSTR(0x22, 0x00), + ILI9881C_COMMAND_INSTR(0x23, 0x00), + ILI9881C_COMMAND_INSTR(0x24, 0x00), + ILI9881C_COMMAND_INSTR(0x25, 0x00), + ILI9881C_COMMAND_INSTR(0x26, 0x00), + ILI9881C_COMMAND_INSTR(0x27, 0x00), + ILI9881C_COMMAND_INSTR(0x28, 0x33), + ILI9881C_COMMAND_INSTR(0x29, 0x33), + ILI9881C_COMMAND_INSTR(0x2a, 0x00), + ILI9881C_COMMAND_INSTR(0x2b, 0x00), + ILI9881C_COMMAND_INSTR(0x2c, 0x00), + ILI9881C_COMMAND_INSTR(0x2d, 0x00), + ILI9881C_COMMAND_INSTR(0x2e, 0x00), + ILI9881C_COMMAND_INSTR(0x2f, 0x00), + ILI9881C_COMMAND_INSTR(0x30, 0x00), + ILI9881C_COMMAND_INSTR(0x31, 0x00), + ILI9881C_COMMAND_INSTR(0x32, 0x00), + ILI9881C_COMMAND_INSTR(0x33, 0x00), + ILI9881C_COMMAND_INSTR(0x34, 0x04), + ILI9881C_COMMAND_INSTR(0x35, 0x00), + ILI9881C_COMMAND_INSTR(0x36, 0x00), + ILI9881C_COMMAND_INSTR(0x37, 0x00), + ILI9881C_COMMAND_INSTR(0x38, 0x3c), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0x3a, 0x00), + ILI9881C_COMMAND_INSTR(0x3b, 0x00), + ILI9881C_COMMAND_INSTR(0x3c, 0x00), + ILI9881C_COMMAND_INSTR(0x3d, 0x00), + ILI9881C_COMMAND_INSTR(0x3e, 0x00), + ILI9881C_COMMAND_INSTR(0x3f, 0x00), + ILI9881C_COMMAND_INSTR(0x40, 0x00), + ILI9881C_COMMAND_INSTR(0x41, 0x00), + ILI9881C_COMMAND_INSTR(0x42, 0x00), + ILI9881C_COMMAND_INSTR(0x43, 0x00), + ILI9881C_COMMAND_INSTR(0x44, 0x00), + ILI9881C_COMMAND_INSTR(0x50, 0x00), + ILI9881C_COMMAND_INSTR(0x51, 0x11), + ILI9881C_COMMAND_INSTR(0x52, 0x44), + ILI9881C_COMMAND_INSTR(0x53, 0x55), + ILI9881C_COMMAND_INSTR(0x54, 0x88), + ILI9881C_COMMAND_INSTR(0x55, 0xab), + ILI9881C_COMMAND_INSTR(0x56, 0x00), + ILI9881C_COMMAND_INSTR(0x57, 0x11), + ILI9881C_COMMAND_INSTR(0x58, 0x22), + ILI9881C_COMMAND_INSTR(0x59, 0x33), + ILI9881C_COMMAND_INSTR(0x5a, 0x44), + ILI9881C_COMMAND_INSTR(0x5b, 0x55), + ILI9881C_COMMAND_INSTR(0x5c, 0x66), + ILI9881C_COMMAND_INSTR(0x5d, 0x77), + ILI9881C_COMMAND_INSTR(0x5e, 0x00), + ILI9881C_COMMAND_INSTR(0x5f, 0x02), + ILI9881C_COMMAND_INSTR(0x60, 0x02), + ILI9881C_COMMAND_INSTR(0x61, 0x0a), + ILI9881C_COMMAND_INSTR(0x62, 0x09), + ILI9881C_COMMAND_INSTR(0x63, 0x08), + ILI9881C_COMMAND_INSTR(0x64, 0x13), + ILI9881C_COMMAND_INSTR(0x65, 0x12), + ILI9881C_COMMAND_INSTR(0x66, 0x11), + ILI9881C_COMMAND_INSTR(0x67, 0x10), + ILI9881C_COMMAND_INSTR(0x68, 0x0f), + ILI9881C_COMMAND_INSTR(0x69, 0x0e), + ILI9881C_COMMAND_INSTR(0x6a, 0x0d), + ILI9881C_COMMAND_INSTR(0x6b, 0x0c), + ILI9881C_COMMAND_INSTR(0x6c, 0x06), + ILI9881C_COMMAND_INSTR(0x6d, 0x07), + ILI9881C_COMMAND_INSTR(0x6e, 0x02), + ILI9881C_COMMAND_INSTR(0x6f, 0x02), + ILI9881C_COMMAND_INSTR(0x70, 0x02), + ILI9881C_COMMAND_INSTR(0x71, 0x02), + ILI9881C_COMMAND_INSTR(0x72, 0x02), + ILI9881C_COMMAND_INSTR(0x73, 0x02), + ILI9881C_COMMAND_INSTR(0x74, 0x02), + ILI9881C_COMMAND_INSTR(0x75, 0x02), + ILI9881C_COMMAND_INSTR(0x76, 0x02), + ILI9881C_COMMAND_INSTR(0x77, 0x0a), + ILI9881C_COMMAND_INSTR(0x78, 0x06), + ILI9881C_COMMAND_INSTR(0x79, 0x07), + ILI9881C_COMMAND_INSTR(0x7a, 0x10), + ILI9881C_COMMAND_INSTR(0x7b, 0x11), + ILI9881C_COMMAND_INSTR(0x7c, 0x12), + ILI9881C_COMMAND_INSTR(0x7d, 0x13), + ILI9881C_COMMAND_INSTR(0x7e, 0x0c), + ILI9881C_COMMAND_INSTR(0x7f, 0x0d), + ILI9881C_COMMAND_INSTR(0x80, 0x0e), + ILI9881C_COMMAND_INSTR(0x81, 0x0f), + ILI9881C_COMMAND_INSTR(0x82, 0x09), + ILI9881C_COMMAND_INSTR(0x83, 0x08), + ILI9881C_COMMAND_INSTR(0x84, 0x02), + ILI9881C_COMMAND_INSTR(0x85, 0x02), + ILI9881C_COMMAND_INSTR(0x86, 0x02), + ILI9881C_COMMAND_INSTR(0x87, 0x02), + ILI9881C_COMMAND_INSTR(0x88, 0x02), + ILI9881C_COMMAND_INSTR(0x89, 0x02), + ILI9881C_COMMAND_INSTR(0x8a, 0x02), + + ILI9881C_SWITCH_PAGE_INSTR(4), + ILI9881C_COMMAND_INSTR(0x6e, 0x2a), + ILI9881C_COMMAND_INSTR(0x6f, 0x37), + ILI9881C_COMMAND_INSTR(0x3a, 0x24), + ILI9881C_COMMAND_INSTR(0x8d, 0x19), + ILI9881C_COMMAND_INSTR(0x87, 0xba), + ILI9881C_COMMAND_INSTR(0xb2, 0xd1), + ILI9881C_COMMAND_INSTR(0x88, 0x0b), + ILI9881C_COMMAND_INSTR(0x38, 0x01), + ILI9881C_COMMAND_INSTR(0x39, 0x00), + ILI9881C_COMMAND_INSTR(0xb5, 0x02), + ILI9881C_COMMAND_INSTR(0x31, 0x25), + ILI9881C_COMMAND_INSTR(0x3b, 0x98), + + ILI9881C_SWITCH_PAGE_INSTR(1), + ILI9881C_COMMAND_INSTR(0x22, 0x0a), + ILI9881C_COMMAND_INSTR(0x31, 0x0c), + ILI9881C_COMMAND_INSTR(0x53, 0x40), + ILI9881C_COMMAND_INSTR(0x55, 0x45), + ILI9881C_COMMAND_INSTR(0x50, 0xb7), + ILI9881C_COMMAND_INSTR(0x51, 0xb2), + ILI9881C_COMMAND_INSTR(0x60, 0x07), + ILI9881C_COMMAND_INSTR(0xa0, 0x22), + ILI9881C_COMMAND_INSTR(0xa1, 0x3f), + ILI9881C_COMMAND_INSTR(0xa2, 0x4e), + ILI9881C_COMMAND_INSTR(0xa3, 0x17), + ILI9881C_COMMAND_INSTR(0xa4, 0x1a), + ILI9881C_COMMAND_INSTR(0xa5, 0x2d), + ILI9881C_COMMAND_INSTR(0xa6, 0x21), + ILI9881C_COMMAND_INSTR(0xa7, 0x22), + ILI9881C_COMMAND_INSTR(0xa8, 0xc4), + ILI9881C_COMMAND_INSTR(0xa9, 0x1b), + ILI9881C_COMMAND_INSTR(0xaa, 0x25), + ILI9881C_COMMAND_INSTR(0xab, 0xa7), + ILI9881C_COMMAND_INSTR(0xac, 0x1a), + ILI9881C_COMMAND_INSTR(0xad, 0x19), + ILI9881C_COMMAND_INSTR(0xae, 0x4b), + ILI9881C_COMMAND_INSTR(0xaf, 0x1f), + ILI9881C_COMMAND_INSTR(0xb0, 0x2a), + ILI9881C_COMMAND_INSTR(0xb1, 0x59), + ILI9881C_COMMAND_INSTR(0xb2, 0x64), + ILI9881C_COMMAND_INSTR(0xb3, 0x3f), + ILI9881C_COMMAND_INSTR(0xc0, 0x22), + ILI9881C_COMMAND_INSTR(0xc1, 0x48), + ILI9881C_COMMAND_INSTR(0xc2, 0x59), + ILI9881C_COMMAND_INSTR(0xc3, 0x15), + ILI9881C_COMMAND_INSTR(0xc4, 0x15), + ILI9881C_COMMAND_INSTR(0xc5, 0x28), + ILI9881C_COMMAND_INSTR(0xc6, 0x1c), + ILI9881C_COMMAND_INSTR(0xc7, 0x1e), + ILI9881C_COMMAND_INSTR(0xc8, 0xc4), + ILI9881C_COMMAND_INSTR(0xc9, 0x1c), + ILI9881C_COMMAND_INSTR(0xca, 0x2b), + ILI9881C_COMMAND_INSTR(0xcb, 0xa3), + ILI9881C_COMMAND_INSTR(0xcc, 0x1f), + ILI9881C_COMMAND_INSTR(0xcd, 0x1e), + ILI9881C_COMMAND_INSTR(0xce, 0x52), + ILI9881C_COMMAND_INSTR(0xcf, 0x24), + ILI9881C_COMMAND_INSTR(0xd0, 0x2a), + ILI9881C_COMMAND_INSTR(0xd1, 0x58), + ILI9881C_COMMAND_INSTR(0xd2, 0x68), + ILI9881C_COMMAND_INSTR(0xd3, 0x3f), +}; + static inline struct ili9881c *panel_to_ili9881c(struct drm_panel *panel) { return container_of(panel, struct ili9881c, panel); @@ -1629,6 +1823,23 @@ static const struct drm_display_mode rpi_7inch_default_mode = { .height_mm = 151, }; +static const struct drm_display_mode bsd1218_a101kl68_default_mode = { + .clock = 70000, + + .hdisplay = 800, + .hsync_start = 800 + 40, + .hsync_end = 800 + 40 + 20, + .htotal = 800 + 40 + 20 + 20, + + .vdisplay = 1280, + .vsync_start = 1280 + 20, + .vsync_end = 1280 + 20 + 4, + .vtotal = 1280 + 20 + 4 + 20, + + .width_mm = 120, + .height_mm = 170, +}; + static int ili9881c_get_modes(struct drm_panel *panel, struct drm_connector *connector) { @@ -1797,8 +2008,18 @@ static const struct ili9881c_desc rpi_7inch_desc = { .lanes = 2, }; +static const struct ili9881c_desc bsd1218_a101kl68_desc = { + .init = bsd1218_a101kl68_init, + .init_length = ARRAY_SIZE(bsd1218_a101kl68_init), + .mode = &bsd1218_a101kl68_default_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, + .lanes = 4, +}; + static const struct of_device_id ili9881c_of_match[] = { { .compatible = "bananapi,lhr050h41", .data = &lhr050h41_desc }, + { .compatible = "bestar,bsd1218-a101kl68", .data = &bsd1218_a101kl68_desc }, { .compatible = "feixin,k101-im2byl02", .data = &k101_im2byl02_desc }, { .compatible = "startek,kd050hdfia020", .data = &kd050hdfia020_desc }, { .compatible = "tdo,tl050hdv35", .data = &tl050hdv35_desc }, From f05530bdaf42aa0e6bb4cde76ba6a081cf473d44 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 7 Jul 2025 18:49:01 +0200 Subject: [PATCH 14/32] dt-bindings: display: rockchip: Add rk3576 to RK3588 DW DSI2 controller schema The rk3576 controller is based on the same newer Synopsis IP as the one found in the rk3588. Its external setting bits in the GRF are different though, so it needs its own distinct compatible. Acked-by: "Rob Herring (Arm)" Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250707164906.1445288-9-heiko@sntech.de --- .../bindings/display/rockchip/rockchip,rk3588-mipi-dsi2.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-mipi-dsi2.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-mipi-dsi2.yaml index 53384e47b507..75cd1c13fa52 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-mipi-dsi2.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3588-mipi-dsi2.yaml @@ -12,6 +12,7 @@ maintainers: properties: compatible: enum: + - rockchip,rk3576-mipi-dsi2 - rockchip,rk3588-mipi-dsi2 reg: From b6f11f114759a088acf44e86b5cd72f24de85d44 Mon Sep 17 00:00:00 2001 From: Guochun Huang Date: Mon, 7 Jul 2025 18:49:02 +0200 Subject: [PATCH 15/32] drm/rockchip: dsi2: add support rk3576 Add the necessary specific bits to support the rk3576-variant of the DW-DSI2 controller. Signed-off-by: Guochun Huang [adapted from the vendor-kernel for mainline] Reviewed-by: Andy Yan Signed-off-by: Heiko Stuebner Link: https://lore.kernel.org/r/20250707164906.1445288-10-heiko@sntech.de --- .../gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c index cdd490778756..0aea764e29b2 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c @@ -437,6 +437,15 @@ static void dw_mipi_dsi2_rockchip_remove(struct platform_device *pdev) dw_mipi_dsi2_remove(dsi2->dmd); } +static const struct dsigrf_reg rk3576_dsi_grf_reg_fields[MAX_FIELDS] = { + [TXREQCLKHS_EN] = { 0x0028, 1, 1 }, + [GATING_EN] = { 0x0028, 0, 0 }, + [IPI_SHUTDN] = { 0x0028, 3, 3 }, + [IPI_COLORM] = { 0x0028, 2, 2 }, + [IPI_COLOR_DEPTH] = { 0x0028, 8, 11 }, + [IPI_FORMAT] = { 0x0028, 4, 7 }, +}; + static const struct dsigrf_reg rk3588_dsi0_grf_reg_fields[MAX_FIELDS] = { [TXREQCLKHS_EN] = { 0x0000, 11, 11 }, [GATING_EN] = { 0x0000, 10, 10 }, @@ -455,6 +464,15 @@ static const struct dsigrf_reg rk3588_dsi1_grf_reg_fields[MAX_FIELDS] = { [IPI_FORMAT] = { 0x0004, 0, 3 }, }; +static const struct rockchip_dw_dsi2_chip_data rk3576_chip_data[] = { + { + .reg = 0x27d80000, + .grf_regs = rk3576_dsi_grf_reg_fields, + .max_bit_rate_per_lane = 2500000ULL, + }, + { /* sentinel */ } +}; + static const struct rockchip_dw_dsi2_chip_data rk3588_chip_data[] = { { .reg = 0xfde20000, @@ -470,6 +488,9 @@ static const struct rockchip_dw_dsi2_chip_data rk3588_chip_data[] = { static const struct of_device_id dw_mipi_dsi2_rockchip_dt_ids[] = { { + .compatible = "rockchip,rk3576-mipi-dsi2", + .data = &rk3576_chip_data, + }, { .compatible = "rockchip,rk3588-mipi-dsi2", .data = &rk3588_chip_data, }, From efe927b9702643a1d80472664c2642f0304cb608 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 23 Aug 2025 03:12:00 +0300 Subject: [PATCH 16/32] drm/msm: fix msm_gem_vma_new() allocations for managed GPUVMs Since commit 3309323241fb ("drm/gpuvm: Kill drm_gpuva_init()") MSM driver fails to init, failing with "[drm:msm_gpu_init] *ERROR* could not allocate memptrs: -22" errors. The mentioned commit reworked the function, but didn't take into account that op_map is initialized at the top of the function, while ranges might change if GPUVM is managed by the kernel. Move op_mode initialization after finalizing all addresses and right before the drm_gpuva_init_from_op() call. Reported-by: Danct12 Fixes: 3309323241fb ("drm/gpuvm: Kill drm_gpuva_init()") Suggested-by: Rob Clark Reviewed-by: Rob Clark Acked-by: Rob Clark Link: https://lore.kernel.org/r/20250823-msm-fix-gpuvm-init-v1-1-e199cd5b1983@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/msm_gem_vma.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 210604181c05..c632db9005e2 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -371,12 +371,6 @@ struct drm_gpuva * msm_gem_vma_new(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj, u64 offset, u64 range_start, u64 range_end) { - struct drm_gpuva_op_map op_map = { - .va.addr = range_start, - .va.range = range_end - range_start, - .gem.obj = obj, - .gem.offset = offset, - }; struct msm_gem_vm *vm = to_msm_vm(gpuvm); struct drm_gpuvm_bo *vm_bo; struct msm_gem_vma *vma; @@ -405,6 +399,13 @@ msm_gem_vma_new(struct drm_gpuvm *gpuvm, struct drm_gem_object *obj, if (obj) GEM_WARN_ON((range_end - range_start) > obj->size); + struct drm_gpuva_op_map op_map = { + .va.addr = range_start, + .va.range = range_end - range_start, + .gem.obj = obj, + .gem.offset = offset, + }; + drm_gpuva_init_from_op(&vma->base, &op_map); vma->mapped = false; From 2eb22214c132374e11e681c44d7879c91f67f614 Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Mon, 18 Aug 2025 19:49:33 +0800 Subject: [PATCH 17/32] drm/panel: Allow powering on panel follower after panel is enabled Some touch controllers have to be powered on after the panel's backlight is enabled. To support these controllers, introduce .panel_enabled() and .panel_disabling() to panel_follower_funcs and use them to power on the device after the panel and its backlight are enabled. Signed-off-by: Pin-yen Lin Reviewed-by: Douglas Anderson Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20250818115015.2909525-1-treapking@chromium.org --- drivers/gpu/drm/drm_panel.c | 73 +++++++++++++++++++++++++++++++------ include/drm/drm_panel.h | 14 +++++++ 2 files changed, 76 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index c8bb28dccdc1..d1e6598ea3bc 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -134,6 +134,9 @@ void drm_panel_prepare(struct drm_panel *panel) panel->prepared = true; list_for_each_entry(follower, &panel->followers, list) { + if (!follower->funcs->panel_prepared) + continue; + ret = follower->funcs->panel_prepared(follower); if (ret < 0) dev_info(panel->dev, "%ps failed: %d\n", @@ -179,6 +182,9 @@ void drm_panel_unprepare(struct drm_panel *panel) mutex_lock(&panel->follower_lock); list_for_each_entry(follower, &panel->followers, list) { + if (!follower->funcs->panel_unpreparing) + continue; + ret = follower->funcs->panel_unpreparing(follower); if (ret < 0) dev_info(panel->dev, "%ps failed: %d\n", @@ -209,6 +215,7 @@ EXPORT_SYMBOL(drm_panel_unprepare); */ void drm_panel_enable(struct drm_panel *panel) { + struct drm_panel_follower *follower; int ret; if (!panel) @@ -219,10 +226,12 @@ void drm_panel_enable(struct drm_panel *panel) return; } + mutex_lock(&panel->follower_lock); + if (panel->funcs && panel->funcs->enable) { ret = panel->funcs->enable(panel); if (ret < 0) - return; + goto exit; } panel->enabled = true; @@ -230,6 +239,19 @@ void drm_panel_enable(struct drm_panel *panel) if (ret < 0) DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n", ret); + + list_for_each_entry(follower, &panel->followers, list) { + if (!follower->funcs->panel_enabled) + continue; + + ret = follower->funcs->panel_enabled(follower); + if (ret < 0) + dev_info(panel->dev, "%ps failed: %d\n", + follower->funcs->panel_enabled, ret); + } + +exit: + mutex_unlock(&panel->follower_lock); } EXPORT_SYMBOL(drm_panel_enable); @@ -243,6 +265,7 @@ EXPORT_SYMBOL(drm_panel_enable); */ void drm_panel_disable(struct drm_panel *panel) { + struct drm_panel_follower *follower; int ret; if (!panel) @@ -262,6 +285,18 @@ void drm_panel_disable(struct drm_panel *panel) return; } + mutex_lock(&panel->follower_lock); + + list_for_each_entry(follower, &panel->followers, list) { + if (!follower->funcs->panel_disabling) + continue; + + ret = follower->funcs->panel_disabling(follower); + if (ret < 0) + dev_info(panel->dev, "%ps failed: %d\n", + follower->funcs->panel_disabling, ret); + } + ret = backlight_disable(panel->backlight); if (ret < 0) DRM_DEV_INFO(panel->dev, "failed to disable backlight: %d\n", @@ -270,9 +305,12 @@ void drm_panel_disable(struct drm_panel *panel) if (panel->funcs && panel->funcs->disable) { ret = panel->funcs->disable(panel); if (ret < 0) - return; + goto exit; } panel->enabled = false; + +exit: + mutex_unlock(&panel->follower_lock); } EXPORT_SYMBOL(drm_panel_disable); @@ -539,13 +577,13 @@ EXPORT_SYMBOL(drm_is_panel_follower); * @follower_dev: The 'struct device' for the follower. * @follower: The panel follower descriptor for the follower. * - * A panel follower is called right after preparing the panel and right before - * unpreparing the panel. It's primary intention is to power on an associated - * touchscreen, though it could be used for any similar devices. Multiple - * devices are allowed the follow the same panel. + * A panel follower is called right after preparing/enabling the panel and right + * before unpreparing/disabling the panel. It's primary intention is to power on + * an associated touchscreen, though it could be used for any similar devices. + * Multiple devices are allowed the follow the same panel. * - * If a follower is added to a panel that's already been turned on, the - * follower's prepare callback is called right away. + * If a follower is added to a panel that's already been prepared/enabled, the + * follower's prepared/enabled callback is called right away. * * The "panel" property of the follower points to the panel to be followed. * @@ -569,12 +607,18 @@ int drm_panel_add_follower(struct device *follower_dev, mutex_lock(&panel->follower_lock); list_add_tail(&follower->list, &panel->followers); - if (panel->prepared) { + if (panel->prepared && follower->funcs->panel_prepared) { ret = follower->funcs->panel_prepared(follower); if (ret < 0) dev_info(panel->dev, "%ps failed: %d\n", follower->funcs->panel_prepared, ret); } + if (panel->enabled && follower->funcs->panel_enabled) { + ret = follower->funcs->panel_enabled(follower); + if (ret < 0) + dev_info(panel->dev, "%ps failed: %d\n", + follower->funcs->panel_enabled, ret); + } mutex_unlock(&panel->follower_lock); @@ -587,7 +631,8 @@ EXPORT_SYMBOL(drm_panel_add_follower); * @follower: The panel follower descriptor for the follower. * * Undo drm_panel_add_follower(). This includes calling the follower's - * unprepare function if we're removed from a panel that's currently prepared. + * unpreparing/disabling function if we're removed from a panel that's currently + * prepared/enabled. * * Return: 0 or an error code. */ @@ -598,7 +643,13 @@ void drm_panel_remove_follower(struct drm_panel_follower *follower) mutex_lock(&panel->follower_lock); - if (panel->prepared) { + if (panel->enabled && follower->funcs->panel_disabling) { + ret = follower->funcs->panel_disabling(follower); + if (ret < 0) + dev_info(panel->dev, "%ps failed: %d\n", + follower->funcs->panel_disabling, ret); + } + if (panel->prepared && follower->funcs->panel_unpreparing) { ret = follower->funcs->panel_unpreparing(follower); if (ret < 0) dev_info(panel->dev, "%ps failed: %d\n", diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 843fb756a295..2407bfa60236 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -160,6 +160,20 @@ struct drm_panel_follower_funcs { * Called before the panel is powered off. */ int (*panel_unpreparing)(struct drm_panel_follower *follower); + + /** + * @panel_enabled: + * + * Called after the panel and the backlight have been enabled. + */ + int (*panel_enabled)(struct drm_panel_follower *follower); + + /** + * @panel_disabling: + * + * Called before the panel and the backlight are disabled. + */ + int (*panel_disabling)(struct drm_panel_follower *follower); }; struct drm_panel_follower { From cbdd16b818eef876dd2de9d503fe7397a0666cbe Mon Sep 17 00:00:00 2001 From: Pin-yen Lin Date: Mon, 18 Aug 2025 19:49:34 +0800 Subject: [PATCH 18/32] HID: i2c-hid: Make elan touch controllers power on after panel is enabled Introduce a new HID quirk to indicate that this device has to be enabled after the panel's backlight is enabled, and update the driver data for the elan devices to enable this quirk. This cannot be a I2C HID quirk because the kernel needs to acknowledge this before powering up the device and read the VID/PID. When this quirk is enabled, register .panel_enabled()/.panel_disabling() instead for the panel follower. Also rename the *panel_prepare* functions into *panel_follower* because they could be called in other situations now. Fixes: bd3cba00dcc63 ("HID: i2c-hid: elan: Add support for Elan eKTH6915 i2c-hid touchscreens") Fixes: d06651bebf99e ("HID: i2c-hid: elan: Add elan-ekth6a12nay timing") Reviewed-by: Douglas Anderson Signed-off-by: Pin-yen Lin Acked-by: Jiri Kosina Signed-off-by: Douglas Anderson Link: https://lore.kernel.org/r/20250818115015.2909525-2-treapking@chromium.org --- drivers/hid/i2c-hid/i2c-hid-core.c | 46 ++++++++++++++++----------- drivers/hid/i2c-hid/i2c-hid-of-elan.c | 11 ++++++- include/linux/hid.h | 2 ++ 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index d3912e3f2f13..99ce6386176c 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -112,9 +112,9 @@ struct i2c_hid { struct i2chid_ops *ops; struct drm_panel_follower panel_follower; - struct work_struct panel_follower_prepare_work; + struct work_struct panel_follower_work; bool is_panel_follower; - bool prepare_work_finished; + bool panel_follower_work_finished; }; static const struct i2c_hid_quirks { @@ -1110,10 +1110,10 @@ static int i2c_hid_core_probe_panel_follower(struct i2c_hid *ihid) return ret; } -static void ihid_core_panel_prepare_work(struct work_struct *work) +static void ihid_core_panel_follower_work(struct work_struct *work) { struct i2c_hid *ihid = container_of(work, struct i2c_hid, - panel_follower_prepare_work); + panel_follower_work); struct hid_device *hid = ihid->hid; int ret; @@ -1130,7 +1130,7 @@ static void ihid_core_panel_prepare_work(struct work_struct *work) if (ret) dev_warn(&ihid->client->dev, "Power on failed: %d\n", ret); else - WRITE_ONCE(ihid->prepare_work_finished, true); + WRITE_ONCE(ihid->panel_follower_work_finished, true); /* * The work APIs provide a number of memory ordering guarantees @@ -1139,12 +1139,12 @@ static void ihid_core_panel_prepare_work(struct work_struct *work) * guarantee that a write that happened in the work is visible after * cancel_work_sync(). We'll add a write memory barrier here to match * with i2c_hid_core_panel_unpreparing() to ensure that our write to - * prepare_work_finished is visible there. + * panel_follower_work_finished is visible there. */ smp_wmb(); } -static int i2c_hid_core_panel_prepared(struct drm_panel_follower *follower) +static int i2c_hid_core_panel_follower_resume(struct drm_panel_follower *follower) { struct i2c_hid *ihid = container_of(follower, struct i2c_hid, panel_follower); @@ -1152,29 +1152,36 @@ static int i2c_hid_core_panel_prepared(struct drm_panel_follower *follower) * Powering on a touchscreen can be a slow process. Queue the work to * the system workqueue so we don't block the panel's power up. */ - WRITE_ONCE(ihid->prepare_work_finished, false); - schedule_work(&ihid->panel_follower_prepare_work); + WRITE_ONCE(ihid->panel_follower_work_finished, false); + schedule_work(&ihid->panel_follower_work); return 0; } -static int i2c_hid_core_panel_unpreparing(struct drm_panel_follower *follower) +static int i2c_hid_core_panel_follower_suspend(struct drm_panel_follower *follower) { struct i2c_hid *ihid = container_of(follower, struct i2c_hid, panel_follower); - cancel_work_sync(&ihid->panel_follower_prepare_work); + cancel_work_sync(&ihid->panel_follower_work); - /* Match with ihid_core_panel_prepare_work() */ + /* Match with ihid_core_panel_follower_work() */ smp_rmb(); - if (!READ_ONCE(ihid->prepare_work_finished)) + if (!READ_ONCE(ihid->panel_follower_work_finished)) return 0; return i2c_hid_core_suspend(ihid, true); } -static const struct drm_panel_follower_funcs i2c_hid_core_panel_follower_funcs = { - .panel_prepared = i2c_hid_core_panel_prepared, - .panel_unpreparing = i2c_hid_core_panel_unpreparing, +static const struct drm_panel_follower_funcs + i2c_hid_core_panel_follower_prepare_funcs = { + .panel_prepared = i2c_hid_core_panel_follower_resume, + .panel_unpreparing = i2c_hid_core_panel_follower_suspend, +}; + +static const struct drm_panel_follower_funcs + i2c_hid_core_panel_follower_enable_funcs = { + .panel_enabled = i2c_hid_core_panel_follower_resume, + .panel_disabling = i2c_hid_core_panel_follower_suspend, }; static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid) @@ -1182,7 +1189,10 @@ static int i2c_hid_core_register_panel_follower(struct i2c_hid *ihid) struct device *dev = &ihid->client->dev; int ret; - ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_funcs; + if (ihid->hid->initial_quirks | HID_QUIRK_POWER_ON_AFTER_BACKLIGHT) + ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_enable_funcs; + else + ihid->panel_follower.funcs = &i2c_hid_core_panel_follower_prepare_funcs; /* * If we're not in control of our own power up/power down then we can't @@ -1237,7 +1247,7 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops, init_waitqueue_head(&ihid->wait); mutex_init(&ihid->cmd_lock); mutex_init(&ihid->reset_lock); - INIT_WORK(&ihid->panel_follower_prepare_work, ihid_core_panel_prepare_work); + INIT_WORK(&ihid->panel_follower_work, ihid_core_panel_follower_work); /* we need to allocate the command buffer without knowing the maximum * size of the reports. Let's use HID_MIN_BUFFER_SIZE, then we do the diff --git a/drivers/hid/i2c-hid/i2c-hid-of-elan.c b/drivers/hid/i2c-hid/i2c-hid-of-elan.c index 3fcff6daa0d3..0215f217f6d8 100644 --- a/drivers/hid/i2c-hid/i2c-hid-of-elan.c +++ b/drivers/hid/i2c-hid/i2c-hid-of-elan.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ struct elan_i2c_hid_chip_data { unsigned int post_power_delay_ms; u16 hid_descriptor_address; const char *main_supply_name; + bool power_after_backlight; }; struct i2c_hid_of_elan { @@ -97,6 +99,7 @@ static int i2c_hid_of_elan_probe(struct i2c_client *client) { struct i2c_hid_of_elan *ihid_elan; int ret; + u32 quirks = 0; ihid_elan = devm_kzalloc(&client->dev, sizeof(*ihid_elan), GFP_KERNEL); if (!ihid_elan) @@ -131,8 +134,12 @@ static int i2c_hid_of_elan_probe(struct i2c_client *client) } } + if (ihid_elan->chip_data->power_after_backlight) + quirks = HID_QUIRK_POWER_ON_AFTER_BACKLIGHT; + ret = i2c_hid_core_probe(client, &ihid_elan->ops, - ihid_elan->chip_data->hid_descriptor_address, 0); + ihid_elan->chip_data->hid_descriptor_address, + quirks); if (ret) goto err_deassert_reset; @@ -150,6 +157,7 @@ static const struct elan_i2c_hid_chip_data elan_ekth6915_chip_data = { .post_gpio_reset_on_delay_ms = 300, .hid_descriptor_address = 0x0001, .main_supply_name = "vcc33", + .power_after_backlight = true, }; static const struct elan_i2c_hid_chip_data elan_ekth6a12nay_chip_data = { @@ -157,6 +165,7 @@ static const struct elan_i2c_hid_chip_data elan_ekth6a12nay_chip_data = { .post_gpio_reset_on_delay_ms = 300, .hid_descriptor_address = 0x0001, .main_supply_name = "vcc33", + .power_after_backlight = true, }; static const struct elan_i2c_hid_chip_data ilitek_ili9882t_chip_data = { diff --git a/include/linux/hid.h b/include/linux/hid.h index 2cc4f1e4ea96..c32425b5d011 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -364,6 +364,7 @@ struct hid_item { * | @HID_QUIRK_HAVE_SPECIAL_DRIVER: * | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE: * | @HID_QUIRK_IGNORE_SPECIAL_DRIVER + * | @HID_QUIRK_POWER_ON_AFTER_BACKLIGHT * | @HID_QUIRK_FULLSPEED_INTERVAL: * | @HID_QUIRK_NO_INIT_REPORTS: * | @HID_QUIRK_NO_IGNORE: @@ -391,6 +392,7 @@ struct hid_item { #define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20) #define HID_QUIRK_NOINVERT BIT(21) #define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22) +#define HID_QUIRK_POWER_ON_AFTER_BACKLIGHT BIT(23) #define HID_QUIRK_FULLSPEED_INTERVAL BIT(28) #define HID_QUIRK_NO_INIT_REPORTS BIT(29) #define HID_QUIRK_NO_IGNORE BIT(30) From cff5fb82733c4f1acda458ffd2bb5c948fb59bd6 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 14 Jul 2025 17:13:01 +0200 Subject: [PATCH 19/32] video: pixel_format: Add compare helpers Add helpers that compare two pixel-format descriptions against each other. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20250714151513.309475-2-tzimmermann@suse.de --- include/video/pixel_format.h | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/include/video/pixel_format.h b/include/video/pixel_format.h index b5104b2a3a13..c57019cd6ea8 100644 --- a/include/video/pixel_format.h +++ b/include/video/pixel_format.h @@ -38,4 +38,62 @@ struct pixel_format { #define PIXEL_FORMAT_XRGB2101010 \ { 32, false, { .alpha = {0, 0}, .red = {20, 10}, .green = {10, 10}, .blue = {0, 10} } } +#define __pixel_format_cmp_field(lhs, rhs, name) \ + { \ + int ret = ((lhs)->name) - ((rhs)->name); \ + if (ret) \ + return ret; \ + } + +#define __pixel_format_cmp_bitfield(lhs, rhs, name) \ + { \ + __pixel_format_cmp_field(lhs, rhs, name.offset); \ + __pixel_format_cmp_field(lhs, rhs, name.length); \ + } + +/** + * pixel_format_cmp - Compares two pixel-format descriptions + * + * @lhs: a pixel-format description + * @rhs: a pixel-format description + * + * Compares two pixel-format descriptions for their order. The semantics + * are equivalent to memcmp(). + * + * Returns: + * 0 if both arguments describe the same pixel format, less-than-zero if lhs < rhs, + * or greater-than-zero if lhs > rhs. + */ +static inline int pixel_format_cmp(const struct pixel_format *lhs, const struct pixel_format *rhs) +{ + __pixel_format_cmp_field(lhs, rhs, bits_per_pixel); + __pixel_format_cmp_field(lhs, rhs, indexed); + + if (lhs->indexed) { + __pixel_format_cmp_bitfield(lhs, rhs, index); + } else { + __pixel_format_cmp_bitfield(lhs, rhs, alpha); + __pixel_format_cmp_bitfield(lhs, rhs, red); + __pixel_format_cmp_bitfield(lhs, rhs, green); + __pixel_format_cmp_bitfield(lhs, rhs, blue); + } + + return 0; +} + +/** + * pixel_format_equal - Compares two pixel-format descriptions for equality + * + * @lhs: a pixel-format description + * @rhs: a pixel-format description + * + * Returns: + * True if both arguments describe the same pixel format, or false otherwise. + */ +static inline bool pixel_format_equal(const struct pixel_format *lhs, + const struct pixel_format *rhs) +{ + return !pixel_format_cmp(lhs, rhs); +} + #endif From d6d05e2af796ca25094f80a73d8841505d54368b Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Mon, 14 Jul 2025 17:13:02 +0200 Subject: [PATCH 20/32] video: screen_info: Add pixel-format helper for linear framebuffers Add screen_info_pixel_format(), which converts a screen_info's information about the color format to struct pixel_format. The encoding within the screen_info structure is complex and therefore prone to errors. Later patches will convert callers to use the pixel format. Signed-off-by: Thomas Zimmermann Reviewed-by: Javier Martinez Canillas Link: https://lore.kernel.org/r/20250714151513.309475-3-tzimmermann@suse.de --- drivers/video/screen_info_generic.c | 55 +++++++++++++++++++++++++++++ include/linux/screen_info.h | 2 ++ 2 files changed, 57 insertions(+) diff --git a/drivers/video/screen_info_generic.c b/drivers/video/screen_info_generic.c index 900e9386eceb..763adbba71cb 100644 --- a/drivers/video/screen_info_generic.c +++ b/drivers/video/screen_info_generic.c @@ -5,6 +5,8 @@ #include #include +#include