From 8cecb9a2cd4296cf887d79cb7707077d6c647cc3 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Mon, 31 Mar 2025 11:15:25 -0400 Subject: [PATCH 1/9] FROMLIST drm/panel: Add new helpers for refcounted panel allocatons Introduce reference counted allocations for panels to avoid use-after-free. The patch adds the macro devm_drm_bridge_alloc() to allocate a new refcounted panel. Followed the documentation for drmm_encoder_alloc() and devm_drm_dev_alloc and other similar implementations for this purpose. Reviewed-by: Maxime Ripard Signed-off-by: Anusha Srivatsa --- drivers/gpu/drm/drm_panel.c | 25 +++++++++++++++++++++++++ include/drm/drm_panel.h | 22 ++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index c627e42a7ce704..bdeab5710ee324 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -355,6 +355,31 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np) } EXPORT_SYMBOL(of_drm_find_panel); +void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset, + const struct drm_panel_funcs *funcs, + int connector_type) +{ + void *container; + struct drm_panel *panel; + + if (!funcs) { + dev_warn(dev, "Missing funcs pointer\n"); + return ERR_PTR(-EINVAL); + } + + container = devm_kzalloc(dev, size, GFP_KERNEL); + if (!container) + return ERR_PTR(-ENOMEM); + + panel = container + offset; + panel->funcs = funcs; + + drm_panel_init(panel, dev, funcs, connector_type); + + return container; +} +EXPORT_SYMBOL(__devm_drm_panel_alloc); + /** * of_drm_get_panel_orientation - look up the orientation of the panel through * the "rotation" binding from a device tree node diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index a9c042c8dea1a8..415e85e8b76a15 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -268,6 +268,28 @@ struct drm_panel { bool enabled; }; +void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset, + const struct drm_panel_funcs *funcs, + int connector_type); + +/** + * devm_drm_panel_alloc - Allocate and initialize a refcounted panel. + * + * @dev: struct device of the panel device + * @type: the type of the struct which contains struct &drm_panel + * @member: the name of the &drm_panel within @type + * @funcs: callbacks for this panel + * @connector_type: the connector type (DRM_MODE_CONNECTOR_*) corresponding to + * the panel interface + * + * Returns: + * Pointer to container structure embedding the panel, ERR_PTR on failure. + */ +#define devm_drm_panel_alloc(dev, type, member, funcs, connector_type) \ + ((type *)__devm_drm_panel_alloc(dev, sizeof(type), \ + offsetof(type, member), funcs, \ + connector_type)) + void drm_panel_init(struct drm_panel *panel, struct device *dev, const struct drm_panel_funcs *funcs, int connector_type); From 47bdaa145623e64dbcfc4d8d0944a8299bbc27c6 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Mon, 31 Mar 2025 11:15:26 -0400 Subject: [PATCH 2/9] FROMLIST drm/panel: Add refcount support Allocate panel via reference counting. Add _get() and _put() helper functions to ensure panel allocations are refcounted. Avoid use after free by ensuring panel pointer is valid and can be usable till the last reference is put. Reviewed-by: Luca Ceresoli Reviewed-by: Maxime Ripard Signed-off-by: Anusha Srivatsa --- drivers/gpu/drm/drm_panel.c | 64 ++++++++++++++++++++++++++++++++++++- include/drm/drm_panel.h | 19 +++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index bdeab5710ee324..7b17531d85a4dc 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -355,24 +355,86 @@ struct drm_panel *of_drm_find_panel(const struct device_node *np) } EXPORT_SYMBOL(of_drm_find_panel); +static void __drm_panel_free(struct kref *kref) +{ + struct drm_panel *panel = container_of(kref, struct drm_panel, refcount); + + kfree(panel->container); +} + +/** + * drm_panel_get - Acquire a panel reference + * @panel: DRM panel + * + * This function increments the panel's refcount. + * Returns: + * Pointer to @panel + */ +struct drm_panel *drm_panel_get(struct drm_panel *panel) +{ + if (!panel) + return panel; + + kref_get(&panel->refcount); + + return panel; +} +EXPORT_SYMBOL(drm_panel_get); + +/** + * drm_panel_put - Release a panel reference + * @panel: DRM panel + * + * This function decrements the panel's reference count and frees the + * object if the reference count drops to zero. + */ +void drm_panel_put(struct drm_panel *panel) +{ + if (panel) + kref_put(&panel->refcount, __drm_panel_free); +} +EXPORT_SYMBOL(drm_panel_put); + +/** + * drm_panel_put_void - wrapper to drm_panel_put() taking a void pointer + * + * @data: pointer to @struct drm_panel, cast to a void pointer + * + * Wrapper of drm_panel_put() to be used when a function taking a void + * pointer is needed, for example as a devm action. + */ +static void drm_panel_put_void(void *data) +{ + struct drm_panel *panel = (struct drm_panel *)data; + + drm_panel_put(panel); +} + void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset, const struct drm_panel_funcs *funcs, int connector_type) { void *container; struct drm_panel *panel; + int err; if (!funcs) { dev_warn(dev, "Missing funcs pointer\n"); return ERR_PTR(-EINVAL); } - container = devm_kzalloc(dev, size, GFP_KERNEL); + container = kzalloc(size, GFP_KERNEL); if (!container) return ERR_PTR(-ENOMEM); panel = container + offset; + panel->container = container; panel->funcs = funcs; + kref_init(&panel->refcount); + + err = devm_add_action_or_reset(dev, drm_panel_put_void, panel); + if (err) + return ERR_PTR(err); drm_panel_init(panel, dev, funcs, connector_type); diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h index 415e85e8b76a15..31d84f901c514c 100644 --- a/include/drm/drm_panel.h +++ b/include/drm/drm_panel.h @@ -28,6 +28,7 @@ #include #include #include +#include struct backlight_device; struct dentry; @@ -266,6 +267,17 @@ struct drm_panel { * If true then the panel has been enabled. */ bool enabled; + + /** + * @container: Pointer to the private driver struct embedding this + * @struct drm_panel. + */ + void *container; + + /** + * @refcount: reference count of users referencing this panel. + */ + struct kref refcount; }; void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset, @@ -282,6 +294,10 @@ void *__devm_drm_panel_alloc(struct device *dev, size_t size, size_t offset, * @connector_type: the connector type (DRM_MODE_CONNECTOR_*) corresponding to * the panel interface * + * The reference count of the returned panel is initialized to 1. This + * reference will be automatically dropped via devm (by calling + * drm_panel_put()) when @dev is removed. + * * Returns: * Pointer to container structure embedding the panel, ERR_PTR on failure. */ @@ -294,6 +310,9 @@ void drm_panel_init(struct drm_panel *panel, struct device *dev, const struct drm_panel_funcs *funcs, int connector_type); +struct drm_panel *drm_panel_get(struct drm_panel *panel); +void drm_panel_put(struct drm_panel *panel); + void drm_panel_add(struct drm_panel *panel); void drm_panel_remove(struct drm_panel *panel); From 7fd11f0be237b1968c4dc740208a0121384fee65 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Mon, 31 Mar 2025 11:15:27 -0400 Subject: [PATCH 3/9] FROMLIST drm/panel: deprecate old-style panel allocation Start moving to the new refcounted allocations using the new API devm_drm_panel_alloc(). Deprecate any other allocation. Reviewed-by: Luca Ceresoli Reviewed-by: Maxime Ripard Signed-off-by: Anusha Srivatsa --- drivers/gpu/drm/drm_panel.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c index 7b17531d85a4dc..870bf8d471ee9c 100644 --- a/drivers/gpu/drm/drm_panel.c +++ b/drivers/gpu/drm/drm_panel.c @@ -74,8 +74,9 @@ EXPORT_SYMBOL(drm_panel_init); * drm_panel_add - add a panel to the global registry * @panel: panel to add * - * Add a panel to the global registry so that it can be looked up by display - * drivers. + * Add a panel to the global registry so that it can be looked + * up by display drivers. The panel to be added must have been + * allocated by devm_drm_panel_alloc(). */ void drm_panel_add(struct drm_panel *panel) { From 861238a27ed4339dcc05dc6cc7a0c91fbabb5537 Mon Sep 17 00:00:00 2001 From: Anusha Srivatsa Date: Mon, 31 Mar 2025 11:15:28 -0400 Subject: [PATCH 4/9] FROMLIST drm/panel/panel-simple: Use the new allocation in place of devm_kzalloc() Start using the new helper that does the refcounted allocations. Reviewed-by: Luca Ceresoli Reviewed-by: Maxime Ripard Signed-off-by: Anusha Srivatsa --- drivers/gpu/drm/panel/panel-simple.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index ae0b431410cdcc..cd8e4e43954585 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -579,9 +579,10 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) u32 bus_flags; int err; - panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); - if (!panel) - return -ENOMEM; + panel = devm_drm_panel_alloc(dev, struct panel_simple, base, + &panel_simple_funcs, desc->connector_type); + if (IS_ERR(panel)) + return PTR_ERR(panel); panel->desc = desc; @@ -694,8 +695,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); - drm_panel_init(&panel->base, dev, &panel_simple_funcs, connector_type); - err = drm_panel_of_backlight(&panel->base); if (err) { dev_err_probe(dev, err, "Could not find backlight\n"); From ffd5b566cf1df4ac203084980d85f86228a0375a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Barnab=C3=A1s=20Cz=C3=A9m=C3=A1n?= Date: Fri, 9 May 2025 23:41:05 +0200 Subject: [PATCH 5/9] Add novatek panel for lavender MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Barnabás Czémán --- drivers/gpu/drm/panel/Kconfig | 10 + drivers/gpu/drm/panel/Makefile | 1 + .../gpu/drm/panel/panel-nt36672a-tianmaplus.c | 252 ++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-nt36672a-tianmaplus.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index adb7e572519698..0091cc7b5c49ec 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -515,6 +515,16 @@ config DRM_PANEL_NOVATEK_NT36672A around the Novatek NT36672A display controller, such as some Tianma panels used in a few Xiaomi Poco F1 mobile phones. +config DRM_PANEL_NOVATEK_NT36672A_TIANMAPLUS + tristate "Novatek NT36672A DSI panel" + depends on OF + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for the panels built + around the Novatek NT36672A display controller, such as some + Tianma panels used in a few Xiaomi Poco F1 mobile phones. + config DRM_PANEL_NOVATEK_NT36672E tristate "Novatek NT36672E DSI panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index ff9ac5dac6dc40..2435a1a5de15c0 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35560) += panel-novatek-nt35560.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT35950) += panel-novatek-nt35950.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36523) += panel-novatek-nt36523.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672A) += panel-novatek-nt36672a.o +obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672A_TIANMAPLUS) += panel-nt36672a-tianmaplus.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672E) += panel-novatek-nt36672e.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672_TIANMA_JASMINE) += panel-novatek-nt36672-tianma-jasmine.o obj-$(CONFIG_DRM_PANEL_NOVATEK_NT36672_TXD) += panel-novatek-nt36672-txd.o diff --git a/drivers/gpu/drm/panel/panel-nt36672a-tianmaplus.c b/drivers/gpu/drm/panel/panel-nt36672a-tianmaplus.c new file mode 100644 index 00000000000000..905b6ce15a3a80 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-nt36672a-tianmaplus.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (c) 2025 FIXME +// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: +// Copyright (c) 2013, The Linux Foundation. All rights reserved. (FIXME) + +#include +#include +#include +#include +#include + +#include