From d6a4da523deba1814a45a593c271c32efedc39f3 Mon Sep 17 00:00:00 2001 From: Tejas Vipin Date: Sat, 19 Apr 2025 09:42:09 +0530 Subject: [PATCH 01/16] drm/panel: panel-samsung-sofef00: transition to mipi_dsi wrapped functions Changes the samsung-sofef00 panel to use multi style functions for improved error handling. Signed-off-by: Tejas Vipin Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250419041210.515517-2-tejasvipin76@gmail.com Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20250419041210.515517-2-tejasvipin76@gmail.com --- drivers/gpu/drm/panel/panel-samsung-sofef00.c | 70 ++++++------------- 1 file changed, 21 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-samsung-sofef00.c b/drivers/gpu/drm/panel/panel-samsung-sofef00.c index 04ce925b3d9d..e20c85d5d9e1 100644 --- a/drivers/gpu/drm/panel/panel-samsung-sofef00.c +++ b/drivers/gpu/drm/panel/panel-samsung-sofef00.c @@ -44,66 +44,44 @@ static void sofef00_panel_reset(struct sofef00_panel *ctx) static int sofef00_panel_on(struct sofef00_panel *ctx) { struct mipi_dsi_device *dsi = ctx->dsi; - struct device *dev = &dsi->dev; - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; dsi->mode_flags |= MIPI_DSI_MODE_LPM; - ret = mipi_dsi_dcs_exit_sleep_mode(dsi); - if (ret < 0) { - dev_err(dev, "Failed to exit sleep mode: %d\n", ret); - return ret; - } - usleep_range(10000, 11000); + mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); + mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000); - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x5a, 0x5a); - ret = mipi_dsi_dcs_set_tear_on(dsi, MIPI_DSI_DCS_TEAR_MODE_VBLANK); - if (ret < 0) { - dev_err(dev, "Failed to set tear on: %d\n", ret); - return ret; - } + mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK); - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0x5a, 0x5a); - mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x07); - mipi_dsi_dcs_write_seq(dsi, 0xb6, 0x12); - mipi_dsi_dcs_write_seq(dsi, 0xf0, 0xa5, 0xa5); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); - mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xa5, 0xa5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x5a, 0x5a); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb0, 0x07); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0x12); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0xa5, 0xa5); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x20); + mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00); - ret = mipi_dsi_dcs_set_display_on(dsi); - if (ret < 0) { - dev_err(dev, "Failed to set display on: %d\n", ret); - return ret; - } + mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); - return 0; + return dsi_ctx.accum_err; } static int sofef00_panel_off(struct sofef00_panel *ctx) { struct mipi_dsi_device *dsi = ctx->dsi; - struct device *dev = &dsi->dev; - int ret; + struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; - ret = mipi_dsi_dcs_set_display_off(dsi); - if (ret < 0) { - dev_err(dev, "Failed to set display off: %d\n", ret); - return ret; - } - msleep(40); + mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 40); - ret = mipi_dsi_dcs_enter_sleep_mode(dsi); - if (ret < 0) { - dev_err(dev, "Failed to enter sleep mode: %d\n", ret); - return ret; - } - msleep(160); + mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); + mipi_dsi_msleep(&dsi_ctx, 160); - return 0; + return dsi_ctx.accum_err; } static int sofef00_panel_prepare(struct drm_panel *panel) @@ -122,7 +100,6 @@ static int sofef00_panel_prepare(struct drm_panel *panel) ret = sofef00_panel_on(ctx); if (ret < 0) { - dev_err(dev, "Failed to initialize panel: %d\n", ret); gpiod_set_value_cansleep(ctx->reset_gpio, 1); return ret; } @@ -133,13 +110,8 @@ static int sofef00_panel_prepare(struct drm_panel *panel) static int sofef00_panel_unprepare(struct drm_panel *panel) { struct sofef00_panel *ctx = to_sofef00_panel(panel); - struct device *dev = &ctx->dsi->dev; - int ret; - - ret = sofef00_panel_off(ctx); - if (ret < 0) - dev_err(dev, "Failed to un-initialize panel: %d\n", ret); + sofef00_panel_off(ctx); regulator_disable(ctx->supply); return 0; -- 2.51.0 From 61a0fc33b8538169eb30365b1598eaf33895c34f Mon Sep 17 00:00:00 2001 From: Tejas Vipin Date: Sat, 19 Apr 2025 09:42:10 +0530 Subject: [PATCH 02/16] drm/mipi-dsi: Remove mipi_dsi_dcs_write_seq There are no remaining users of mipi_dsi_dcs_write_seq and it can be removed in favor of mipi_dsi_dcs_write_seq_multi. Signed-off-by: Tejas Vipin Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20250419041210.515517-3-tejasvipin76@gmail.com Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20250419041210.515517-3-tejasvipin76@gmail.com --- include/drm/drm_mipi_dsi.h | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index d6796ce9f5ff..b37860f4a895 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -417,28 +417,6 @@ void mipi_dsi_dcs_set_tear_off_multi(struct mipi_dsi_multi_context *ctx); mipi_dsi_generic_write_multi(ctx, d, ARRAY_SIZE(d)); \ } while (0) -/** - * mipi_dsi_dcs_write_seq - transmit a DCS command with payload - * - * This macro will print errors for you and will RETURN FROM THE CALLING - * FUNCTION (yes this is non-intuitive) upon error. - * - * Because of the non-intuitive return behavior, THIS MACRO IS DEPRECATED. - * Please replace calls of it with mipi_dsi_dcs_write_seq_multi(). - * - * @dsi: DSI peripheral device - * @cmd: Command - * @seq: buffer containing data to be transmitted - */ -#define mipi_dsi_dcs_write_seq(dsi, cmd, seq...) \ - do { \ - static const u8 d[] = { cmd, seq }; \ - int ret; \ - ret = mipi_dsi_dcs_write_buffer_chatty(dsi, d, ARRAY_SIZE(d)); \ - if (ret < 0) \ - return ret; \ - } while (0) - /** * mipi_dsi_dcs_write_seq_multi - transmit a DCS command with payload * -- 2.51.0 From e1eb7293ab4107e9e19fa609835e657fe30dfec7 Mon Sep 17 00:00:00 2001 From: Casey Connolly Date: Sat, 19 Apr 2025 18:31:44 +0200 Subject: [PATCH 03/16] drm/panel: samsung-sofef00: Drop s6e3fc2x01 support We never properly supported this panel and always used the wrong init sequence. Drop support so we can move it to it's own proper driver. Fixes: 5933baa36e26 ("drm/panel/samsung-sofef00: Add panel for OnePlus 6/T devices") Signed-off-by: Casey Connolly Signed-off-by: David Heidelberg Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://lore.kernel.org/r/20250419-drop-s6e3fc2x01-support-v1-1-05edfe0d27aa@ixit.cz --- drivers/gpu/drm/panel/panel-samsung-sofef00.c | 34 ++----------------- 1 file changed, 2 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-samsung-sofef00.c b/drivers/gpu/drm/panel/panel-samsung-sofef00.c index e20c85d5d9e1..210a25afe82b 100644 --- a/drivers/gpu/drm/panel/panel-samsung-sofef00.c +++ b/drivers/gpu/drm/panel/panel-samsung-sofef00.c @@ -22,7 +22,6 @@ struct sofef00_panel { struct mipi_dsi_device *dsi; struct regulator *supply; struct gpio_desc *reset_gpio; - const struct drm_display_mode *mode; }; static inline @@ -131,26 +130,11 @@ static const struct drm_display_mode enchilada_panel_mode = { .height_mm = 145, }; -static const struct drm_display_mode fajita_panel_mode = { - .clock = (1080 + 72 + 16 + 36) * (2340 + 32 + 4 + 18) * 60 / 1000, - .hdisplay = 1080, - .hsync_start = 1080 + 72, - .hsync_end = 1080 + 72 + 16, - .htotal = 1080 + 72 + 16 + 36, - .vdisplay = 2340, - .vsync_start = 2340 + 32, - .vsync_end = 2340 + 32 + 4, - .vtotal = 2340 + 32 + 4 + 18, - .width_mm = 68, - .height_mm = 145, -}; - static int sofef00_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector) { struct drm_display_mode *mode; - struct sofef00_panel *ctx = to_sofef00_panel(panel); - mode = drm_mode_duplicate(connector->dev, ctx->mode); + mode = drm_mode_duplicate(connector->dev, &enchilada_panel_mode); if (!mode) return -ENOMEM; @@ -211,13 +195,6 @@ static int sofef00_panel_probe(struct mipi_dsi_device *dsi) if (!ctx) return -ENOMEM; - ctx->mode = of_device_get_match_data(dev); - - if (!ctx->mode) { - dev_err(dev, "Missing device mode\n"); - return -ENODEV; - } - ctx->supply = devm_regulator_get(dev, "vddio"); if (IS_ERR(ctx->supply)) return dev_err_probe(dev, PTR_ERR(ctx->supply), @@ -267,14 +244,7 @@ static void sofef00_panel_remove(struct mipi_dsi_device *dsi) } static const struct of_device_id sofef00_panel_of_match[] = { - { // OnePlus 6 / enchilada - .compatible = "samsung,sofef00", - .data = &enchilada_panel_mode, - }, - { // OnePlus 6T / fajita - .compatible = "samsung,s6e3fc2x01", - .data = &fajita_panel_mode, - }, + { .compatible = "samsung,sofef00" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sofef00_panel_of_match); -- 2.51.0 From b437b8f745e21de6b45a9b3bd712407f6b4c1ecb Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 17 Apr 2025 14:19:42 +0200 Subject: [PATCH 04/16] drm/panthor: Don't create a file offset for NO_MMAP BOs MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Right now the DRM_PANTHOR_BO_NO_MMAP flag is ignored by panthor_ioctl_bo_mmap_offset(), meaning BOs with this flag set can have a file offset but can't be mapped anyway, because panthor_gem_mmap() will filter them out. If we error out at mmap_offset creation time, we can get rid of panthor_gem_mmap() and call drm_gem_shmem_object_mmap directly, and we get rid of this inconsistency of having an mmap offset for a BO that can never be mmap-ed. Changes in v2: - Get rid of panthor_gem_mmap() - Get rid of the Fixes tag and adjust the commit message accordingly - Return ENOPERM instead of EINVAL Changes in v3: - Don't leak the BO ref - Add R-bs Reviewed-by: Steven Price Reviewed-by: Liviu Dudau Reviewed-by: Adrián Larumbe Link: https://lore.kernel.org/r/20250417121942.3574111-1-boris.brezillon@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_drv.c | 7 +++++++ drivers/gpu/drm/panthor/panthor_gem.c | 13 +------------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index 06fe46e32073..4d4a52a033f6 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -940,6 +940,7 @@ static int panthor_ioctl_bo_mmap_offset(struct drm_device *ddev, void *data, struct drm_file *file) { struct drm_panthor_bo_mmap_offset *args = data; + struct panthor_gem_object *bo; struct drm_gem_object *obj; int ret; @@ -950,6 +951,12 @@ static int panthor_ioctl_bo_mmap_offset(struct drm_device *ddev, void *data, if (!obj) return -ENOENT; + bo = to_panthor_bo(obj); + if (bo->flags & DRM_PANTHOR_BO_NO_MMAP) { + ret = -EPERM; + goto out; + } + ret = drm_gem_create_mmap_offset(obj); if (ret) goto out; diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index fd014ccc3bfc..22d78cef9c66 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -129,17 +129,6 @@ err_free_bo: return ERR_PTR(ret); } -static int panthor_gem_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) -{ - struct panthor_gem_object *bo = to_panthor_bo(obj); - - /* Don't allow mmap on objects that have the NO_MMAP flag set. */ - if (bo->flags & DRM_PANTHOR_BO_NO_MMAP) - return -EINVAL; - - return drm_gem_shmem_object_mmap(obj, vma); -} - static struct dma_buf * panthor_gem_prime_export(struct drm_gem_object *obj, int flags) { @@ -169,7 +158,7 @@ static const struct drm_gem_object_funcs panthor_gem_funcs = { .get_sg_table = drm_gem_shmem_object_get_sg_table, .vmap = drm_gem_shmem_object_vmap, .vunmap = drm_gem_shmem_object_vunmap, - .mmap = panthor_gem_mmap, + .mmap = drm_gem_shmem_object_mmap, .status = panthor_gem_status, .export = panthor_gem_prime_export, .vm_ops = &drm_gem_shmem_vm_ops, -- 2.51.0 From b1d6a89d7b75435da9c541c5f9d4df8268291c6e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 12 Apr 2025 07:12:54 +0100 Subject: [PATCH 05/16] drm: renesas: rz-du: rzg2l_mipi_dsi: Update the comment in rzg2l_mipi_dsi_start_video() Add missing space in the comment in rzg2l_mipi_dsi_start_video(). Reported-by: Pavel Machek Closes: https://lore.kernel.org/all/ZPg7STHDn4LbLy7f@duo.ucw.cz/ Signed-off-by: Biju Das Reviewed-by: Geert Uytterhoeven Reviewed-by: Laurent Pinchart Link: https://lore.kernel.org/r/20250412061258.5447-1-biju.das.jz@bp.renesas.com --- drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c index 96c014449547..dc6ab012cdb6 100644 --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c @@ -479,7 +479,7 @@ static int rzg2l_mipi_dsi_start_video(struct rzg2l_mipi_dsi *dsi) u32 status; int ret; - /* Configuration for Blanking sequence and start video input*/ + /* Configuration for Blanking sequence and start video input */ vich1set0r = VICH1SET0R_HFPNOLP | VICH1SET0R_HBPNOLP | VICH1SET0R_HSANOLP | VICH1SET0R_VSTART; rzg2l_mipi_dsi_link_write(dsi, VICH1SET0R, vich1set0r); -- 2.51.0 From b65cbfe0e1d8bcb74dbeb221d423dd926f326d05 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 1 Apr 2025 08:11:33 +0300 Subject: [PATCH 06/16] drm/bridge: analogix_dp: drop extra calls to analogix_dp_prepare_panel() The analogix_dp_prepare_panel() returns immediately if there is no attached panel. Drop several calls to this function which are performed when dp->plat_data->panel is NULL. Tested-by: Damon Ding Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250401-panel-return-void-v1-1-93e1be33dc8d@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- .../drm/bridge/analogix/analogix_dp_core.c | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 838454d6bdeb..2dd04f4d5494 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1005,17 +1005,11 @@ static int analogix_dp_get_modes(struct drm_connector *connector) { struct analogix_dp_device *dp = to_dp(connector); const struct drm_edid *drm_edid; - int ret, num_modes = 0; + int num_modes = 0; if (dp->plat_data->panel) { num_modes += drm_panel_get_modes(dp->plat_data->panel, connector); } else { - ret = analogix_dp_prepare_panel(dp, true, false); - if (ret) { - DRM_ERROR("Failed to prepare panel (%d)\n", ret); - return 0; - } - drm_edid = drm_edid_read_ddc(connector, &dp->aux.ddc); drm_edid_connector_update(&dp->connector, drm_edid); @@ -1024,10 +1018,6 @@ static int analogix_dp_get_modes(struct drm_connector *connector) num_modes += drm_edid_connector_add_modes(&dp->connector); drm_edid_free(drm_edid); } - - ret = analogix_dp_prepare_panel(dp, false, false); - if (ret) - DRM_ERROR("Failed to unprepare panel (%d)\n", ret); } if (dp->plat_data->get_modes) @@ -1087,19 +1077,9 @@ analogix_dp_detect(struct drm_connector *connector, bool force) if (dp->plat_data->panel) return connector_status_connected; - ret = analogix_dp_prepare_panel(dp, true, false); - if (ret) { - DRM_ERROR("Failed to prepare panel (%d)\n", ret); - return connector_status_disconnected; - } - if (!analogix_dp_detect_hpd(dp)) status = connector_status_connected; - ret = analogix_dp_prepare_panel(dp, false, false); - if (ret) - DRM_ERROR("Failed to unprepare panel (%d)\n", ret); - return status; } -- 2.51.0 From 0ce432e18c932a7fd219b9c2bf1db623fb0f7840 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 1 Apr 2025 08:11:34 +0300 Subject: [PATCH 07/16] drm/bridge: analogix_dp: drop unused argument to analogix_dp_prepare_panel() After previous cleanup all calling sites pass true as is_modeset_prepare argument to analogix_dp_prepare_panel(). Drop dead code depending on that argument being false. Tested-by: Damon Ding Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250401-panel-return-void-v1-2-93e1be33dc8d@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- .../drm/bridge/analogix/analogix_dp_core.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 2dd04f4d5494..20f356a22262 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -963,13 +963,13 @@ static int analogix_dp_disable_psr(struct analogix_dp_device *dp) * If @prepare is true, this function will prepare the panel. Conversely, if it * is false, the panel will be unprepared. * - * If @is_modeset_prepare is true, the function will disregard the current state + * The function will disregard the current state * of the panel and either prepare/unprepare the panel based on @prepare. Once * it finishes, it will update dp->panel_is_modeset to reflect the current state * of the panel. */ static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, - bool prepare, bool is_modeset_prepare) + bool prepare) { int ret = 0; @@ -978,13 +978,6 @@ static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, mutex_lock(&dp->panel_lock); - /* - * Exit early if this is a temporary prepare/unprepare and we're already - * modeset (since we neither want to prepare twice or unprepare early). - */ - if (dp->panel_is_modeset && !is_modeset_prepare) - goto out; - if (prepare) ret = drm_panel_prepare(dp->plat_data->panel); else @@ -993,8 +986,7 @@ static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, if (ret) goto out; - if (is_modeset_prepare) - dp->panel_is_modeset = prepare; + dp->panel_is_modeset = prepare; out: mutex_unlock(&dp->panel_lock); @@ -1072,7 +1064,6 @@ analogix_dp_detect(struct drm_connector *connector, bool force) { struct analogix_dp_device *dp = to_dp(connector); enum drm_connector_status status = connector_status_disconnected; - int ret; if (dp->plat_data->panel) return connector_status_connected; @@ -1194,7 +1185,7 @@ static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, if (old_crtc_state && old_crtc_state->self_refresh_active) return; - ret = analogix_dp_prepare_panel(dp, true, true); + ret = analogix_dp_prepare_panel(dp, true); if (ret) DRM_ERROR("failed to setup the panel ret = %d\n", ret); } @@ -1294,7 +1285,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) pm_runtime_put_sync(dp->dev); - ret = analogix_dp_prepare_panel(dp, false, true); + ret = analogix_dp_prepare_panel(dp, false); if (ret) DRM_ERROR("failed to setup the panel ret = %d\n", ret); -- 2.51.0 From 4fc72e1fc46b0dca74c1f8c94091e524ad5b9fdb Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 1 Apr 2025 08:11:35 +0300 Subject: [PATCH 08/16] drm/bridge: analogic_dp: drop panel_is_modeset The dp->panel_is_modeset is now a write-only field. Drop it completely. Tested-by: Damon Ding Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250401-panel-return-void-v1-3-93e1be33dc8d@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 11 +---------- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index 20f356a22262..f62035c50f35 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -964,9 +964,7 @@ static int analogix_dp_disable_psr(struct analogix_dp_device *dp) * is false, the panel will be unprepared. * * The function will disregard the current state - * of the panel and either prepare/unprepare the panel based on @prepare. Once - * it finishes, it will update dp->panel_is_modeset to reflect the current state - * of the panel. + * of the panel and either prepare/unprepare the panel based on @prepare. */ static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, bool prepare) @@ -983,12 +981,6 @@ static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, else ret = drm_panel_unprepare(dp->plat_data->panel); - if (ret) - goto out; - - dp->panel_is_modeset = prepare; - -out: mutex_unlock(&dp->panel_lock); return ret; } @@ -1556,7 +1548,6 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) dp->dpms_mode = DRM_MODE_DPMS_OFF; mutex_init(&dp->panel_lock); - dp->panel_is_modeset = false; /* * platform dp driver need containor_of the plat_data to get diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index 774d11574b09..b679d5b71d27 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -170,7 +170,6 @@ struct analogix_dp_device { bool psr_supported; struct mutex panel_lock; - bool panel_is_modeset; struct analogix_dp_plat_data *plat_data; }; -- 2.51.0 From 62ca1c3a146c73f8b8a381bf4461a82951defb8b Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 1 Apr 2025 08:11:36 +0300 Subject: [PATCH 09/16] drm/bridge: analogic_dp: drop panel_lock The analogix_dp_prepare_panel() function is called from bridge's atomic_pre_enable() and atomic_post_disable() callbacks, which can not happen simultaneously. Drop the useless mutex. Tested-by: Damon Ding Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250401-panel-return-void-v1-4-93e1be33dc8d@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 5 ----- drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 2 -- 2 files changed, 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index f62035c50f35..f411dd33e730 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -974,14 +974,11 @@ static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, if (!dp->plat_data->panel) return 0; - mutex_lock(&dp->panel_lock); - if (prepare) ret = drm_panel_prepare(dp->plat_data->panel); else ret = drm_panel_unprepare(dp->plat_data->panel); - mutex_unlock(&dp->panel_lock); return ret; } @@ -1547,8 +1544,6 @@ analogix_dp_probe(struct device *dev, struct analogix_dp_plat_data *plat_data) dp->dev = &pdev->dev; dp->dpms_mode = DRM_MODE_DPMS_OFF; - mutex_init(&dp->panel_lock); - /* * platform dp driver need containor_of the plat_data to get * the driver private data, so we need to store the point of diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h index b679d5b71d27..2b54120ba4a3 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h @@ -169,8 +169,6 @@ struct analogix_dp_device { bool fast_train_enable; bool psr_supported; - struct mutex panel_lock; - struct analogix_dp_plat_data *plat_data; }; -- 2.51.0 From d5f34ca5df7c0ae075fdfeba20edd6f81c792554 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 1 Apr 2025 08:11:37 +0300 Subject: [PATCH 10/16] drm/bridge: analogix_dp: inline analogix_dp_prepare_panel() The analogix_dp_prepare_panel() is now only calling a corresponding drm_panel function. Inline it to simplify the code. Tested-by: Damon Ding Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250401-panel-return-void-v1-5-93e1be33dc8d@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- .../drm/bridge/analogix/analogix_dp_core.c | 43 +++++-------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index f411dd33e730..ac49afc2169e 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -955,33 +955,6 @@ static int analogix_dp_disable_psr(struct analogix_dp_device *dp) return analogix_dp_send_psr_spd(dp, &psr_vsc, true); } -/* - * This function is a bit of a catch-all for panel preparation, hopefully - * simplifying the logic of functions that need to prepare/unprepare the panel - * below. - * - * If @prepare is true, this function will prepare the panel. Conversely, if it - * is false, the panel will be unprepared. - * - * The function will disregard the current state - * of the panel and either prepare/unprepare the panel based on @prepare. - */ -static int analogix_dp_prepare_panel(struct analogix_dp_device *dp, - bool prepare) -{ - int ret = 0; - - if (!dp->plat_data->panel) - return 0; - - if (prepare) - ret = drm_panel_prepare(dp->plat_data->panel); - else - ret = drm_panel_unprepare(dp->plat_data->panel); - - return ret; -} - static int analogix_dp_get_modes(struct drm_connector *connector) { struct analogix_dp_device *dp = to_dp(connector); @@ -1174,9 +1147,11 @@ static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, if (old_crtc_state && old_crtc_state->self_refresh_active) return; - ret = analogix_dp_prepare_panel(dp, true); - if (ret) - DRM_ERROR("failed to setup the panel ret = %d\n", ret); + if (dp->plat_data->panel) { + ret = drm_panel_prepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to prepare the panel ret = %d\n", ret); + } } static int analogix_dp_set_bridge(struct analogix_dp_device *dp) @@ -1274,9 +1249,11 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) pm_runtime_put_sync(dp->dev); - ret = analogix_dp_prepare_panel(dp, false); - if (ret) - DRM_ERROR("failed to setup the panel ret = %d\n", ret); + if (dp->plat_data->panel) { + ret = drm_panel_unprepare(dp->plat_data->panel); + if (ret) + DRM_ERROR("failed to unprepare the panel ret = %d\n", ret); + } dp->fast_train_enable = false; dp->psr_supported = false; -- 2.51.0 From 58a71d2bf103550f809987e16d8c1949be719040 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 1 Apr 2025 08:11:38 +0300 Subject: [PATCH 11/16] drm/bridge: analogix_dp: ignore return values of drm_panel_* calls Follow the example of other drivers and ignore return values of the drm_panel_prepare() / unprepare() / enable() / disable() calls. There is no possible error recovery, so the driver just logs a message. Tested-by: Damon Ding Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250401-panel-return-void-v1-6-93e1be33dc8d@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- .../drm/bridge/analogix/analogix_dp_core.c | 39 +++---------------- 1 file changed, 6 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index ac49afc2169e..a761941bc3c2 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -838,10 +838,7 @@ static int analogix_dp_commit(struct analogix_dp_device *dp) int ret; /* Keep the panel disabled while we configure video */ - if (dp->plat_data->panel) { - if (drm_panel_disable(dp->plat_data->panel)) - DRM_ERROR("failed to disable the panel\n"); - } + drm_panel_disable(dp->plat_data->panel); ret = analogix_dp_train_link(dp); if (ret) { @@ -863,13 +860,7 @@ static int analogix_dp_commit(struct analogix_dp_device *dp) } /* Safe to enable the panel now */ - if (dp->plat_data->panel) { - ret = drm_panel_enable(dp->plat_data->panel); - if (ret) { - DRM_ERROR("failed to enable the panel\n"); - return ret; - } - } + drm_panel_enable(dp->plat_data->panel); /* Check whether panel supports fast training */ ret = analogix_dp_fast_link_train_detection(dp); @@ -1136,7 +1127,6 @@ static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; - int ret; crtc = analogix_dp_get_new_crtc(dp, old_state); if (!crtc) @@ -1147,11 +1137,7 @@ static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, if (old_crtc_state && old_crtc_state->self_refresh_active) return; - if (dp->plat_data->panel) { - ret = drm_panel_prepare(dp->plat_data->panel); - if (ret) - DRM_ERROR("failed to prepare the panel ret = %d\n", ret); - } + drm_panel_prepare(dp->plat_data->panel); } static int analogix_dp_set_bridge(struct analogix_dp_device *dp) @@ -1231,17 +1217,11 @@ static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, static void analogix_dp_bridge_disable(struct drm_bridge *bridge) { struct analogix_dp_device *dp = bridge->driver_private; - int ret; if (dp->dpms_mode != DRM_MODE_DPMS_ON) return; - if (dp->plat_data->panel) { - if (drm_panel_disable(dp->plat_data->panel)) { - DRM_ERROR("failed to disable the panel\n"); - return; - } - } + drm_panel_disable(dp->plat_data->panel); disable_irq(dp->irq); @@ -1249,11 +1229,7 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) pm_runtime_put_sync(dp->dev); - if (dp->plat_data->panel) { - ret = drm_panel_unprepare(dp->plat_data->panel); - if (ret) - DRM_ERROR("failed to unprepare the panel ret = %d\n", ret); - } + drm_panel_unprepare(dp->plat_data->panel); dp->fast_train_enable = false; dp->psr_supported = false; @@ -1694,10 +1670,7 @@ void analogix_dp_unbind(struct analogix_dp_device *dp) analogix_dp_bridge_disable(dp->bridge); dp->connector.funcs->destroy(&dp->connector); - if (dp->plat_data->panel) { - if (drm_panel_unprepare(dp->plat_data->panel)) - DRM_ERROR("failed to turnoff the panel\n"); - } + drm_panel_unprepare(dp->plat_data->panel); drm_dp_aux_unregister(&dp->aux); } -- 2.51.0 From dcbd5dcc956e2331414fd7020b4655df08deeb87 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Tue, 1 Apr 2025 08:11:39 +0300 Subject: [PATCH 12/16] drm/panel: make prepare/enable and disable/unprepare calls return void Now there are no users of the return value of the drm_panel_prepare(), drm_panel_unprepare(), drm_panel_enable() and drm_panel_disable() calls. Usually these calls are performed from the atomic callbacks, where it is impossible to return an error. Stop returning error codes and return void instead. Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20250401-panel-return-void-v1-7-93e1be33dc8d@oss.qualcomm.com Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/drm_panel.c | 54 +++++++------------ .../gpu/drm/panel/panel-newvision-nv3051d.c | 9 +--- include/drm/drm_panel.h | 8 +-- 3 files changed, 26 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index 99b348782ce3..650de4da0853 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -106,21 +106,21 @@ EXPORT_SYMBOL(drm_panel_remove); * * Calling this function will enable power and deassert any reset signals to * the panel. After this has completed it is possible to communicate with any - * integrated circuitry via a command bus. - * - * Return: 0 on success or a negative error code on failure. + * integrated circuitry via a command bus. This function cannot fail (as it is + * called from the pre_enable call chain). There will always be a call to + * drm_panel_disable() afterwards. */ -int drm_panel_prepare(struct drm_panel *panel) +void drm_panel_prepare(struct drm_panel *panel) { struct drm_panel_follower *follower; int ret; if (!panel) - return -EINVAL; + return; if (panel->prepared) { dev_warn(panel->dev, "Skipping prepare of already prepared panel\n"); - return 0; + return; } mutex_lock(&panel->follower_lock); @@ -139,11 +139,8 @@ int drm_panel_prepare(struct drm_panel *panel) follower->funcs->panel_prepared, ret); } - ret = 0; exit: mutex_unlock(&panel->follower_lock); - - return ret; } EXPORT_SYMBOL(drm_panel_prepare); @@ -155,16 +152,14 @@ EXPORT_SYMBOL(drm_panel_prepare); * reset, turn off power supplies, ...). After this function has completed, it * is usually no longer possible to communicate with the panel until another * call to drm_panel_prepare(). - * - * Return: 0 on success or a negative error code on failure. */ -int drm_panel_unprepare(struct drm_panel *panel) +void drm_panel_unprepare(struct drm_panel *panel) { struct drm_panel_follower *follower; int ret; if (!panel) - return -EINVAL; + return; /* * If you are seeing the warning below it likely means one of two things: @@ -177,7 +172,7 @@ int drm_panel_unprepare(struct drm_panel *panel) */ if (!panel->prepared) { dev_warn(panel->dev, "Skipping unprepare of already unprepared panel\n"); - return 0; + return; } mutex_lock(&panel->follower_lock); @@ -196,11 +191,8 @@ int drm_panel_unprepare(struct drm_panel *panel) } panel->prepared = false; - ret = 0; exit: mutex_unlock(&panel->follower_lock); - - return ret; } EXPORT_SYMBOL(drm_panel_unprepare); @@ -210,26 +202,26 @@ EXPORT_SYMBOL(drm_panel_unprepare); * * Calling this function will cause the panel display drivers to be turned on * and the backlight to be enabled. Content will be visible on screen after - * this call completes. - * - * Return: 0 on success or a negative error code on failure. + * this call completes. This function cannot fail (as it is called from the + * enable call chain). There will always be a call to drm_panel_disable() + * afterwards. */ -int drm_panel_enable(struct drm_panel *panel) +void drm_panel_enable(struct drm_panel *panel) { int ret; if (!panel) - return -EINVAL; + return; if (panel->enabled) { dev_warn(panel->dev, "Skipping enable of already enabled panel\n"); - return 0; + return; } if (panel->funcs && panel->funcs->enable) { ret = panel->funcs->enable(panel); if (ret < 0) - return ret; + return; } panel->enabled = true; @@ -237,8 +229,6 @@ int drm_panel_enable(struct drm_panel *panel) if (ret < 0) DRM_DEV_INFO(panel->dev, "failed to enable backlight: %d\n", ret); - - return 0; } EXPORT_SYMBOL(drm_panel_enable); @@ -249,15 +239,13 @@ EXPORT_SYMBOL(drm_panel_enable); * This will typically turn off the panel's backlight or disable the display * drivers. For smart panels it should still be possible to communicate with * the integrated circuitry via any command bus after this call. - * - * Return: 0 on success or a negative error code on failure. */ -int drm_panel_disable(struct drm_panel *panel) +void drm_panel_disable(struct drm_panel *panel) { int ret; if (!panel) - return -EINVAL; + return; /* * If you are seeing the warning below it likely means one of two things: @@ -270,7 +258,7 @@ int drm_panel_disable(struct drm_panel *panel) */ if (!panel->enabled) { dev_warn(panel->dev, "Skipping disable of already disabled panel\n"); - return 0; + return; } ret = backlight_disable(panel->backlight); @@ -281,11 +269,9 @@ int drm_panel_disable(struct drm_panel *panel) if (panel->funcs && panel->funcs->disable) { ret = panel->funcs->disable(panel); if (ret < 0) - return ret; + return; } panel->enabled = false; - - return 0; } EXPORT_SYMBOL(drm_panel_disable); diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c index 5d115ecd5dd4..b6429795e8f5 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c @@ -413,15 +413,10 @@ static int panel_nv3051d_probe(struct mipi_dsi_device *dsi) static void panel_nv3051d_shutdown(struct mipi_dsi_device *dsi) { struct panel_nv3051d *ctx = mipi_dsi_get_drvdata(dsi); - int ret; - ret = drm_panel_unprepare(&ctx->panel); - if (ret < 0) - dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret); + drm_panel_unprepare(&ctx->panel); - ret = drm_panel_disable(&ctx->panel); - if (ret < 0) - dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret); + drm_panel_disable(&ctx->panel); } static void panel_nv3051d_remove(struct mipi_dsi_device *dsi) diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 31d84f901c51..843fb756a295 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -316,11 +316,11 @@ void drm_panel_put(struct drm_panel *panel); void drm_panel_add(struct drm_panel *panel); void drm_panel_remove(struct drm_panel *panel); -int drm_panel_prepare(struct drm_panel *panel); -int drm_panel_unprepare(struct drm_panel *panel); +void drm_panel_prepare(struct drm_panel *panel); +void drm_panel_unprepare(struct drm_panel *panel); -int drm_panel_enable(struct drm_panel *panel); -int drm_panel_disable(struct drm_panel *panel); +void drm_panel_enable(struct drm_panel *panel); +void drm_panel_disable(struct drm_panel *panel); int drm_panel_get_modes(struct drm_panel *panel, struct drm_connector *connector); -- 2.51.0 From b848cd418aebdb313364b4843f41fae82281a823 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 18 Apr 2025 08:48:16 +0200 Subject: [PATCH 13/16] drm/bridge: lt9611uxc: Fix an error handling path in lt9611uxc_probe() If lt9611uxc_audio_init() fails, some resources still need to be released before returning the error code. Use the existing error handling path. Fixes: 0cbbd5b1a012 ("drm: bridge: add support for lontium LT9611UXC bridge") Signed-off-by: Christophe JAILLET Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/f167608e392c6b4d7d7f6e45e3c21878feb60cbd.1744958833.git.christophe.jaillet@wanadoo.fr Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 20bf1a3c786d..bb33c30d3f88 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -881,7 +881,11 @@ retry: } } - return lt9611uxc_audio_init(dev, lt9611uxc); + ret = lt9611uxc_audio_init(dev, lt9611uxc); + if (ret) + goto err_remove_bridge; + + return 0; err_remove_bridge: free_irq(client->irq, lt9611uxc); -- 2.51.0 From db49d7f1ccdb1599154af263ef55ac282bccb6a4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Adri=C3=A1n=20Larumbe?= Date: Wed, 23 Apr 2025 03:12:31 +0100 Subject: [PATCH 14/16] drm/panthor: Introduce BO labeling MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Add a new character string Panthor BO field, and a function that allows setting it from within the driver. Driver takes care of freeing the string when it's replaced or no longer needed at object destruction time, but allocating it is the responsibility of callers. Signed-off-by: Adrián Larumbe Reviewed-by: Boris Brezillon Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://lore.kernel.org/r/20250423021238.1639175-2-adrian.larumbe@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_gem.c | 46 +++++++++++++++++++++++++++ drivers/gpu/drm/panthor/panthor_gem.h | 17 ++++++++++ 2 files changed, 63 insertions(+) diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 22d78cef9c66..4c9d52378d1c 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -2,6 +2,7 @@ /* Copyright 2019 Linaro, Ltd, Rob Herring */ /* Copyright 2023 Collabora ltd. */ +#include #include #include #include @@ -18,6 +19,14 @@ static void panthor_gem_free_object(struct drm_gem_object *obj) struct panthor_gem_object *bo = to_panthor_bo(obj); struct drm_gem_object *vm_root_gem = bo->exclusive_vm_root_gem; + /* + * Label might have been allocated with kstrdup_const(), + * we need to take that into account when freeing the memory + */ + kfree_const(bo->label.str); + + mutex_destroy(&bo->label.lock); + drm_gem_free_mmap_offset(&bo->base.base); mutex_destroy(&bo->gpuva_list_lock); drm_gem_shmem_free(&bo->base); @@ -185,6 +194,7 @@ struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t obj->base.map_wc = !ptdev->coherent; mutex_init(&obj->gpuva_list_lock); drm_gem_gpuva_set_lock(&obj->base.base, &obj->gpuva_list_lock); + mutex_init(&obj->label.lock); return &obj->base.base; } @@ -236,3 +246,39 @@ panthor_gem_create_with_handle(struct drm_file *file, return ret; } + +void +panthor_gem_bo_set_label(struct drm_gem_object *obj, const char *label) +{ + struct panthor_gem_object *bo = to_panthor_bo(obj); + const char *old_label; + + scoped_guard(mutex, &bo->label.lock) { + old_label = bo->label.str; + bo->label.str = label; + } + + kfree_const(old_label); +} + +void +panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label) +{ + const char *str; + + /* We should never attempt labelling a UM-exposed GEM object */ + if (drm_WARN_ON(bo->obj->dev, bo->obj->handle_count > 0)) + return; + + if (!label) + return; + + str = kstrdup_const(label, GFP_KERNEL); + if (!str) { + /* Failing to allocate memory for a label isn't a fatal condition */ + drm_warn(bo->obj->dev, "Not enough memory to allocate BO label"); + return; + } + + panthor_gem_bo_set_label(bo->obj, str); +} diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index 1a363bb814f4..af0d77338860 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -46,6 +46,20 @@ struct panthor_gem_object { /** @flags: Combination of drm_panthor_bo_flags flags. */ u32 flags; + + /** + * @label: BO tagging fields. The label can be assigned within the + * driver itself or through a specific IOCTL. + */ + struct { + /** + * @label.str: Pointer to NULL-terminated string, + */ + const char *str; + + /** @lock.str: Protects access to the @label.str field. */ + struct mutex lock; + } label; }; /** @@ -91,6 +105,9 @@ panthor_gem_create_with_handle(struct drm_file *file, struct panthor_vm *exclusive_vm, u64 *size, u32 flags, uint32_t *handle); +void panthor_gem_bo_set_label(struct drm_gem_object *obj, const char *label); +void panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label); + static inline u64 panthor_kernel_bo_gpuva(struct panthor_kernel_bo *bo) { -- 2.51.0 From a572dc467de241706ab92d61b3b3a0bca93450c8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Adri=C3=A1n=20Larumbe?= Date: Wed, 23 Apr 2025 03:12:32 +0100 Subject: [PATCH 15/16] drm/panthor: Add driver IOCTL for setting BO labels MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Allow UM to label a BO for which it possesses a DRM handle. Signed-off-by: Adrián Larumbe Reviewed-by: Liviu Dudau Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Link: https://lore.kernel.org/r/20250423021238.1639175-3-adrian.larumbe@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_drv.c | 44 ++++++++++++++++++++++++++- drivers/gpu/drm/panthor/panthor_gem.h | 2 ++ include/uapi/drm/panthor_drm.h | 23 ++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panthor/panthor_drv.c b/drivers/gpu/drm/panthor/panthor_drv.c index 4d4a52a033f6..32c956d4c366 100644 --- a/drivers/gpu/drm/panthor/panthor_drv.c +++ b/drivers/gpu/drm/panthor/panthor_drv.c @@ -1338,6 +1338,46 @@ static int panthor_ioctl_vm_get_state(struct drm_device *ddev, void *data, return 0; } +static int panthor_ioctl_bo_set_label(struct drm_device *ddev, void *data, + struct drm_file *file) +{ + struct drm_panthor_bo_set_label *args = data; + struct drm_gem_object *obj; + const char *label = NULL; + int ret = 0; + + if (args->pad) + return -EINVAL; + + obj = drm_gem_object_lookup(file, args->handle); + if (!obj) + return -ENOENT; + + if (args->label) { + label = strndup_user((const char __user *)(uintptr_t)args->label, + PANTHOR_BO_LABEL_MAXLEN); + if (IS_ERR(label)) { + ret = PTR_ERR(label); + if (ret == -EINVAL) + ret = -E2BIG; + goto err_put_obj; + } + } + + /* + * We treat passing a label of length 0 and passing a NULL label + * differently, because even though they might seem conceptually + * similar, future uses of the BO label might expect a different + * behaviour in each case. + */ + panthor_gem_bo_set_label(obj, label); + +err_put_obj: + drm_gem_object_put(obj); + + return ret; +} + static int panthor_open(struct drm_device *ddev, struct drm_file *file) { @@ -1407,6 +1447,7 @@ static const struct drm_ioctl_desc panthor_drm_driver_ioctls[] = { PANTHOR_IOCTL(TILER_HEAP_CREATE, tiler_heap_create, DRM_RENDER_ALLOW), PANTHOR_IOCTL(TILER_HEAP_DESTROY, tiler_heap_destroy, DRM_RENDER_ALLOW), PANTHOR_IOCTL(GROUP_SUBMIT, group_submit, DRM_RENDER_ALLOW), + PANTHOR_IOCTL(BO_SET_LABEL, bo_set_label, DRM_RENDER_ALLOW), }; static int panthor_mmap(struct file *filp, struct vm_area_struct *vma) @@ -1516,6 +1557,7 @@ static void panthor_debugfs_init(struct drm_minor *minor) * - 1.2 - adds DEV_QUERY_GROUP_PRIORITIES_INFO query * - adds PANTHOR_GROUP_PRIORITY_REALTIME priority * - 1.3 - adds DRM_PANTHOR_GROUP_STATE_INNOCENT flag + * - 1.4 - adds DRM_IOCTL_PANTHOR_BO_SET_LABEL ioctl */ static const struct drm_driver panthor_drm_driver = { .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ | @@ -1529,7 +1571,7 @@ static const struct drm_driver panthor_drm_driver = { .name = "panthor", .desc = "Panthor DRM driver", .major = 1, - .minor = 3, + .minor = 4, .gem_create_object = panthor_gem_create_object, .gem_prime_import_sg_table = drm_gem_shmem_prime_import_sg_table, diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index af0d77338860..983cc8ca264e 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -13,6 +13,8 @@ struct panthor_vm; +#define PANTHOR_BO_LABEL_MAXLEN 4096 + /** * struct panthor_gem_object - Driver specific GEM object. */ diff --git a/include/uapi/drm/panthor_drm.h b/include/uapi/drm/panthor_drm.h index 97e2c4510e69..ad9a70afea6c 100644 --- a/include/uapi/drm/panthor_drm.h +++ b/include/uapi/drm/panthor_drm.h @@ -127,6 +127,9 @@ enum drm_panthor_ioctl_id { /** @DRM_PANTHOR_TILER_HEAP_DESTROY: Destroy a tiler heap. */ DRM_PANTHOR_TILER_HEAP_DESTROY, + + /** @DRM_PANTHOR_BO_SET_LABEL: Label a BO. */ + DRM_PANTHOR_BO_SET_LABEL, }; /** @@ -977,6 +980,24 @@ struct drm_panthor_tiler_heap_destroy { __u32 pad; }; +/** + * struct drm_panthor_bo_set_label - Arguments passed to DRM_IOCTL_PANTHOR_BO_SET_LABEL + */ +struct drm_panthor_bo_set_label { + /** @handle: Handle of the buffer object to label. */ + __u32 handle; + + /** @pad: MBZ. */ + __u32 pad; + + /** + * @label: User pointer to a NUL-terminated string + * + * Length cannot be greater than 4096 + */ + __u64 label; +}; + /** * DRM_IOCTL_PANTHOR() - Build a Panthor IOCTL number * @__access: Access type. Must be R, W or RW. @@ -1019,6 +1040,8 @@ enum { DRM_IOCTL_PANTHOR(WR, TILER_HEAP_CREATE, tiler_heap_create), DRM_IOCTL_PANTHOR_TILER_HEAP_DESTROY = DRM_IOCTL_PANTHOR(WR, TILER_HEAP_DESTROY, tiler_heap_destroy), + DRM_IOCTL_PANTHOR_BO_SET_LABEL = + DRM_IOCTL_PANTHOR(WR, BO_SET_LABEL, bo_set_label), }; #if defined(__cplusplus) -- 2.51.0 From 0489149fd6711a8a020a8500029d4ee971c541ba Mon Sep 17 00:00:00 2001 From: =?utf8?q?Adri=C3=A1n=20Larumbe?= Date: Wed, 23 Apr 2025 03:12:33 +0100 Subject: [PATCH 16/16] drm/panthor: Label all kernel BO's MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Kernel BO's aren't exposed to UM, so labelling them is the responsibility of the driver itself. This kind of tagging will prove useful in further commits when want to expose these objects through DebugFS. Expand panthor_kernel_bo_create() interface to take a NUL-terminated string. No bounds checking is done because all label strings are given as statically-allocated literals, but if a more complex kernel BO naming scheme with explicit memory allocation and formatting was desired in the future, this would have to change. Signed-off-by: Adrián Larumbe Reviewed-by: Boris Brezillon Reviewed-by: Liviu Dudau Reviewed-by: Steven Price Link: https://lore.kernel.org/r/20250423021238.1639175-4-adrian.larumbe@collabora.com Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panthor/panthor_fw.c | 8 +++++--- drivers/gpu/drm/panthor/panthor_gem.c | 5 ++++- drivers/gpu/drm/panthor/panthor_gem.h | 2 +- drivers/gpu/drm/panthor/panthor_heap.c | 6 ++++-- drivers/gpu/drm/panthor/panthor_sched.c | 9 ++++++--- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index 446bb377b953..7bc38e635329 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -449,7 +449,8 @@ panthor_fw_alloc_queue_iface_mem(struct panthor_device *ptdev, DRM_PANTHOR_BO_NO_MMAP, DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC | DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED, - PANTHOR_VM_KERNEL_AUTO_VA); + PANTHOR_VM_KERNEL_AUTO_VA, + "Queue FW interface"); if (IS_ERR(mem)) return mem; @@ -481,7 +482,8 @@ panthor_fw_alloc_suspend_buf_mem(struct panthor_device *ptdev, size_t size) return panthor_kernel_bo_create(ptdev, panthor_fw_vm(ptdev), size, DRM_PANTHOR_BO_NO_MMAP, DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC, - PANTHOR_VM_KERNEL_AUTO_VA); + PANTHOR_VM_KERNEL_AUTO_VA, + "FW suspend buffer"); } static int panthor_fw_load_section_entry(struct panthor_device *ptdev, @@ -601,7 +603,7 @@ static int panthor_fw_load_section_entry(struct panthor_device *ptdev, section->mem = panthor_kernel_bo_create(ptdev, panthor_fw_vm(ptdev), section_size, DRM_PANTHOR_BO_NO_MMAP, - vm_map_flags, va); + vm_map_flags, va, "FW section"); if (IS_ERR(section->mem)) return PTR_ERR(section->mem); diff --git a/drivers/gpu/drm/panthor/panthor_gem.c b/drivers/gpu/drm/panthor/panthor_gem.c index 4c9d52378d1c..a61a50d8d5f5 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.c +++ b/drivers/gpu/drm/panthor/panthor_gem.c @@ -76,13 +76,14 @@ out_free_bo: * @gpu_va: GPU address assigned when mapping to the VM. * If gpu_va == PANTHOR_VM_KERNEL_AUTO_VA, the virtual address will be * automatically allocated. + * @name: Descriptive label of the BO's contents * * Return: A valid pointer in case of success, an ERR_PTR() otherwise. */ struct panthor_kernel_bo * panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, size_t size, u32 bo_flags, u32 vm_map_flags, - u64 gpu_va) + u64 gpu_va, const char *name) { struct drm_gem_shmem_object *obj; struct panthor_kernel_bo *kbo; @@ -106,6 +107,8 @@ panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, kbo->obj = &obj->base; bo->flags = bo_flags; + panthor_gem_kernel_bo_set_label(kbo, name); + /* The system and GPU MMU page size might differ, which becomes a * problem for FW sections that need to be mapped at explicit address * since our PAGE_SIZE alignment might cover a VA range that's diff --git a/drivers/gpu/drm/panthor/panthor_gem.h b/drivers/gpu/drm/panthor/panthor_gem.h index 983cc8ca264e..3c09af568e47 100644 --- a/drivers/gpu/drm/panthor/panthor_gem.h +++ b/drivers/gpu/drm/panthor/panthor_gem.h @@ -153,7 +153,7 @@ panthor_kernel_bo_vunmap(struct panthor_kernel_bo *bo) struct panthor_kernel_bo * panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm, size_t size, u32 bo_flags, u32 vm_map_flags, - u64 gpu_va); + u64 gpu_va, const char *name); void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo); diff --git a/drivers/gpu/drm/panthor/panthor_heap.c b/drivers/gpu/drm/panthor/panthor_heap.c index 3bdf61c14264..d236e9ceade4 100644 --- a/drivers/gpu/drm/panthor/panthor_heap.c +++ b/drivers/gpu/drm/panthor/panthor_heap.c @@ -151,7 +151,8 @@ static int panthor_alloc_heap_chunk(struct panthor_heap_pool *pool, chunk->bo = panthor_kernel_bo_create(pool->ptdev, pool->vm, heap->chunk_size, DRM_PANTHOR_BO_NO_MMAP, DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC, - PANTHOR_VM_KERNEL_AUTO_VA); + PANTHOR_VM_KERNEL_AUTO_VA, + "Tiler heap chunk"); if (IS_ERR(chunk->bo)) { ret = PTR_ERR(chunk->bo); goto err_free_chunk; @@ -555,7 +556,8 @@ panthor_heap_pool_create(struct panthor_device *ptdev, struct panthor_vm *vm) pool->gpu_contexts = panthor_kernel_bo_create(ptdev, vm, bosize, DRM_PANTHOR_BO_NO_MMAP, DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC, - PANTHOR_VM_KERNEL_AUTO_VA); + PANTHOR_VM_KERNEL_AUTO_VA, + "Heap pool"); if (IS_ERR(pool->gpu_contexts)) { ret = PTR_ERR(pool->gpu_contexts); goto err_destroy_pool; diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 446ec780eb4a..43ee57728de5 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -3332,7 +3332,8 @@ group_create_queue(struct panthor_group *group, DRM_PANTHOR_BO_NO_MMAP, DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC | DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED, - PANTHOR_VM_KERNEL_AUTO_VA); + PANTHOR_VM_KERNEL_AUTO_VA, + "CS ring buffer"); if (IS_ERR(queue->ringbuf)) { ret = PTR_ERR(queue->ringbuf); goto err_free_queue; @@ -3362,7 +3363,8 @@ group_create_queue(struct panthor_group *group, DRM_PANTHOR_BO_NO_MMAP, DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC | DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED, - PANTHOR_VM_KERNEL_AUTO_VA); + PANTHOR_VM_KERNEL_AUTO_VA, + "Group job stats"); if (IS_ERR(queue->profiling.slots)) { ret = PTR_ERR(queue->profiling.slots); @@ -3493,7 +3495,8 @@ int panthor_group_create(struct panthor_file *pfile, DRM_PANTHOR_BO_NO_MMAP, DRM_PANTHOR_VM_BIND_OP_MAP_NOEXEC | DRM_PANTHOR_VM_BIND_OP_MAP_UNCACHED, - PANTHOR_VM_KERNEL_AUTO_VA); + PANTHOR_VM_KERNEL_AUTO_VA, + "Group sync objects"); if (IS_ERR(group->syncobjs)) { ret = PTR_ERR(group->syncobjs); goto err_put_group; -- 2.51.0