From 9edb071c8bd322482fa9cd1b60f26d0243479d76 Mon Sep 17 00:00:00 2001 From: Justin Stitt Date: Tue, 19 Sep 2023 04:41:16 +0000 Subject: [PATCH 01/80] drm/gma500: refactor deprecated strncpy `strncpy` is deprecated for use on NUL-terminated destination strings [1]. We should prefer more robust and less ambiguous string interfaces. Since `chan->base.name` is expected to be NUL-terminated, a suitable replacement is `strscpy` [2] due to the fact that it guarantees NUL-termination on the destination buffer without also unnecessarily NUL-padding (since `chan` is kzalloc'd already). Link: https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings [1] Link: https://manpages.debian.org/testing/linux-manual-4.8/strscpy.9.en.html [2] Link: https://github.com/KSPP/linux/issues/90 Cc: linux-hardening@vger.kernel.org Signed-off-by: Justin Stitt Reviewed-by: Kees Cook Signed-off-by: Patrik Jakobsson Link: https://patchwork.freedesktop.org/patch/msgid/20230919-drivers-gpu-drm-gma500-oaktrail_lvds_i2c-c-v2-1-9ebe6983b4cb@google.com --- drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c index 06b5b2d70d48..939c53fd09e8 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds_i2c.c @@ -141,7 +141,7 @@ struct gma_i2c_chan *oaktrail_lvds_i2c_init(struct drm_device *dev) chan->drm_dev = dev; chan->reg = dev_priv->lpc_gpio_base; - strncpy(chan->base.name, "gma500 LPC", I2C_NAME_SIZE - 1); + strscpy(chan->base.name, "gma500 LPC", sizeof(chan->base.name)); chan->base.owner = THIS_MODULE; chan->base.algo_data = &chan->algo; chan->base.dev.parent = dev->dev; From c78199a78fe8c4f1724820a8f41f81a08a8d6e8a Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 7 Sep 2023 09:26:09 +0200 Subject: [PATCH 02/80] accel/ivpu: Update debugfs to latest changes in DRM Use new drm debugfs helpers. This is needed after changes from commit 78346ebf9f94 ("drm/debugfs: drop debugfs_init() for the render and accel node v2"). Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20230907072610.433497-1-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/ivpu_debugfs.c | 50 +++++++++++++++---------------- drivers/accel/ivpu/ivpu_debugfs.h | 4 +-- drivers/accel/ivpu/ivpu_drv.c | 8 ++--- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 5e5996fd4f9f..ea453b985b49 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -17,20 +17,26 @@ #include "ivpu_jsm_msg.h" #include "ivpu_pm.h" +static inline struct ivpu_device *seq_to_ivpu(struct seq_file *s) +{ + struct drm_debugfs_entry *entry = s->private; + + return to_ivpu_device(entry->dev); +} + static int bo_list_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; struct drm_printer p = drm_seq_file_printer(s); + struct ivpu_device *vdev = seq_to_ivpu(s); - ivpu_bo_list(node->minor->dev, &p); + ivpu_bo_list(&vdev->drm, &p); return 0; } static int fw_name_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); seq_printf(s, "%s\n", vdev->fw->name); return 0; @@ -38,8 +44,7 @@ static int fw_name_show(struct seq_file *s, void *v) static int fw_trace_capability_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); u64 trace_hw_component_mask; u32 trace_destination_mask; int ret; @@ -57,8 +62,7 @@ static int fw_trace_capability_show(struct seq_file *s, void *v) static int fw_trace_config_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); /** * WA: VPU_JSM_MSG_TRACE_GET_CONFIG command is not working yet, * so we use values from vdev->fw instead of calling ivpu_jsm_trace_get_config() @@ -78,8 +82,7 @@ static int fw_trace_config_show(struct seq_file *s, void *v) static int last_bootmode_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); seq_printf(s, "%s\n", (vdev->pm->is_warmboot) ? "warmboot" : "coldboot"); @@ -88,8 +91,7 @@ static int last_bootmode_show(struct seq_file *s, void *v) static int reset_counter_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_counter)); return 0; @@ -97,14 +99,13 @@ static int reset_counter_show(struct seq_file *s, void *v) static int reset_pending_show(struct seq_file *s, void *v) { - struct drm_info_node *node = (struct drm_info_node *)s->private; - struct ivpu_device *vdev = to_ivpu_device(node->minor->dev); + struct ivpu_device *vdev = seq_to_ivpu(s); seq_printf(s, "%d\n", atomic_read(&vdev->pm->in_reset)); return 0; } -static const struct drm_info_list vdev_debugfs_list[] = { +static const struct drm_debugfs_info vdev_debugfs_list[] = { {"bo_list", bo_list_show, 0}, {"fw_name", fw_name_show, 0}, {"fw_trace_capability", fw_trace_capability_show, 0}, @@ -270,25 +271,24 @@ static const struct file_operations ivpu_reset_engine_fops = { .write = ivpu_reset_engine_fn, }; -void ivpu_debugfs_init(struct drm_minor *minor) +void ivpu_debugfs_init(struct ivpu_device *vdev) { - struct ivpu_device *vdev = to_ivpu_device(minor->dev); + struct dentry *debugfs_root = vdev->drm.debugfs_root; - drm_debugfs_create_files(vdev_debugfs_list, ARRAY_SIZE(vdev_debugfs_list), - minor->debugfs_root, minor); + drm_debugfs_add_files(&vdev->drm, vdev_debugfs_list, ARRAY_SIZE(vdev_debugfs_list)); - debugfs_create_file("force_recovery", 0200, minor->debugfs_root, vdev, + debugfs_create_file("force_recovery", 0200, debugfs_root, vdev, &ivpu_force_recovery_fops); - debugfs_create_file("fw_log", 0644, minor->debugfs_root, vdev, + debugfs_create_file("fw_log", 0644, debugfs_root, vdev, &fw_log_fops); - debugfs_create_file("fw_trace_destination_mask", 0200, minor->debugfs_root, vdev, + debugfs_create_file("fw_trace_destination_mask", 0200, debugfs_root, vdev, &fw_trace_destination_mask_fops); - debugfs_create_file("fw_trace_hw_comp_mask", 0200, minor->debugfs_root, vdev, + debugfs_create_file("fw_trace_hw_comp_mask", 0200, debugfs_root, vdev, &fw_trace_hw_comp_mask_fops); - debugfs_create_file("fw_trace_level", 0200, minor->debugfs_root, vdev, + debugfs_create_file("fw_trace_level", 0200, debugfs_root, vdev, &fw_trace_level_fops); - debugfs_create_file("reset_engine", 0200, minor->debugfs_root, vdev, + debugfs_create_file("reset_engine", 0200, debugfs_root, vdev, &ivpu_reset_engine_fops); } diff --git a/drivers/accel/ivpu/ivpu_debugfs.h b/drivers/accel/ivpu/ivpu_debugfs.h index 78f80c1e00e4..76dbce139772 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.h +++ b/drivers/accel/ivpu/ivpu_debugfs.h @@ -6,8 +6,8 @@ #ifndef __IVPU_DEBUGFS_H__ #define __IVPU_DEBUGFS_H__ -struct drm_minor; +struct ivpu_device; -void ivpu_debugfs_init(struct drm_minor *minor); +void ivpu_debugfs_init(struct ivpu_device *vdev); #endif /* __IVPU_DEBUGFS_H__ */ diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index fa0680ba9340..b6aaf9811355 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -395,10 +395,6 @@ static const struct drm_driver driver = { .postclose = ivpu_postclose, .gem_prime_import = ivpu_gem_prime_import, -#if defined(CONFIG_DEBUG_FS) - .debugfs_init = ivpu_debugfs_init, -#endif - .ioctls = ivpu_drm_ioctls, .num_ioctls = ARRAY_SIZE(ivpu_drm_ioctls), .fops = &ivpu_fops, @@ -631,6 +627,10 @@ static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; +#if defined(CONFIG_DEBUG_FS) + ivpu_debugfs_init(vdev); +#endif + ret = drm_dev_register(&vdev->drm, 0); if (ret) { dev_err(&pdev->dev, "Failed to register DRM device: %d\n", ret); From d776f654d08948639d445a750839612977e78a49 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Thu, 7 Sep 2023 09:26:10 +0200 Subject: [PATCH 03/80] accel/ivpu: Compile ivpu_debugfs.c conditionally Only compile ivpu_debugfs.c file with CONFIG_DEBUG_FS. Reviewed-by: Jeffrey Hugo Signed-off-by: Stanislaw Gruszka Link: https://patchwork.freedesktop.org/patch/msgid/20230907072610.433497-2-stanislaw.gruszka@linux.intel.com --- drivers/accel/ivpu/Makefile | 3 ++- drivers/accel/ivpu/ivpu_debugfs.h | 4 ++++ drivers/accel/ivpu/ivpu_drv.c | 2 -- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/accel/ivpu/Makefile b/drivers/accel/ivpu/Makefile index e4328b430564..95ff7ad16338 100644 --- a/drivers/accel/ivpu/Makefile +++ b/drivers/accel/ivpu/Makefile @@ -2,7 +2,6 @@ # Copyright (C) 2023 Intel Corporation intel_vpu-y := \ - ivpu_debugfs.o \ ivpu_drv.o \ ivpu_fw.o \ ivpu_fw_log.o \ @@ -16,4 +15,6 @@ intel_vpu-y := \ ivpu_mmu_context.o \ ivpu_pm.o +intel_vpu-$(CONFIG_DEBUG_FS) += ivpu_debugfs.o + obj-$(CONFIG_DRM_ACCEL_IVPU) += intel_vpu.o diff --git a/drivers/accel/ivpu/ivpu_debugfs.h b/drivers/accel/ivpu/ivpu_debugfs.h index 76dbce139772..49ae9ea78287 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.h +++ b/drivers/accel/ivpu/ivpu_debugfs.h @@ -8,6 +8,10 @@ struct ivpu_device; +#if defined(CONFIG_DEBUG_FS) void ivpu_debugfs_init(struct ivpu_device *vdev); +#else +static inline void ivpu_debugfs_init(struct ivpu_device *vdev) { } +#endif #endif /* __IVPU_DEBUGFS_H__ */ diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index b6aaf9811355..7851ff7773ca 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -627,9 +627,7 @@ static int ivpu_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; -#if defined(CONFIG_DEBUG_FS) ivpu_debugfs_init(vdev); -#endif ret = drm_dev_register(&vdev->drm, 0); if (ret) { From 24c614c3d60c41743b1a5e588a4019c1d30c0faa Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 26 Sep 2023 12:51:28 +0200 Subject: [PATCH 04/80] drm/gpuvm: doc: fix filename references Commit f72c2db47080 ("drm/gpuvm: rename struct drm_gpuva_manager to struct drm_gpuvm") did also change the corresponding filenames which are referenced from the documentation, but were not adjusted accordingly. Hence, fix up those filenames. Fixes: f72c2db47080 ("drm/gpuvm: rename struct drm_gpuva_manager to struct drm_gpuvm") Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/dri-devel/20230926150725.4cca5fc5@canb.auug.org.au/ Signed-off-by: Danilo Krummrich Acked-by: Dave Airlie Link: https://patchwork.freedesktop.org/patch/msgid/20230926105146.10808-1-dakr@redhat.com --- Documentation/gpu/drm-mm.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index c19b34b1c0ed..602010cb6894 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -466,40 +466,40 @@ DRM MM Range Allocator Function References .. kernel-doc:: drivers/gpu/drm/drm_mm.c :export: -DRM GPU VA Manager -================== +DRM GPUVM +========= Overview -------- -.. kernel-doc:: drivers/gpu/drm/drm_gpuva_mgr.c +.. kernel-doc:: drivers/gpu/drm/drm_gpuvm.c :doc: Overview Split and Merge --------------- -.. kernel-doc:: drivers/gpu/drm/drm_gpuva_mgr.c +.. kernel-doc:: drivers/gpu/drm/drm_gpuvm.c :doc: Split and Merge Locking ------- -.. kernel-doc:: drivers/gpu/drm/drm_gpuva_mgr.c +.. kernel-doc:: drivers/gpu/drm/drm_gpuvm.c :doc: Locking Examples -------- -.. kernel-doc:: drivers/gpu/drm/drm_gpuva_mgr.c +.. kernel-doc:: drivers/gpu/drm/drm_gpuvm.c :doc: Examples -DRM GPU VA Manager Function References --------------------------------------- +DRM GPUVM Function References +----------------------------- -.. kernel-doc:: include/drm/drm_gpuva_mgr.h +.. kernel-doc:: include/drm/drm_gpuvm.h :internal: -.. kernel-doc:: drivers/gpu/drm/drm_gpuva_mgr.c +.. kernel-doc:: drivers/gpu/drm/drm_gpuvm.c :export: DRM Buddy Allocator From a4ead6e37e3290cff399e2598d75e98777b69b37 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 25 Sep 2023 17:59:24 +0200 Subject: [PATCH 05/80] drm/nouveau/kms/nv50: hide unused variables After a recent change, two variables are only used in an #ifdef: drivers/gpu/drm/nouveau/dispnv50/disp.c: In function 'nv50_sor_atomic_disable': drivers/gpu/drm/nouveau/dispnv50/disp.c:1569:13: error: unused variable 'ret' [-Werror=unused-variable] 1569 | int ret; | ^~~ drivers/gpu/drm/nouveau/dispnv50/disp.c:1568:28: error: unused variable 'aux' [-Werror=unused-variable] 1568 | struct drm_dp_aux *aux = &nv_connector->aux; | ^~~ Move them into the same conditional block, along with the nv_connector variable that becomes unused during that fix. Fixes: 757033808c95 ("drm/nouveau/kms/nv50-: fixup sink D3 before tearing down link") Signed-off-by: Arnd Bergmann Reviewed-by: Danilo Krummrich Signed-off-by: Danilo Krummrich Link: https://patchwork.freedesktop.org/patch/msgid/20230925155930.677620-1-arnd@kernel.org --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index dcd19c418389..9066a1263b73 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1560,15 +1560,13 @@ nv50_sor_atomic_disable(struct drm_encoder *encoder, struct drm_atomic_state *st { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); struct nv50_head *head = nv50_head(nv_encoder->crtc); - struct nouveau_connector *nv_connector = nv50_outp_get_old_connector(state, nv_encoder); #ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT + struct nouveau_connector *nv_connector = nv50_outp_get_old_connector(state, nv_encoder); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); struct nouveau_backlight *backlight = nv_connector->backlight; -#endif struct drm_dp_aux *aux = &nv_connector->aux; int ret; -#ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT if (backlight && backlight->uses_dpcd) { ret = drm_edp_backlight_disable(aux, &backlight->edp_info); if (ret < 0) From 5a44d50f00725f31bf4a85e61587c87ce0429787 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 21 Sep 2023 12:57:43 +0200 Subject: [PATCH 06/80] MAINTAINERS: Update drm-misc entry to match all drivers We've had a number of times when a patch slipped through and we couldn't pick them up either because our MAINTAINERS entry only covers the framework and thus we weren't Cc'd. Let's take another approach where we match everything, and remove all the drivers that are not maintained through drm-misc. Acked-by: Jani Nikula Acked-by: Dave Airlie Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20230921105743.2611263-1-mripard@kernel.org --- MAINTAINERS | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index d72d3af551fb..e3903177a739 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6826,12 +6826,26 @@ M: Thomas Zimmermann S: Maintained W: https://01.org/linuxgraphics/gfx-docs/maintainer-tools/drm-misc.html T: git git://anongit.freedesktop.org/drm/drm-misc +F: Documentation/devicetree/bindings/display/ +F: Documentation/devicetree/bindings/gpu/ F: Documentation/gpu/ -F: drivers/gpu/drm/* +F: drivers/gpu/drm/ F: drivers/gpu/vga/ -F: include/drm/drm* +F: include/drm/drm F: include/linux/vga* -F: include/uapi/drm/drm* +F: include/uapi/drm/ +X: drivers/gpu/drm/amd/ +X: drivers/gpu/drm/armada/ +X: drivers/gpu/drm/etnaviv/ +X: drivers/gpu/drm/exynos/ +X: drivers/gpu/drm/i915/ +X: drivers/gpu/drm/kmb/ +X: drivers/gpu/drm/mediatek/ +X: drivers/gpu/drm/msm/ +X: drivers/gpu/drm/nouveau/ +X: drivers/gpu/drm/radeon/ +X: drivers/gpu/drm/renesas/ +X: drivers/gpu/drm/tegra/ DRM DRIVERS FOR ALLWINNER A10 M: Maxime Ripard From fc5fb9e7f81e4ae73958d05adb4fe7cde24c88a2 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 25 Sep 2023 15:49:29 -0700 Subject: [PATCH 07/80] MAINTAINERS: Document that the NXP i.MX 8MQ DCSS driver goes thru drm-misc As per the discussion on the lists [1], changes to this driver generally flow through drm-misc. Add a tag in MAINTAINERS to document this [1] https://lore.kernel.org/r/20230925054710.r3guqn5jzdl4giwd@fsr-ub1664-121.ea.freescale.net Signed-off-by: Douglas Anderson Acked-by: Laurentiu Palcu Signed-off-by: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20230925154929.1.I3287e895ce8e68d41b458494a49a1b5ec5c71013@changeid --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index e3903177a739..d787a18a76c4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15239,6 +15239,7 @@ M: Laurentiu Palcu R: Lucas Stach L: dri-devel@lists.freedesktop.org S: Maintained +T: git git://anongit.freedesktop.org/drm/drm-misc F: Documentation/devicetree/bindings/display/imx/nxp,imx8mq-dcss.yaml F: drivers/gpu/drm/imx/dcss/ From ab2dbf894a0f931aa4aba52f736ce460028c187f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 14 Sep 2023 16:14:49 +0300 Subject: [PATCH 08/80] drm/bridge: use drm_bridge_get_edid() instead of using ->get_edid directly Make drm_bridge_get_edid() the one place to call the hook. Cc: Andrzej Hajda Cc: Neil Armstrong Cc: Robert Foss Cc: Laurent Pinchart Cc: Jonas Karlman Cc: Jernej Skrabec Signed-off-by: Jani Nikula Reviewed-by: Laurent Pinchart Link: https://patchwork.freedesktop.org/patch/msgid/20230914131450.2473061-1-jani.nikula@intel.com --- drivers/gpu/drm/drm_bridge_connector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index 1da93d5a1f61..31baf1f5ff81 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -238,7 +238,7 @@ static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector, if (status != connector_status_connected) goto no_edid; - edid = bridge->funcs->get_edid(bridge, connector); + edid = drm_bridge_get_edid(bridge, connector); if (!drm_edid_is_valid(edid)) { kfree(edid); goto no_edid; From e35728d0286c79ea6cf16fa0c7847cf2b65e690f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 14 Sep 2023 16:14:50 +0300 Subject: [PATCH 09/80] drm/bridge: lt9611uxc: use drm_bridge_get_edid() instead of using ->get_edid directly Make drm_bridge_get_edid() the one place to call the hook. Cc: Andrzej Hajda Cc: Neil Armstrong Cc: Robert Foss Cc: Laurent Pinchart Cc: Jonas Karlman Cc: Jernej Skrabec Signed-off-by: Jani Nikula Reviewed-by: Laurent Pinchart Link: https://patchwork.freedesktop.org/patch/msgid/20230914131450.2473061-2-jani.nikula@intel.com --- drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c index 22c84d29c2bc..7835738a532e 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c +++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c @@ -296,7 +296,7 @@ static int lt9611uxc_connector_get_modes(struct drm_connector *connector) unsigned int count; struct edid *edid; - edid = lt9611uxc->bridge.funcs->get_edid(<9611uxc->bridge, connector); + edid = drm_bridge_get_edid(<9611uxc->bridge, connector); drm_connector_update_edid_property(connector, edid); count = drm_add_edid_modes(connector, edid); kfree(edid); From 15bda1f8de5d192fb003c63c4d13cf53d9ae4590 Mon Sep 17 00:00:00 2001 From: Arthur Grillo Date: Mon, 18 Sep 2023 20:51:04 -0300 Subject: [PATCH 10/80] drm/tests: Add calls to drm_fb_blit() on supported format conversion tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a call to drm_fb_blit() on existing format conversion tests that has support. Signed-off-by: Arthur Grillo Reviewed-by: Maíra Canal Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20230918-final-gsoc-v3-1-b999c042a4cc@riseup.net --- .../gpu/drm/tests/drm_format_helper_test.c | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c index 1a6bd291345d..eaf3d6c33859 100644 --- a/drivers/gpu/drm/tests/drm_format_helper_test.c +++ b/drivers/gpu/drm/tests/drm_format_helper_test.c @@ -643,6 +643,18 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test) drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, true); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size); + + buf = dst.vaddr; + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGB565, &src, &fb, ¶ms->clip); + + buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test) @@ -677,6 +689,18 @@ static void drm_test_fb_xrgb8888_to_xrgb1555(struct kunit *test) drm_fb_xrgb8888_to_xrgb1555(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB1555, &src, &fb, ¶ms->clip); + + buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test) @@ -711,6 +735,18 @@ static void drm_test_fb_xrgb8888_to_argb1555(struct kunit *test) drm_fb_xrgb8888_to_argb1555(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB1555, &src, &fb, ¶ms->clip); + + buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test) @@ -745,6 +781,18 @@ static void drm_test_fb_xrgb8888_to_rgba5551(struct kunit *test) drm_fb_xrgb8888_to_rgba5551(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGBA5551, &src, &fb, ¶ms->clip); + + buf = le16buf_to_cpu(test, (__force const __le16 *)buf, dst_size / sizeof(__le16)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) @@ -782,6 +830,16 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test) drm_fb_xrgb8888_to_rgb888(&dst, dst_pitch, &src, &fb, ¶ms->clip); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_RGB888, &src, &fb, ¶ms->clip); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test) @@ -816,6 +874,18 @@ static void drm_test_fb_xrgb8888_to_argb8888(struct kunit *test) drm_fb_xrgb8888_to_argb8888(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB8888, &src, &fb, ¶ms->clip); + + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) @@ -850,6 +920,17 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test) drm_fb_xrgb8888_to_xrgb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le32buf_to_cpu(test, buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB2101010, &src, &fb, + ¶ms->clip); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test) @@ -884,6 +965,19 @@ static void drm_test_fb_xrgb8888_to_argb2101010(struct kunit *test) drm_fb_xrgb8888_to_argb2101010(&dst, dst_pitch, &src, &fb, ¶ms->clip); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ARGB2101010, &src, &fb, + ¶ms->clip); + + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } static void drm_test_fb_xrgb8888_to_mono(struct kunit *test) @@ -951,6 +1045,41 @@ static void drm_test_fb_swab(struct kunit *test) drm_fb_swab(&dst, dst_pitch, &src, &fb, ¶ms->clip, false); buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; /* restore original value of buf */ + memset(buf, 0, dst_size); + + int blit_result; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB8888 | DRM_FORMAT_BIG_ENDIAN, + &src, &fb, ¶ms->clip); + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; + memset(buf, 0, dst_size); + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_BGRX8888, &src, &fb, ¶ms->clip); + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); + + buf = dst.vaddr; + memset(buf, 0, dst_size); + + struct drm_format_info mock_format = *fb.format; + + mock_format.format |= DRM_FORMAT_BIG_ENDIAN; + fb.format = &mock_format; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XRGB8888, &src, &fb, ¶ms->clip); + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } struct clip_offset_case { @@ -1538,6 +1667,19 @@ static void drm_test_fb_memcpy(struct kunit *test) drm_fb_memcpy(dst, dst_pitches, src, &fb, ¶ms->clip); + for (size_t i = 0; i < fb.format->num_planes; i++) { + expected[i] = cpubuf_to_le32(test, params->expected[i], TEST_BUF_SIZE); + KUNIT_EXPECT_MEMEQ_MSG(test, buf[i], expected[i], dst_size[i], + "Failed expectation on plane %zu", i); + + memset(buf[i], 0, dst_size[i]); + } + + int blit_result; + + blit_result = drm_fb_blit(dst, dst_pitches, params->format, src, &fb, ¶ms->clip); + + KUNIT_EXPECT_FALSE(test, blit_result); for (size_t i = 0; i < fb.format->num_planes; i++) { expected[i] = cpubuf_to_le32(test, params->expected[i], TEST_BUF_SIZE); KUNIT_EXPECT_MEMEQ_MSG(test, buf[i], expected[i], dst_size[i], From 91951d36c2231c84be8266b2e852e59a552e66d0 Mon Sep 17 00:00:00 2001 From: Arthur Grillo Date: Mon, 18 Sep 2023 20:51:05 -0300 Subject: [PATCH 11/80] drm/tests: Add new format conversion tests to better cover drm_fb_blit() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To fully cover drm_fb_blit(), add format conversion tests that are only supported through drm_fb_blit(). Signed-off-by: Arthur Grillo Reviewed-by: Maíra Canal Signed-off-by: Maíra Canal Link: https://patchwork.freedesktop.org/patch/msgid/20230918-final-gsoc-v3-2-b999c042a4cc@riseup.net --- .../gpu/drm/tests/drm_format_helper_test.c | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/drivers/gpu/drm/tests/drm_format_helper_test.c b/drivers/gpu/drm/tests/drm_format_helper_test.c index eaf3d6c33859..f6408e56f786 100644 --- a/drivers/gpu/drm/tests/drm_format_helper_test.c +++ b/drivers/gpu/drm/tests/drm_format_helper_test.c @@ -81,6 +81,16 @@ struct fb_swab_result { const u32 expected[TEST_BUF_SIZE]; }; +struct convert_to_xbgr8888_result { + unsigned int dst_pitch; + const u32 expected[TEST_BUF_SIZE]; +}; + +struct convert_to_abgr8888_result { + unsigned int dst_pitch; + const u32 expected[TEST_BUF_SIZE]; +}; + struct convert_xrgb8888_case { const char *name; unsigned int pitch; @@ -98,6 +108,8 @@ struct convert_xrgb8888_case { struct convert_to_argb2101010_result argb2101010_result; struct convert_to_mono_result mono_result; struct fb_swab_result swab_result; + struct convert_to_xbgr8888_result xbgr8888_result; + struct convert_to_abgr8888_result abgr8888_result; }; static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { @@ -155,6 +167,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x0000FF01 }, }, + .xbgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0x010000FF }, + }, + .abgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0xFF0000FF }, + }, }, { .name = "single_pixel_clip_rectangle", @@ -213,6 +233,14 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { .dst_pitch = TEST_USE_DEFAULT_PITCH, .expected = { 0x0000FF10 }, }, + .xbgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0x100000FF }, + }, + .abgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { 0xFF0000FF }, + }, }, { /* Well known colors: White, black, red, green, blue, magenta, @@ -343,6 +371,24 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0x00FFFF77, 0xFFFF0088, }, }, + .xbgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { + 0x11FFFFFF, 0x22000000, + 0x330000FF, 0x4400FF00, + 0x55FF0000, 0x66FF00FF, + 0x7700FFFF, 0x88FFFF00, + }, + }, + .abgr8888_result = { + .dst_pitch = TEST_USE_DEFAULT_PITCH, + .expected = { + 0xFFFFFFFF, 0xFF000000, + 0xFF0000FF, 0xFF00FF00, + 0xFFFF0000, 0xFFFF00FF, + 0xFF00FFFF, 0xFFFFFF00, + }, + }, }, { /* Randomly picked colors. Full buffer within the clip area. */ @@ -458,6 +504,22 @@ static struct convert_xrgb8888_case convert_xrgb8888_cases[] = { 0x0303A8C2, 0x73F06CD2, 0x9C440EA3, 0x00000000, 0x00000000, }, }, + .xbgr8888_result = { + .dst_pitch = 20, + .expected = { + 0xA19C440E, 0xB1054D11, 0xC103F3A8, 0x00000000, 0x00000000, + 0xD173F06C, 0xA29C440E, 0xB2054D11, 0x00000000, 0x00000000, + 0xC20303A8, 0xD273F06C, 0xA39C440E, 0x00000000, 0x00000000, + }, + }, + .abgr8888_result = { + .dst_pitch = 20, + .expected = { + 0xFF9C440E, 0xFF054D11, 0xFF03F3A8, 0x00000000, 0x00000000, + 0xFF73F06C, 0xFF9C440E, 0xFF054D11, 0x00000000, 0x00000000, + 0xFF0303A8, 0xFF73F06C, 0xFF9C440E, 0x00000000, 0x00000000, + }, + }, }, }; @@ -1082,6 +1144,84 @@ static void drm_test_fb_swab(struct kunit *test) KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); } +static void drm_test_fb_xrgb8888_to_abgr8888(struct kunit *test) +{ + const struct convert_xrgb8888_case *params = test->param_value; + const struct convert_to_abgr8888_result *result = ¶ms->abgr8888_result; + size_t dst_size; + u32 *buf = NULL; + __le32 *xrgb8888 = NULL; + struct iosys_map dst, src; + + struct drm_framebuffer fb = { + .format = drm_format_info(DRM_FORMAT_XRGB8888), + .pitches = { params->pitch, 0, 0 }, + }; + + dst_size = conversion_buf_size(DRM_FORMAT_XBGR8888, result->dst_pitch, ¶ms->clip, 0); + + KUNIT_ASSERT_GT(test, dst_size, 0); + + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_ABGR8888, &src, &fb, ¶ms->clip); + + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); +} + +static void drm_test_fb_xrgb8888_to_xbgr8888(struct kunit *test) +{ + const struct convert_xrgb8888_case *params = test->param_value; + const struct convert_to_xbgr8888_result *result = ¶ms->xbgr8888_result; + size_t dst_size; + u32 *buf = NULL; + __le32 *xrgb8888 = NULL; + struct iosys_map dst, src; + + struct drm_framebuffer fb = { + .format = drm_format_info(DRM_FORMAT_XRGB8888), + .pitches = { params->pitch, 0, 0 }, + }; + + dst_size = conversion_buf_size(DRM_FORMAT_XBGR8888, result->dst_pitch, ¶ms->clip, 0); + + KUNIT_ASSERT_GT(test, dst_size, 0); + + buf = kunit_kzalloc(test, dst_size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + iosys_map_set_vaddr(&dst, buf); + + xrgb8888 = cpubuf_to_le32(test, params->xrgb8888, TEST_BUF_SIZE); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xrgb8888); + iosys_map_set_vaddr(&src, xrgb8888); + + const unsigned int *dst_pitch = (result->dst_pitch == TEST_USE_DEFAULT_PITCH) ? + NULL : &result->dst_pitch; + + int blit_result = 0; + + blit_result = drm_fb_blit(&dst, dst_pitch, DRM_FORMAT_XBGR8888, &src, &fb, ¶ms->clip); + + buf = le32buf_to_cpu(test, (__force const __le32 *)buf, dst_size / sizeof(u32)); + + KUNIT_EXPECT_FALSE(test, blit_result); + KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size); +} + struct clip_offset_case { const char *name; unsigned int pitch; @@ -1700,6 +1840,8 @@ static struct kunit_case drm_format_helper_test_cases[] = { KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_argb2101010, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_mono, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_swab, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_xbgr8888, convert_xrgb8888_gen_params), + KUNIT_CASE_PARAM(drm_test_fb_xrgb8888_to_abgr8888, convert_xrgb8888_gen_params), KUNIT_CASE_PARAM(drm_test_fb_clip_offset, clip_offset_gen_params), KUNIT_CASE_PARAM(drm_test_fb_build_fourcc_list, fb_build_fourcc_list_gen_params), KUNIT_CASE_PARAM(drm_test_fb_memcpy, fb_memcpy_gen_params), From 86c3331c8089ac1cf231825f406c4bf8afd9f3a2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 29 Sep 2023 14:54:19 +0200 Subject: [PATCH 12/80] drm/bridge: adv7511: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Reviewed-by: Laurent Pinchart Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230929-drm-adv7511-v1-1-b871b28ee594@kernel.org --- drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index 2611afd2c1c1..d518de88b5c3 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -121,7 +121,7 @@ static const struct regmap_config adv7511_regmap_config = { .val_bits = 8, .max_register = 0xff, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults_raw = adv7511_register_defaults, .num_reg_defaults_raw = ARRAY_SIZE(adv7511_register_defaults), @@ -1068,7 +1068,7 @@ static const struct regmap_config adv7511_cec_regmap_config = { .val_bits = 8, .max_register = 0xff, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = adv7511_cec_register_volatile, }; From 9a9f6fb5205a6cb189147bca1264311c4bf45163 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 1 Oct 2023 01:42:24 +0200 Subject: [PATCH 13/80] drm/bridge: dpc3433: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231001-drm-dlpc3433-maple-v1-1-7d71170c010b@kernel.org --- drivers/gpu/drm/bridge/ti-dlpc3433.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/ti-dlpc3433.c b/drivers/gpu/drm/bridge/ti-dlpc3433.c index b65632ec7e7d..ca3348109bcd 100644 --- a/drivers/gpu/drm/bridge/ti-dlpc3433.c +++ b/drivers/gpu/drm/bridge/ti-dlpc3433.c @@ -100,7 +100,7 @@ static struct regmap_config dlpc_regmap_config = { .max_register = WR_DSI_PORT_EN, .writeable_noinc_reg = dlpc_writeable_noinc_reg, .volatile_table = &dlpc_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .name = "dlpc3433", }; From 4dd9368671fb7649dc914e661256a07250c271ca Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 1 Oct 2023 01:43:13 +0200 Subject: [PATCH 14/80] drm/bridge: tc358767: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231001-drm-tc358767-maple-v1-1-f759fcc4bd98@kernel.org --- drivers/gpu/drm/bridge/tc358767.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index b45bffab7c81..ef2e373606ba 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -2005,7 +2005,7 @@ static const struct regmap_config tc_regmap_config = { .val_bits = 32, .reg_stride = 4, .max_register = PLL_DBG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .readable_reg = tc_readable_reg, .volatile_table = &tc_volatile_table, .writeable_reg = tc_writeable_reg, From fb6f4f47dd4a71a0394d346eda7589dd9397c4bc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 1 Oct 2023 00:46:38 +0100 Subject: [PATCH 15/80] drm/bridge: icn6211: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231001-drm-chipone-maple-v1-1-fb3ce5a53710@kernel.org --- drivers/gpu/drm/bridge/chipone-icn6211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index d205e755e524..82d23e4df09e 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -197,7 +197,7 @@ static const struct regmap_config chipone_regmap_config = { .val_bits = 8, .rd_table = &chipone_dsi_readable_table, .wr_table = &chipone_dsi_writeable_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = MIPI_ATE_STATUS(1), }; From eae0cfcce3cd10a9189bf46934de9bde7ad7b2d0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 1 Oct 2023 11:24:49 +0100 Subject: [PATCH 16/80] drm/bridge: lt9211: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231001-drm-lt9211-maple-v1-1-1cf74fb10991@kernel.org --- drivers/gpu/drm/bridge/lontium-lt9211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/lontium-lt9211.c b/drivers/gpu/drm/bridge/lontium-lt9211.c index 4d404f5ef87e..c8881796fba4 100644 --- a/drivers/gpu/drm/bridge/lontium-lt9211.c +++ b/drivers/gpu/drm/bridge/lontium-lt9211.c @@ -89,7 +89,7 @@ static const struct regmap_config lt9211_regmap_config = { .volatile_table = <9211_rw_table, .ranges = <9211_range, .num_ranges = 1, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = 0xda00, }; From 0908a0225d0fa6d7675bf3c2cc4c25a89e13e83c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 1 Oct 2023 11:26:22 +0100 Subject: [PATCH 17/80] drm/bridge: sn65dsi83: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231001-drm-sn65dsi83-maple-v1-1-cf8ad22b6be0@kernel.org --- drivers/gpu/drm/bridge/ti-sn65dsi83.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index 061e8bd5915d..4814b7b6d1fd 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -233,7 +233,7 @@ static const struct regmap_config sn65dsi83_regmap_config = { .rd_table = &sn65dsi83_readable_table, .wr_table = &sn65dsi83_writeable_table, .volatile_table = &sn65dsi83_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = REG_IRQ_STAT, }; From c8c575ebf6daaf1fbe029cc04c845e2fad462320 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 1 Oct 2023 11:24:13 +0100 Subject: [PATCH 18/80] drm/panel: ili9322: Remove redundant volatle_reg() operation The ili9322 driver has a volatile_reg() operation in it's regmap which always returns false. This is redundant since it is the default in the regmap core, remove the operation for a trivial code size and performance improvement. Signed-off-by: Mark Brown Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231001-drm-sn65dsi83-maple-v1-1-5519799a55e5@kernel.org --- drivers/gpu/drm/panel/panel-ilitek-ili9322.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index 61c872f0f7ca..15b81e5228b5 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -325,11 +325,6 @@ static struct regmap_bus ili9322_regmap_bus = { .val_format_endian_default = REGMAP_ENDIAN_BIG, }; -static bool ili9322_volatile_reg(struct device *dev, unsigned int reg) -{ - return false; -} - static bool ili9322_writeable_reg(struct device *dev, unsigned int reg) { /* Just register 0 is read-only */ @@ -343,7 +338,6 @@ static const struct regmap_config ili9322_regmap_config = { .val_bits = 8, .max_register = 0x44, .cache_type = REGCACHE_RBTREE, - .volatile_reg = ili9322_volatile_reg, .writeable_reg = ili9322_writeable_reg, }; From 800c1ff7d1b12b6309eb877542367b94f376acbc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 1 Oct 2023 11:24:14 +0100 Subject: [PATCH 19/80] drm/panel: ili9322: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231001-drm-sn65dsi83-maple-v1-2-5519799a55e5@kernel.org --- drivers/gpu/drm/panel/panel-ilitek-ili9322.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c index 15b81e5228b5..4a6dcfd781e8 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9322.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9322.c @@ -337,7 +337,7 @@ static const struct regmap_config ili9322_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = 0x44, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .writeable_reg = ili9322_writeable_reg, }; From d1fd19e6bd7d276cf2290300cc563e2e5ac4ebf7 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 29 Sep 2023 14:54:20 +0200 Subject: [PATCH 20/80] dt-bindings: display: panel: Add Raydium RM692E5 Raydium RM692E5 is a display driver IC used to drive AMOLED DSI panels. Describe it. Reviewed-by: Conor Dooley Signed-off-by: Konrad Dybcio Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230927-topic-fp5_disp-v2-1-7b5e1d1662a6@linaro.org --- .../display/panel/raydium,rm692e5.yaml | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 Documentation/devicetree/bindings/display/panel/raydium,rm692e5.yaml diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm692e5.yaml b/Documentation/devicetree/bindings/display/panel/raydium,rm692e5.yaml new file mode 100644 index 000000000000..f436ba6738ca --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/raydium,rm692e5.yaml @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/raydium,rm692e5.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Raydium RM692E5 based DSI display panels + +maintainers: + - Konrad Dybcio + +description: + The Raydium RM692E5 is a generic DSI Panel IC used to control + AMOLED panels. + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + items: + - const: fairphone,fp5-rm692e5-boe + - const: raydium,rm692e5 + + dvdd-supply: + description: Digital voltage rail + + vci-supply: + description: Analog voltage rail + + vddio-supply: + description: I/O voltage rail + + reg: true + port: true + +required: + - compatible + - reg + - reset-gpios + - dvdd-supply + - vci-supply + - vddio-supply + - port + +unevaluatedProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "fairphone,fp5-rm692e5-boe", "raydium,rm692e5"; + reg = <0>; + + reset-gpios = <&tlmm 44 GPIO_ACTIVE_LOW>; + dvdd-supply = <&vreg_oled_vci>; + vci-supply = <&vreg_l12c>; + vddio-supply = <&vreg_oled_dvdd>; + + port { + panel_in_0: endpoint { + remote-endpoint = <&dsi0_out>; + }; + }; + }; + }; + +... From 988d0ff29ecf7ab750b9be29fddae588156c3d03 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Fri, 29 Sep 2023 14:54:21 +0200 Subject: [PATCH 21/80] drm/panel: Add driver for BOE RM692E5 AMOLED panel Add support for the 2700x1224 AMOLED BOE panel bundled with a RM692E5 driver IC, as found on the Fairphone 5 smartphone. Co-developed-by: Luca Weiss Signed-off-by: Luca Weiss Signed-off-by: Konrad Dybcio Reviewed-by: Neil Armstrong Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230927-topic-fp5_disp-v2-2-7b5e1d1662a6@linaro.org --- drivers/gpu/drm/panel/Kconfig | 9 + drivers/gpu/drm/panel/Makefile | 1 + drivers/gpu/drm/panel/panel-raydium-rm692e5.c | 423 ++++++++++++++++++ 3 files changed, 433 insertions(+) create mode 100644 drivers/gpu/drm/panel/panel-raydium-rm692e5.c diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 2d6d96ee3547..ecb22ea326cb 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -516,6 +516,15 @@ config DRM_PANEL_RAYDIUM_RM68200 Say Y here if you want to enable support for Raydium RM68200 720x1280 DSI video mode panel. +config DRM_PANEL_RAYDIUM_RM692E5 + tristate "Raydium RM692E5-based 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 Raydium RM692E5-based + display panels, such as the one found in the Fairphone 5 smartphone. + config DRM_PANEL_RONBO_RB070D30 tristate "Ronbo Electronics RB070D30 panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 157c77ff157f..e14ce55a0875 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67191) += panel-raydium-rm67191.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o +obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM692E5) += panel-raydium-rm692e5.o obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20) += panel-samsung-atna33xc20.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o diff --git a/drivers/gpu/drm/panel/panel-raydium-rm692e5.c b/drivers/gpu/drm/panel/panel-raydium-rm692e5.c new file mode 100644 index 000000000000..a613ba5b816c --- /dev/null +++ b/drivers/gpu/drm/panel/panel-raydium-rm692e5.c @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2023 Linaro Limited + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct rm692e5_panel { + struct drm_panel panel; + struct mipi_dsi_device *dsi; + struct drm_dsc_config dsc; + struct regulator_bulk_data supplies[3]; + struct gpio_desc *reset_gpio; + bool prepared; +}; + +static inline struct rm692e5_panel *to_rm692e5_panel(struct drm_panel *panel) +{ + return container_of(panel, struct rm692e5_panel, panel); +} + +static void rm692e5_reset(struct rm692e5_panel *ctx) +{ + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + usleep_range(5000, 6000); + gpiod_set_value_cansleep(ctx->reset_gpio, 0); + usleep_range(10000, 11000); +} + +static int rm692e5_on(struct rm692e5_panel *ctx) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x41); + mipi_dsi_generic_write_seq(dsi, 0xd6, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x16); + mipi_dsi_generic_write_seq(dsi, 0x8a, 0x87); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x71); + mipi_dsi_generic_write_seq(dsi, 0x82, 0x01); + mipi_dsi_generic_write_seq(dsi, 0xc6, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xc7, 0x2c); + mipi_dsi_generic_write_seq(dsi, 0xc8, 0x64); + mipi_dsi_generic_write_seq(dsi, 0xc9, 0x3c); + mipi_dsi_generic_write_seq(dsi, 0xca, 0x80); + mipi_dsi_generic_write_seq(dsi, 0xcb, 0x02); + mipi_dsi_generic_write_seq(dsi, 0xcc, 0x02); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x38); + mipi_dsi_generic_write_seq(dsi, 0x18, 0x13); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0xf4); + mipi_dsi_generic_write_seq(dsi, 0x00, 0xff); + mipi_dsi_generic_write_seq(dsi, 0x01, 0xff); + mipi_dsi_generic_write_seq(dsi, 0x02, 0xcf); + mipi_dsi_generic_write_seq(dsi, 0x03, 0xbc); + mipi_dsi_generic_write_seq(dsi, 0x04, 0xb9); + mipi_dsi_generic_write_seq(dsi, 0x05, 0x99); + mipi_dsi_generic_write_seq(dsi, 0x06, 0x02); + mipi_dsi_generic_write_seq(dsi, 0x07, 0x0a); + mipi_dsi_generic_write_seq(dsi, 0x08, 0xe0); + mipi_dsi_generic_write_seq(dsi, 0x09, 0x4c); + mipi_dsi_generic_write_seq(dsi, 0x0a, 0xeb); + mipi_dsi_generic_write_seq(dsi, 0x0b, 0xe8); + mipi_dsi_generic_write_seq(dsi, 0x0c, 0x32); + mipi_dsi_generic_write_seq(dsi, 0x0d, 0x07); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0xf4); + mipi_dsi_generic_write_seq(dsi, 0x0d, 0xc0); + mipi_dsi_generic_write_seq(dsi, 0x0e, 0xff); + mipi_dsi_generic_write_seq(dsi, 0x0f, 0xff); + mipi_dsi_generic_write_seq(dsi, 0x10, 0x33); + mipi_dsi_generic_write_seq(dsi, 0x11, 0x6f); + mipi_dsi_generic_write_seq(dsi, 0x12, 0x6e); + mipi_dsi_generic_write_seq(dsi, 0x13, 0xa6); + mipi_dsi_generic_write_seq(dsi, 0x14, 0x80); + mipi_dsi_generic_write_seq(dsi, 0x15, 0x02); + mipi_dsi_generic_write_seq(dsi, 0x16, 0x38); + mipi_dsi_generic_write_seq(dsi, 0x17, 0xd3); + mipi_dsi_generic_write_seq(dsi, 0x18, 0x3a); + mipi_dsi_generic_write_seq(dsi, 0x19, 0xba); + mipi_dsi_generic_write_seq(dsi, 0x1a, 0xcc); + mipi_dsi_generic_write_seq(dsi, 0x1b, 0x01); + + ret = mipi_dsi_dcs_nop(dsi); + if (ret < 0) { + dev_err(dev, "Failed to nop: %d\n", ret); + return ret; + } + msleep(32); + + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x38); + mipi_dsi_generic_write_seq(dsi, 0x18, 0x13); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0xd1); + mipi_dsi_generic_write_seq(dsi, 0xd3, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xd0, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xd2, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xd4, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xb4, 0x01); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0xf9); + mipi_dsi_generic_write_seq(dsi, 0x00, 0xaf); + mipi_dsi_generic_write_seq(dsi, 0x1d, 0x37); + mipi_dsi_generic_write_seq(dsi, 0x44, 0x0a, 0x7b); + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x00); + mipi_dsi_generic_write_seq(dsi, 0xfa, 0x01); + mipi_dsi_generic_write_seq(dsi, 0xc2, 0x08); + mipi_dsi_generic_write_seq(dsi, 0x35, 0x00); + mipi_dsi_generic_write_seq(dsi, 0x51, 0x05, 0x42); + + ret = mipi_dsi_dcs_exit_sleep_mode(dsi); + if (ret < 0) { + dev_err(dev, "Failed to exit sleep mode: %d\n", ret); + return ret; + } + msleep(100); + + ret = mipi_dsi_dcs_set_display_on(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display on: %d\n", ret); + return ret; + } + + return 0; +} + +static int rm692e5_disable(struct drm_panel *panel) +{ + struct rm692e5_panel *ctx = to_rm692e5_panel(panel); + struct mipi_dsi_device *dsi = ctx->dsi; + struct device *dev = &dsi->dev; + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + mipi_dsi_generic_write_seq(dsi, 0xfe, 0x00); + + ret = mipi_dsi_dcs_set_display_off(dsi); + if (ret < 0) { + dev_err(dev, "Failed to set display off: %d\n", ret); + return ret; + } + + 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(100); + + return 0; +} + +static int rm692e5_prepare(struct drm_panel *panel) +{ + struct rm692e5_panel *ctx = to_rm692e5_panel(panel); + struct drm_dsc_picture_parameter_set pps; + struct device *dev = &ctx->dsi->dev; + int ret; + + if (ctx->prepared) + return 0; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators: %d\n", ret); + return ret; + } + + rm692e5_reset(ctx); + + ret = rm692e5_on(ctx); + if (ret < 0) { + dev_err(dev, "Failed to initialize panel: %d\n", ret); + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + return ret; + } + + drm_dsc_pps_payload_pack(&pps, &ctx->dsc); + + ret = mipi_dsi_picture_parameter_set(ctx->dsi, &pps); + if (ret < 0) { + dev_err(panel->dev, "failed to transmit PPS: %d\n", ret); + return ret; + } + + ret = mipi_dsi_compression_mode(ctx->dsi, true); + if (ret < 0) { + dev_err(dev, "failed to enable compression mode: %d\n", ret); + return ret; + } + + msleep(28); + + mipi_dsi_generic_write_seq(ctx->dsi, 0xfe, 0x40); + + /* 0x05 -> 90Hz, 0x00 -> 60Hz */ + mipi_dsi_generic_write_seq(ctx->dsi, 0xbd, 0x05); + + mipi_dsi_generic_write_seq(ctx->dsi, 0xfe, 0x00); + + ctx->prepared = true; + + return 0; +} + +static int rm692e5_unprepare(struct drm_panel *panel) +{ + struct rm692e5_panel *ctx = to_rm692e5_panel(panel); + + if (!ctx->prepared) + return 0; + + gpiod_set_value_cansleep(ctx->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + + ctx->prepared = false; + return 0; +} + +static const struct drm_display_mode rm692e5_mode = { + .clock = (1224 + 32 + 8 + 8) * (2700 + 8 + 2 + 8) * 90 / 1000, + .hdisplay = 1224, + .hsync_start = 1224 + 32, + .hsync_end = 1224 + 32 + 8, + .htotal = 1224 + 32 + 8 + 8, + .vdisplay = 2700, + .vsync_start = 2700 + 8, + .vsync_end = 2700 + 8 + 2, + .vtotal = 2700 + 8 + 2 + 8, + .width_mm = 68, + .height_mm = 150, +}; + +static int rm692e5_get_modes(struct drm_panel *panel, + struct drm_connector *connector) +{ + struct drm_display_mode *mode; + + mode = drm_mode_duplicate(connector->dev, &rm692e5_mode); + if (!mode) + return -ENOMEM; + + drm_mode_set_name(mode); + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs rm692e5_panel_funcs = { + .prepare = rm692e5_prepare, + .unprepare = rm692e5_unprepare, + .disable = rm692e5_disable, + .get_modes = rm692e5_get_modes, +}; + +static int rm692e5_bl_update_status(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness = backlight_get_brightness(bl); + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return 0; +} + +static int rm692e5_bl_get_brightness(struct backlight_device *bl) +{ + struct mipi_dsi_device *dsi = bl_get_data(bl); + u16 brightness; + int ret; + + dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; + + ret = mipi_dsi_dcs_get_display_brightness_large(dsi, &brightness); + if (ret < 0) + return ret; + + dsi->mode_flags |= MIPI_DSI_MODE_LPM; + + return brightness; +} + +static const struct backlight_ops rm692e5_bl_ops = { + .update_status = rm692e5_bl_update_status, + .get_brightness = rm692e5_bl_get_brightness, +}; + +static struct backlight_device * +rm692e5_create_backlight(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + const struct backlight_properties props = { + .type = BACKLIGHT_RAW, + .brightness = 4095, + .max_brightness = 4095, + }; + + return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, + &rm692e5_bl_ops, &props); +} + +static int rm692e5_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct rm692e5_panel *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->supplies[0].supply = "vddio"; + ctx->supplies[1].supply = "dvdd"; + ctx->supplies[2].supply = "vci"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ctx->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), + "Failed to get reset-gpios\n"); + + ctx->dsi = dsi; + mipi_dsi_set_drvdata(dsi, ctx); + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_NO_EOT_PACKET | + MIPI_DSI_CLOCK_NON_CONTINUOUS; + + drm_panel_init(&ctx->panel, dev, &rm692e5_panel_funcs, + DRM_MODE_CONNECTOR_DSI); + ctx->panel.prepare_prev_first = true; + + ctx->panel.backlight = rm692e5_create_backlight(dsi); + if (IS_ERR(ctx->panel.backlight)) + return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight), + "Failed to create backlight\n"); + + drm_panel_add(&ctx->panel); + + /* This panel only supports DSC; unconditionally enable it */ + dsi->dsc = &ctx->dsc; + + /* TODO: Pass slice_per_pkt = 2 */ + ctx->dsc.dsc_version_major = 1; + ctx->dsc.dsc_version_minor = 1; + ctx->dsc.slice_height = 60; + ctx->dsc.slice_width = 1224; + + ctx->dsc.slice_count = 1224 / ctx->dsc.slice_width; + ctx->dsc.bits_per_component = 8; + ctx->dsc.bits_per_pixel = 8 << 4; /* 4 fractional bits */ + ctx->dsc.block_pred_enable = true; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) { + dev_err(dev, "Failed to attach to DSI host: %d\n", ret); + drm_panel_remove(&ctx->panel); + return ret; + } + + return 0; +} + +static void rm692e5_remove(struct mipi_dsi_device *dsi) +{ + struct rm692e5_panel *ctx = mipi_dsi_get_drvdata(dsi); + int ret; + + ret = mipi_dsi_detach(dsi); + if (ret < 0) + dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); + + drm_panel_remove(&ctx->panel); +} + +static const struct of_device_id rm692e5_of_match[] = { + { .compatible = "fairphone,fp5-rm692e5-boe" }, + { } +}; +MODULE_DEVICE_TABLE(of, rm692e5_of_match); + +static struct mipi_dsi_driver rm692e5_driver = { + .probe = rm692e5_probe, + .remove = rm692e5_remove, + .driver = { + .name = "panel-rm692e5-boe-amoled", + .of_match_table = rm692e5_of_match, + }, +}; +module_mipi_dsi_driver(rm692e5_driver); + +MODULE_DESCRIPTION("DRM driver for rm692e5-equipped DSI panels"); +MODULE_LICENSE("GPL"); From db0f246c39be6971cdaa2b9326f7cb6cdfd8f11b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Almeida?= Date: Fri, 29 Sep 2023 11:25:09 +0200 Subject: [PATCH 22/80] drm/doc: Document DRM device reset expectations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a section that specifies how to deal with DRM device resets for kernel and userspace drivers. Signed-off-by: André Almeida Acked-by: Pekka Paalanen Acked-by: Sebastian Wick Reviewed-by: Christian König Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20230929092509.42042-1-andrealmeid@igalia.com --- Documentation/gpu/drm-uapi.rst | 77 ++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/Documentation/gpu/drm-uapi.rst b/Documentation/gpu/drm-uapi.rst index eef5fd19bc92..632989df3727 100644 --- a/Documentation/gpu/drm-uapi.rst +++ b/Documentation/gpu/drm-uapi.rst @@ -285,6 +285,83 @@ for GPU1 and GPU2 from different vendors, and a third handler for mmapped regular files. Threads cause additional pain with signal handling as well. +Device reset +============ + +The GPU stack is really complex and is prone to errors, from hardware bugs, +faulty applications and everything in between the many layers. Some errors +require resetting the device in order to make the device usable again. This +section describes the expectations for DRM and usermode drivers when a +device resets and how to propagate the reset status. + +Device resets can not be disabled without tainting the kernel, which can lead to +hanging the entire kernel through shrinkers/mmu_notifiers. Userspace role in +device resets is to propagate the message to the application and apply any +special policy for blocking guilty applications, if any. Corollary is that +debugging a hung GPU context require hardware support to be able to preempt such +a GPU context while it's stopped. + +Kernel Mode Driver +------------------ + +The KMD is responsible for checking if the device needs a reset, and to perform +it as needed. Usually a hang is detected when a job gets stuck executing. KMD +should keep track of resets, because userspace can query any time about the +reset status for a specific context. This is needed to propagate to the rest of +the stack that a reset has happened. Currently, this is implemented by each +driver separately, with no common DRM interface. Ideally this should be properly +integrated at DRM scheduler to provide a common ground for all drivers. After a +reset, KMD should reject new command submissions for affected contexts. + +User Mode Driver +---------------- + +After command submission, UMD should check if the submission was accepted or +rejected. After a reset, KMD should reject submissions, and UMD can issue an +ioctl to the KMD to check the reset status, and this can be checked more often +if the UMD requires it. After detecting a reset, UMD will then proceed to report +it to the application using the appropriate API error code, as explained in the +section below about robustness. + +Robustness +---------- + +The only way to try to keep a graphical API context working after a reset is if +it complies with the robustness aspects of the graphical API that it is using. + +Graphical APIs provide ways to applications to deal with device resets. However, +there is no guarantee that the app will use such features correctly, and a +userspace that doesn't support robust interfaces (like a non-robust +OpenGL context or API without any robustness support like libva) leave the +robustness handling entirely to the userspace driver. There is no strong +community consensus on what the userspace driver should do in that case, +since all reasonable approaches have some clear downsides. + +OpenGL +~~~~~~ + +Apps using OpenGL should use the available robust interfaces, like the +extension ``GL_ARB_robustness`` (or ``GL_EXT_robustness`` for OpenGL ES). This +interface tells if a reset has happened, and if so, all the context state is +considered lost and the app proceeds by creating new ones. There's no consensus +on what to do to if robustness is not in use. + +Vulkan +~~~~~~ + +Apps using Vulkan should check for ``VK_ERROR_DEVICE_LOST`` for submissions. +This error code means, among other things, that a device reset has happened and +it needs to recreate the contexts to keep going. + +Reporting causes of resets +-------------------------- + +Apart from propagating the reset through the stack so apps can recover, it's +really useful for driver developers to learn more about what caused the reset in +the first place. DRM devices should make use of devcoredump to store relevant +information about the reset, so this information can be added to user bug +reports. + .. _drm_driver_ioctl: IOCTL Support on Device Nodes From 653e2486450a0d973d15f6ae870cfdfad1b8fe17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 20 Sep 2023 17:03:38 +0300 Subject: [PATCH 23/80] drm/vblank: Warn when silently cancelling vblank works MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Silently cancelling vblank works is a bit rude, especially if said works do any resource management (eg. free memory). WARN if we ever hit this. TODO: Maybe drm_crtc_vblank_off() should wait for any pending work to reach its target vblank before actually doing anything drastic? Cc: Lyude Paul Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20230920140339.28322-2-ville.syrjala@linux.intel.com Reviewed-by: Lyude Paul --- drivers/gpu/drm/drm_vblank_work.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/drm_vblank_work.c b/drivers/gpu/drm/drm_vblank_work.c index bd481fdd6b87..43cd5c0f4f6f 100644 --- a/drivers/gpu/drm/drm_vblank_work.c +++ b/drivers/gpu/drm/drm_vblank_work.c @@ -73,6 +73,9 @@ void drm_vblank_cancel_pending_works(struct drm_vblank_crtc *vblank) assert_spin_locked(&vblank->dev->event_lock); + drm_WARN_ONCE(vblank->dev, !list_empty(&vblank->pending_work), + "Cancelling pending vblank works!\n"); + list_for_each_entry_safe(work, next, &vblank->pending_work, node) { list_del_init(&work->node); drm_vblank_put(vblank->dev, vblank->pipe); From 51dcc15b5b0fb548c47cf5188f88d86fe79312bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Larumbe?= Date: Fri, 29 Sep 2023 19:14:27 +0100 Subject: [PATCH 24/80] drm/panfrost: Add cycle count GPU register definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These GPU registers will be used when programming the cycle counter, which we need for providing accurate fdinfo drm-cycles values to user space. Signed-off-by: Adrián Larumbe Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20230929181616.2769345-2-adrian.larumbe@collabora.com --- drivers/gpu/drm/panfrost/panfrost_regs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_regs.h b/drivers/gpu/drm/panfrost/panfrost_regs.h index 919f44ac853d..55ec807550b3 100644 --- a/drivers/gpu/drm/panfrost/panfrost_regs.h +++ b/drivers/gpu/drm/panfrost/panfrost_regs.h @@ -46,6 +46,8 @@ #define GPU_CMD_SOFT_RESET 0x01 #define GPU_CMD_PERFCNT_CLEAR 0x03 #define GPU_CMD_PERFCNT_SAMPLE 0x04 +#define GPU_CMD_CYCLE_COUNT_START 0x05 +#define GPU_CMD_CYCLE_COUNT_STOP 0x06 #define GPU_CMD_CLEAN_CACHES 0x07 #define GPU_CMD_CLEAN_INV_CACHES 0x08 #define GPU_STATUS 0x34 @@ -73,6 +75,9 @@ #define GPU_PRFCNT_TILER_EN 0x74 #define GPU_PRFCNT_MMU_L2_EN 0x7c +#define GPU_CYCLE_COUNT_LO 0x90 +#define GPU_CYCLE_COUNT_HI 0x94 + #define GPU_THREAD_MAX_THREADS 0x0A0 /* (RO) Maximum number of threads per core */ #define GPU_THREAD_MAX_WORKGROUP_SIZE 0x0A4 /* (RO) Maximum workgroup size */ #define GPU_THREAD_MAX_BARRIER_SIZE 0x0A8 /* (RO) Maximum threads waiting at a barrier */ From f11b0417eec21ade937da866363433cc0b8b396c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Larumbe?= Date: Fri, 29 Sep 2023 19:14:28 +0100 Subject: [PATCH 25/80] drm/panfrost: Add fdinfo support GPU load metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drm-stats fdinfo tags made available to user space are drm-engine, drm-cycles, drm-max-freq and drm-curfreq, one per job slot. This deviates from standard practice in other DRM drivers, where a single set of key:value pairs is provided for the whole render engine. However, Panfrost has separate queues for fragment and vertex/tiler jobs, so a decision was made to calculate bus cycles and workload times separately. Maximum operating frequency is calculated at devfreq initialisation time. Current frequency is made available to user space because nvtop uses it when performing engine usage calculations. It is important to bear in mind that both GPU cycle and kernel time numbers provided are at best rough estimations, and always reported in excess from the actual figure because of two reasons: - Excess time because of the delay between the end of a job processing, the subsequent job IRQ and the actual time of the sample. - Time spent in the engine queue waiting for the GPU to pick up the next job. To avoid race conditions during enablement/disabling, a reference counting mechanism was introduced, and a job flag that tells us whether a given job increased the refcount. This is necessary, because user space can toggle cycle counting through a debugfs file, and a given job might have been in flight by the time cycle counting was disabled. The main goal of the debugfs cycle counter knob is letting tools like nvtop or IGT's gputop switch it at any time, to avoid power waste in case no engine usage measuring is necessary. Also add a documentation file explaining the possible values for fdinfo's engine keystrings and Panfrost-specific drm-curfreq- pairs. Signed-off-by: Adrián Larumbe Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20230929181616.2769345-3-adrian.larumbe@collabora.com --- Documentation/gpu/drm-usage-stats.rst | 1 + Documentation/gpu/panfrost.rst | 40 ++++++++++++++ MAINTAINERS | 1 + drivers/gpu/drm/panfrost/Makefile | 2 + drivers/gpu/drm/panfrost/panfrost_debugfs.c | 21 ++++++++ drivers/gpu/drm/panfrost/panfrost_debugfs.h | 14 +++++ drivers/gpu/drm/panfrost/panfrost_devfreq.c | 8 +++ drivers/gpu/drm/panfrost/panfrost_devfreq.h | 3 ++ drivers/gpu/drm/panfrost/panfrost_device.c | 2 + drivers/gpu/drm/panfrost/panfrost_device.h | 13 +++++ drivers/gpu/drm/panfrost/panfrost_drv.c | 58 ++++++++++++++++++++- drivers/gpu/drm/panfrost/panfrost_gpu.c | 41 +++++++++++++++ drivers/gpu/drm/panfrost/panfrost_gpu.h | 4 ++ drivers/gpu/drm/panfrost/panfrost_job.c | 24 +++++++++ drivers/gpu/drm/panfrost/panfrost_job.h | 5 ++ 15 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 Documentation/gpu/panfrost.rst create mode 100644 drivers/gpu/drm/panfrost/panfrost_debugfs.c create mode 100644 drivers/gpu/drm/panfrost/panfrost_debugfs.h diff --git a/Documentation/gpu/drm-usage-stats.rst b/Documentation/gpu/drm-usage-stats.rst index fe35a291ff3e..8d963cd7c1b7 100644 --- a/Documentation/gpu/drm-usage-stats.rst +++ b/Documentation/gpu/drm-usage-stats.rst @@ -169,3 +169,4 @@ Driver specific implementations ------------------------------- :ref:`i915-usage-stats` +:ref:`panfrost-usage-stats` diff --git a/Documentation/gpu/panfrost.rst b/Documentation/gpu/panfrost.rst new file mode 100644 index 000000000000..b80e41f4b2c5 --- /dev/null +++ b/Documentation/gpu/panfrost.rst @@ -0,0 +1,40 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +========================= + drm/Panfrost Mali Driver +========================= + +.. _panfrost-usage-stats: + +Panfrost DRM client usage stats implementation +============================================== + +The drm/Panfrost driver implements the DRM client usage stats specification as +documented in :ref:`drm-client-usage-stats`. + +Example of the output showing the implemented key value pairs and entirety of +the currently possible format options: + +:: + pos: 0 + flags: 02400002 + mnt_id: 27 + ino: 531 + drm-driver: panfrost + drm-client-id: 14 + drm-engine-fragment: 1846584880 ns + drm-cycles-fragment: 1424359409 + drm-maxfreq-fragment: 799999987 Hz + drm-curfreq-fragment: 799999987 Hz + drm-engine-vertex-tiler: 71932239 ns + drm-cycles-vertex-tiler: 52617357 + drm-maxfreq-vertex-tiler: 799999987 Hz + drm-curfreq-vertex-tiler: 799999987 Hz + drm-total-memory: 290 MiB + drm-shared-memory: 0 MiB + drm-active-memory: 226 MiB + drm-resident-memory: 36496 KiB + drm-purgeable-memory: 128 KiB + +Possible `drm-engine-` key names are: `fragment`, and `vertex-tiler`. +`drm-curfreq-` values convey the current operating frequency for that engine. diff --git a/MAINTAINERS b/MAINTAINERS index d787a18a76c4..46ca5c4affdb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1620,6 +1620,7 @@ R: Steven Price L: dri-devel@lists.freedesktop.org S: Supported T: git git://anongit.freedesktop.org/drm/drm-misc +F: Documentation/gpu/panfrost.rst F: drivers/gpu/drm/panfrost/ F: include/uapi/drm/panfrost_drm.h diff --git a/drivers/gpu/drm/panfrost/Makefile b/drivers/gpu/drm/panfrost/Makefile index 7da2b3f02ed9..2c01c1e7523e 100644 --- a/drivers/gpu/drm/panfrost/Makefile +++ b/drivers/gpu/drm/panfrost/Makefile @@ -12,4 +12,6 @@ panfrost-y := \ panfrost_perfcnt.o \ panfrost_dump.o +panfrost-$(CONFIG_DEBUG_FS) += panfrost_debugfs.o + obj-$(CONFIG_DRM_PANFROST) += panfrost.o diff --git a/drivers/gpu/drm/panfrost/panfrost_debugfs.c b/drivers/gpu/drm/panfrost/panfrost_debugfs.c new file mode 100644 index 000000000000..72d4286a6bf7 --- /dev/null +++ b/drivers/gpu/drm/panfrost/panfrost_debugfs.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright 2023 Collabora ltd. */ +/* Copyright 2023 Amazon.com, Inc. or its affiliates. */ + +#include +#include +#include +#include +#include + +#include "panfrost_device.h" +#include "panfrost_gpu.h" +#include "panfrost_debugfs.h" + +void panfrost_debugfs_init(struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct panfrost_device *pfdev = platform_get_drvdata(to_platform_device(dev->dev)); + + debugfs_create_atomic_t("profile", 0600, minor->debugfs_root, &pfdev->profile_mode); +} diff --git a/drivers/gpu/drm/panfrost/panfrost_debugfs.h b/drivers/gpu/drm/panfrost/panfrost_debugfs.h new file mode 100644 index 000000000000..c5af5f35877f --- /dev/null +++ b/drivers/gpu/drm/panfrost/panfrost_debugfs.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2023 Collabora ltd. + * Copyright 2023 Amazon.com, Inc. or its affiliates. + */ + +#ifndef PANFROST_DEBUGFS_H +#define PANFROST_DEBUGFS_H + +#ifdef CONFIG_DEBUG_FS +void panfrost_debugfs_init(struct drm_minor *minor); +#endif + +#endif /* PANFROST_DEBUGFS_H */ diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.c b/drivers/gpu/drm/panfrost/panfrost_devfreq.c index 58dfb15a8757..28caffc689e2 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.c +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.c @@ -58,6 +58,7 @@ static int panfrost_devfreq_get_dev_status(struct device *dev, spin_lock_irqsave(&pfdevfreq->lock, irqflags); panfrost_devfreq_update_utilization(pfdevfreq); + pfdevfreq->current_frequency = status->current_frequency; status->total_time = ktime_to_ns(ktime_add(pfdevfreq->busy_time, pfdevfreq->idle_time)); @@ -117,6 +118,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) struct devfreq *devfreq; struct thermal_cooling_device *cooling; struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq; + unsigned long freq = ULONG_MAX; if (pfdev->comp->num_supplies > 1) { /* @@ -172,6 +174,12 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev) return ret; } + /* Find the fastest defined rate */ + opp = dev_pm_opp_find_freq_floor(dev, &freq); + if (IS_ERR(opp)) + return PTR_ERR(opp); + pfdevfreq->fast_rate = freq; + dev_pm_opp_put(opp); /* diff --git a/drivers/gpu/drm/panfrost/panfrost_devfreq.h b/drivers/gpu/drm/panfrost/panfrost_devfreq.h index 1514c1f9d91c..48dbe185f206 100644 --- a/drivers/gpu/drm/panfrost/panfrost_devfreq.h +++ b/drivers/gpu/drm/panfrost/panfrost_devfreq.h @@ -19,6 +19,9 @@ struct panfrost_devfreq { struct devfreq_simple_ondemand_data gov_data; bool opp_of_table_added; + unsigned long current_frequency; + unsigned long fast_rate; + ktime_t busy_time; ktime_t idle_time; ktime_t time_last_update; diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index fa1a086a862b..28f7046e1b1a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -207,6 +207,8 @@ int panfrost_device_init(struct panfrost_device *pfdev) spin_lock_init(&pfdev->as_lock); + spin_lock_init(&pfdev->cycle_counter.lock); + err = panfrost_clk_init(pfdev); if (err) { dev_err(pfdev->dev, "clk init failed %d\n", err); diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index b0126b9fbadc..1e85656dc2f7 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -107,6 +107,7 @@ struct panfrost_device { struct list_head scheduled_jobs; struct panfrost_perfcnt *perfcnt; + atomic_t profile_mode; struct mutex sched_lock; @@ -121,6 +122,11 @@ struct panfrost_device { struct shrinker shrinker; struct panfrost_devfreq pfdevfreq; + + struct { + atomic_t use_count; + spinlock_t lock; + } cycle_counter; }; struct panfrost_mmu { @@ -135,12 +141,19 @@ struct panfrost_mmu { struct list_head list; }; +struct panfrost_engine_usage { + unsigned long long elapsed_ns[NUM_JOB_SLOTS]; + unsigned long long cycles[NUM_JOB_SLOTS]; +}; + struct panfrost_file_priv { struct panfrost_device *pfdev; struct drm_sched_entity sched_entity[NUM_JOB_SLOTS]; struct panfrost_mmu *mmu; + + struct panfrost_engine_usage engine_usage; }; static inline struct panfrost_device *to_panfrost_device(struct drm_device *ddev) diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index a2ab99698ca8..97e5bc4a82c8 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -20,6 +20,7 @@ #include "panfrost_job.h" #include "panfrost_gpu.h" #include "panfrost_perfcnt.h" +#include "panfrost_debugfs.h" static bool unstable_ioctls; module_param_unsafe(unstable_ioctls, bool, 0600); @@ -267,6 +268,7 @@ static int panfrost_ioctl_submit(struct drm_device *dev, void *data, job->requirements = args->requirements; job->flush_id = panfrost_gpu_get_latest_flush_id(pfdev); job->mmu = file_priv->mmu; + job->engine_usage = &file_priv->engine_usage; slot = panfrost_job_get_slot(job); @@ -523,7 +525,56 @@ static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = { PANFROST_IOCTL(MADVISE, madvise, DRM_RENDER_ALLOW), }; -DEFINE_DRM_GEM_FOPS(panfrost_drm_driver_fops); +static void panfrost_gpu_show_fdinfo(struct panfrost_device *pfdev, + struct panfrost_file_priv *panfrost_priv, + struct drm_printer *p) +{ + int i; + + /* + * IMPORTANT NOTE: drm-cycles and drm-engine measurements are not + * accurate, as they only provide a rough estimation of the number of + * GPU cycles and CPU time spent in a given context. This is due to two + * different factors: + * - Firstly, we must consider the time the CPU and then the kernel + * takes to process the GPU interrupt, which means additional time and + * GPU cycles will be added in excess to the real figure. + * - Secondly, the pipelining done by the Job Manager (2 job slots per + * engine) implies there is no way to know exactly how much time each + * job spent on the GPU. + */ + + static const char * const engine_names[] = { + "fragment", "vertex-tiler", "compute-only" + }; + + BUILD_BUG_ON(ARRAY_SIZE(engine_names) != NUM_JOB_SLOTS); + + for (i = 0; i < NUM_JOB_SLOTS - 1; i++) { + drm_printf(p, "drm-engine-%s:\t%llu ns\n", + engine_names[i], panfrost_priv->engine_usage.elapsed_ns[i]); + drm_printf(p, "drm-cycles-%s:\t%llu\n", + engine_names[i], panfrost_priv->engine_usage.cycles[i]); + drm_printf(p, "drm-maxfreq-%s:\t%lu Hz\n", + engine_names[i], pfdev->pfdevfreq.fast_rate); + drm_printf(p, "drm-curfreq-%s:\t%lu Hz\n", + engine_names[i], pfdev->pfdevfreq.current_frequency); + } +} + +static void panfrost_show_fdinfo(struct drm_printer *p, struct drm_file *file) +{ + struct drm_device *dev = file->minor->dev; + struct panfrost_device *pfdev = dev->dev_private; + + panfrost_gpu_show_fdinfo(pfdev, file->driver_priv, p); +} + +static const struct file_operations panfrost_drm_driver_fops = { + .owner = THIS_MODULE, + DRM_GEM_FOPS, + .show_fdinfo = drm_show_fdinfo, +}; /* * Panfrost driver version: @@ -535,6 +586,7 @@ static const struct drm_driver panfrost_drm_driver = { .driver_features = DRIVER_RENDER | DRIVER_GEM | DRIVER_SYNCOBJ, .open = panfrost_open, .postclose = panfrost_postclose, + .show_fdinfo = panfrost_show_fdinfo, .ioctls = panfrost_drm_driver_ioctls, .num_ioctls = ARRAY_SIZE(panfrost_drm_driver_ioctls), .fops = &panfrost_drm_driver_fops, @@ -546,6 +598,10 @@ static const struct drm_driver panfrost_drm_driver = { .gem_create_object = panfrost_gem_create_object, .gem_prime_import_sg_table = panfrost_gem_prime_import_sg_table, + +#ifdef CONFIG_DEBUG_FS + .debugfs_init = panfrost_debugfs_init, +#endif }; static int panfrost_probe(struct platform_device *pdev) diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c index 2faa344d89ee..f0be7e19b13e 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c @@ -73,6 +73,13 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev) gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_MASK_ALL); gpu_write(pfdev, GPU_INT_MASK, GPU_IRQ_MASK_ALL); + /* + * All in-flight jobs should have released their cycle + * counter references upon reset, but let us make sure + */ + if (drm_WARN_ON(pfdev->ddev, atomic_read(&pfdev->cycle_counter.use_count) != 0)) + atomic_set(&pfdev->cycle_counter.use_count, 0); + return 0; } @@ -321,6 +328,40 @@ static void panfrost_gpu_init_features(struct panfrost_device *pfdev) pfdev->features.shader_present, pfdev->features.l2_present); } +void panfrost_cycle_counter_get(struct panfrost_device *pfdev) +{ + if (atomic_inc_not_zero(&pfdev->cycle_counter.use_count)) + return; + + spin_lock(&pfdev->cycle_counter.lock); + if (atomic_inc_return(&pfdev->cycle_counter.use_count) == 1) + gpu_write(pfdev, GPU_CMD, GPU_CMD_CYCLE_COUNT_START); + spin_unlock(&pfdev->cycle_counter.lock); +} + +void panfrost_cycle_counter_put(struct panfrost_device *pfdev) +{ + if (atomic_add_unless(&pfdev->cycle_counter.use_count, -1, 1)) + return; + + spin_lock(&pfdev->cycle_counter.lock); + if (atomic_dec_return(&pfdev->cycle_counter.use_count) == 0) + gpu_write(pfdev, GPU_CMD, GPU_CMD_CYCLE_COUNT_STOP); + spin_unlock(&pfdev->cycle_counter.lock); +} + +unsigned long long panfrost_cycle_counter_read(struct panfrost_device *pfdev) +{ + u32 hi, lo; + + do { + hi = gpu_read(pfdev, GPU_CYCLE_COUNT_HI); + lo = gpu_read(pfdev, GPU_CYCLE_COUNT_LO); + } while (hi != gpu_read(pfdev, GPU_CYCLE_COUNT_HI)); + + return ((u64)hi << 32) | lo; +} + void panfrost_gpu_power_on(struct panfrost_device *pfdev) { int ret; diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.h b/drivers/gpu/drm/panfrost/panfrost_gpu.h index 468c51e7e46d..876fdad9f721 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gpu.h +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.h @@ -16,6 +16,10 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev); void panfrost_gpu_power_on(struct panfrost_device *pfdev); void panfrost_gpu_power_off(struct panfrost_device *pfdev); +void panfrost_cycle_counter_get(struct panfrost_device *pfdev); +void panfrost_cycle_counter_put(struct panfrost_device *pfdev); +unsigned long long panfrost_cycle_counter_read(struct panfrost_device *pfdev); + void panfrost_gpu_amlogic_quirk(struct panfrost_device *pfdev); #endif diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c index 033f5e684707..fb16de2d0420 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.c +++ b/drivers/gpu/drm/panfrost/panfrost_job.c @@ -159,6 +159,16 @@ panfrost_dequeue_job(struct panfrost_device *pfdev, int slot) struct panfrost_job *job = pfdev->jobs[slot][0]; WARN_ON(!job); + if (job->is_profiled) { + if (job->engine_usage) { + job->engine_usage->elapsed_ns[slot] += + ktime_to_ns(ktime_sub(ktime_get(), job->start_time)); + job->engine_usage->cycles[slot] += + panfrost_cycle_counter_read(pfdev) - job->start_cycles; + } + panfrost_cycle_counter_put(job->pfdev); + } + pfdev->jobs[slot][0] = pfdev->jobs[slot][1]; pfdev->jobs[slot][1] = NULL; @@ -233,6 +243,13 @@ static void panfrost_job_hw_submit(struct panfrost_job *job, int js) subslot = panfrost_enqueue_job(pfdev, js, job); /* Don't queue the job if a reset is in progress */ if (!atomic_read(&pfdev->reset.pending)) { + if (atomic_read(&pfdev->profile_mode)) { + panfrost_cycle_counter_get(pfdev); + job->is_profiled = true; + job->start_time = ktime_get(); + job->start_cycles = panfrost_cycle_counter_read(pfdev); + } + job_write(pfdev, JS_COMMAND_NEXT(js), JS_COMMAND_START); dev_dbg(pfdev->dev, "JS: Submitting atom %p to js[%d][%d] with head=0x%llx AS %d", @@ -660,10 +677,14 @@ panfrost_reset(struct panfrost_device *pfdev, * stuck jobs. Let's make sure the PM counters stay balanced by * manually calling pm_runtime_put_noidle() and * panfrost_devfreq_record_idle() for each stuck job. + * Let's also make sure the cycle counting register's refcnt is + * kept balanced to prevent it from running forever */ spin_lock(&pfdev->js->job_lock); for (i = 0; i < NUM_JOB_SLOTS; i++) { for (j = 0; j < ARRAY_SIZE(pfdev->jobs[0]) && pfdev->jobs[i][j]; j++) { + if (pfdev->jobs[i][j]->is_profiled) + panfrost_cycle_counter_put(pfdev->jobs[i][j]->pfdev); pm_runtime_put_noidle(pfdev->dev); panfrost_devfreq_record_idle(&pfdev->pfdevfreq); } @@ -926,6 +947,9 @@ void panfrost_job_close(struct panfrost_file_priv *panfrost_priv) } job_write(pfdev, JS_COMMAND(i), cmd); + + /* Jobs can outlive their file context */ + job->engine_usage = NULL; } } spin_unlock(&pfdev->js->job_lock); diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h index 8becc1ba0eb9..17ff808dba07 100644 --- a/drivers/gpu/drm/panfrost/panfrost_job.h +++ b/drivers/gpu/drm/panfrost/panfrost_job.h @@ -32,6 +32,11 @@ struct panfrost_job { /* Fence to be signaled by drm-sched once its done with the job */ struct dma_fence *render_done_fence; + + struct panfrost_engine_usage *engine_usage; + bool is_profiled; + ktime_t start_time; + u64 start_cycles; }; int panfrost_job_init(struct panfrost_device *pfdev); From 9ccdac7aa822f0468893e161c1a311674667da1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Larumbe?= Date: Fri, 29 Sep 2023 19:14:29 +0100 Subject: [PATCH 26/80] drm/panfrost: Add fdinfo support for memory stats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A new DRM GEM object function is added so that drm_show_memory_stats can provide more accurate memory usage numbers. Ideally, in panfrost_gem_status, the BO's purgeable flag would be checked after locking the driver's shrinker mutex, but drm_show_memory_stats takes over the drm file's object handle database spinlock, so there's potential for a race condition here. Signed-off-by: Adrián Larumbe Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20230929181616.2769345-4-adrian.larumbe@collabora.com --- drivers/gpu/drm/panfrost/panfrost_drv.c | 2 ++ drivers/gpu/drm/panfrost/panfrost_gem.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_drv.c b/drivers/gpu/drm/panfrost/panfrost_drv.c index 97e5bc4a82c8..b834777b409b 100644 --- a/drivers/gpu/drm/panfrost/panfrost_drv.c +++ b/drivers/gpu/drm/panfrost/panfrost_drv.c @@ -568,6 +568,8 @@ static void panfrost_show_fdinfo(struct drm_printer *p, struct drm_file *file) struct panfrost_device *pfdev = dev->dev_private; panfrost_gpu_show_fdinfo(pfdev, file->driver_priv, p); + + drm_show_memory_stats(p, file); } static const struct file_operations panfrost_drm_driver_fops = { diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c index 3c812fbd126f..de238b71b321 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.c +++ b/drivers/gpu/drm/panfrost/panfrost_gem.c @@ -195,6 +195,20 @@ static int panfrost_gem_pin(struct drm_gem_object *obj) return drm_gem_shmem_pin(&bo->base); } +static enum drm_gem_object_status panfrost_gem_status(struct drm_gem_object *obj) +{ + struct panfrost_gem_object *bo = to_panfrost_bo(obj); + enum drm_gem_object_status res = 0; + + if (bo->base.pages) + res |= DRM_GEM_OBJECT_RESIDENT; + + if (bo->base.madv == PANFROST_MADV_DONTNEED) + res |= DRM_GEM_OBJECT_PURGEABLE; + + return res; +} + static const struct drm_gem_object_funcs panfrost_gem_funcs = { .free = panfrost_gem_free_object, .open = panfrost_gem_open, @@ -206,6 +220,7 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = { .vmap = drm_gem_shmem_object_vmap, .vunmap = drm_gem_shmem_object_vunmap, .mmap = drm_gem_shmem_object_mmap, + .status = panfrost_gem_status, .vm_ops = &drm_gem_shmem_vm_ops, }; From 553c84892bac704e1a7999b7db7e67640a31a4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Larumbe?= Date: Fri, 29 Sep 2023 19:14:30 +0100 Subject: [PATCH 27/80] drm/drm_file: Add DRM obj's RSS reporting function for fdinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some BO's might be mapped onto physical memory chunkwise and on demand, like Panfrost's tiler heap. In this case, even though the drm_gem_shmem_object page array might already be allocated, only a very small fraction of the BO is currently backed by system memory, but drm_show_memory_stats will then proceed to add its entire virtual size to the file's total resident size regardless. This led to very unrealistic RSS sizes being reckoned for Panfrost, where said tiler heap buffer is initially allocated with a virtual size of 128 MiB, but only a small part of it will eventually be backed by system memory after successive GPU page faults. Provide a new DRM object generic function that would allow drivers to return a more accurate RSS and purgeable sizes for their BOs. Signed-off-by: Adrián Larumbe Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Rob Clark Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20230929181616.2769345-5-adrian.larumbe@collabora.com --- drivers/gpu/drm/drm_file.c | 8 +++++--- include/drm/drm_gem.h | 9 +++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index e692770ef6d3..446458aca8e9 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -964,6 +964,8 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) spin_lock(&file->table_lock); idr_for_each_entry (&file->object_idr, obj, id) { enum drm_gem_object_status s = 0; + size_t add_size = (obj->funcs && obj->funcs->rss) ? + obj->funcs->rss(obj) : obj->size; if (obj->funcs && obj->funcs->status) { s = obj->funcs->status(obj); @@ -978,7 +980,7 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) } if (s & DRM_GEM_OBJECT_RESIDENT) { - status.resident += obj->size; + status.resident += add_size; } else { /* If already purged or not yet backed by pages, don't * count it as purgeable: @@ -987,14 +989,14 @@ void drm_show_memory_stats(struct drm_printer *p, struct drm_file *file) } if (!dma_resv_test_signaled(obj->resv, dma_resv_usage_rw(true))) { - status.active += obj->size; + status.active += add_size; /* If still active, don't count as purgeable: */ s &= ~DRM_GEM_OBJECT_PURGEABLE; } if (s & DRM_GEM_OBJECT_PURGEABLE) - status.purgeable += obj->size; + status.purgeable += add_size; } spin_unlock(&file->table_lock); diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index bc9f6aa2f3fe..16364487fde9 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -208,6 +208,15 @@ struct drm_gem_object_funcs { */ enum drm_gem_object_status (*status)(struct drm_gem_object *obj); + /** + * @rss: + * + * Return resident size of the object in physical memory. + * + * Called by drm_show_memory_stats(). + */ + size_t (*rss)(struct drm_gem_object *obj); + /** * @vm_ops: * From 407c0ad5b19a477ff974a1c8007c00f01e7d04b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Larumbe?= Date: Fri, 29 Sep 2023 19:14:31 +0100 Subject: [PATCH 28/80] drm/panfrost: Implement generic DRM object RSS reporting function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BO's RSS is updated every time new pages are allocated on demand and mapped for the object at GPU page fault's IRQ handler, but only for heap buffers. The reason this is unnecessary for non-heap buffers is that they are mapped onto the GPU's VA space and backed by physical memory in their entirety at BO creation time. This calculation is unnecessary for imported PRIME objects, since heap buffers cannot be exported by our driver, and the actual BO RSS size is the one reported in its attached dmabuf structure. Signed-off-by: Adrián Larumbe Reviewed-by: Boris Brezillon Reviewed-by: Steven Price Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20230929181616.2769345-6-adrian.larumbe@collabora.com --- drivers/gpu/drm/panfrost/panfrost_gem.c | 15 +++++++++++++++ drivers/gpu/drm/panfrost/panfrost_gem.h | 5 +++++ drivers/gpu/drm/panfrost/panfrost_mmu.c | 1 + 3 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.c b/drivers/gpu/drm/panfrost/panfrost_gem.c index de238b71b321..0cf64456e29a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.c +++ b/drivers/gpu/drm/panfrost/panfrost_gem.c @@ -209,6 +209,20 @@ static enum drm_gem_object_status panfrost_gem_status(struct drm_gem_object *obj return res; } +static size_t panfrost_gem_rss(struct drm_gem_object *obj) +{ + struct panfrost_gem_object *bo = to_panfrost_bo(obj); + + if (bo->is_heap) { + return bo->heap_rss_size; + } else if (bo->base.pages) { + WARN_ON(bo->heap_rss_size); + return bo->base.base.size; + } + + return 0; +} + static const struct drm_gem_object_funcs panfrost_gem_funcs = { .free = panfrost_gem_free_object, .open = panfrost_gem_open, @@ -221,6 +235,7 @@ static const struct drm_gem_object_funcs panfrost_gem_funcs = { .vunmap = drm_gem_shmem_object_vunmap, .mmap = drm_gem_shmem_object_mmap, .status = panfrost_gem_status, + .rss = panfrost_gem_rss, .vm_ops = &drm_gem_shmem_vm_ops, }; diff --git a/drivers/gpu/drm/panfrost/panfrost_gem.h b/drivers/gpu/drm/panfrost/panfrost_gem.h index ad2877eeeccd..13c0a8149c3a 100644 --- a/drivers/gpu/drm/panfrost/panfrost_gem.h +++ b/drivers/gpu/drm/panfrost/panfrost_gem.h @@ -36,6 +36,11 @@ struct panfrost_gem_object { */ atomic_t gpu_usecount; + /* + * Object chunk size currently mapped onto physical memory + */ + size_t heap_rss_size; + bool noexec :1; bool is_heap :1; }; diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c index d54d4e7b2195..846dd697c410 100644 --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c @@ -522,6 +522,7 @@ static int panfrost_mmu_map_fault_addr(struct panfrost_device *pfdev, int as, IOMMU_WRITE | IOMMU_READ | IOMMU_NOEXEC, sgt); bomapping->active = true; + bo->heap_rss_size += SZ_2M; dev_dbg(pfdev->dev, "mapped page fault @ AS%d %llx", as, addr); From a640e3c3a573f53088e251b2fb6e7cd7a9546151 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:32:06 -0700 Subject: [PATCH 29/80] drm/amd/pm: Annotate struct smu10_voltage_dependency_table with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct smu10_voltage_dependency_table. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Evan Quan Cc: Alex Deucher Cc: "Christian König" Cc: "Pan, Xinhui" Cc: David Airlie Cc: Daniel Vetter Cc: Xiaojian Du Cc: Huang Rui Cc: Kevin Wang Cc: amd-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Signed-off-by: Kees Cook Acked-by: Alex Deucher Reviewed-by: Gustavo A. R. Silva Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20230922173216.3823169-1-keescook@chromium.org --- drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h index 808e0ecbe1f0..42adc2a3dcbc 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu10_hwmgr.h @@ -192,7 +192,7 @@ struct smu10_clock_voltage_dependency_record { struct smu10_voltage_dependency_table { uint32_t count; - struct smu10_clock_voltage_dependency_record entries[]; + struct smu10_clock_voltage_dependency_record entries[] __counted_by(count); }; struct smu10_clock_voltage_information { From ac8e62ab25f2b8d7e0077093d66f00419f382c4b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:32:07 -0700 Subject: [PATCH 30/80] drm/amdgpu/discovery: Annotate struct ip_hw_instance with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct ip_hw_instance. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Alex Deucher Cc: "Christian König" Cc: "Pan, Xinhui" Cc: David Airlie Cc: Daniel Vetter Cc: Hawking Zhang Cc: amd-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Signed-off-by: Kees Cook Acked-by: Alex Deucher Reviewed-by: Gustavo A. R. Silva Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20230922173216.3823169-2-keescook@chromium.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 8e1cfc87122d..9259bddb8202 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -654,7 +654,7 @@ struct ip_hw_instance { u8 harvest; int num_base_addresses; - u32 base_addr[]; + u32 base_addr[] __counted_by(num_base_addresses); }; struct ip_hw_id { From 8a922cf12cdeadc64abdbb1c9fe330c44a045f57 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:32:08 -0700 Subject: [PATCH 31/80] drm/i915/selftests: Annotate struct perf_series with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct perf_series. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: Tvrtko Ursulin Cc: David Airlie Cc: Daniel Vetter Cc: Chris Wilson Cc: John Harrison Cc: Andi Shyti Cc: Matthew Brost Cc: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Reviewed-by: Andrzej Hajda Reviewed-by: Andi Shyti Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20230922173216.3823169-3-keescook@chromium.org --- drivers/gpu/drm/i915/selftests/i915_request.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c index a9b79888c193..acae30a04a94 100644 --- a/drivers/gpu/drm/i915/selftests/i915_request.c +++ b/drivers/gpu/drm/i915/selftests/i915_request.c @@ -1924,7 +1924,7 @@ struct perf_stats { struct perf_series { struct drm_i915_private *i915; unsigned int nengines; - struct intel_context *ce[]; + struct intel_context *ce[] __counted_by(nengines); }; static int cmp_u32(const void *A, const void *B) From 8f5d3daad715ea55d1cfdaa3e180d3820237cad5 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:32:09 -0700 Subject: [PATCH 32/80] drm/msm/dpu: Annotate struct dpu_hw_intr with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct dpu_hw_intr. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Rob Clark Cc: Abhinav Kumar Cc: Dmitry Baryshkov Cc: Sean Paul Cc: Marijn Suijten Cc: David Airlie Cc: Daniel Vetter Cc: Bjorn Andersson Cc: linux-arm-msm@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Cc: freedreno@lists.freedesktop.org Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20230922173216.3823169-4-keescook@chromium.org --- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h index 1f2dabc54c22..d6a17f052b3a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h @@ -65,7 +65,7 @@ struct dpu_hw_intr { void (*cb)(void *arg, int irq_idx); void *arg; atomic_t count; - } irq_tbl[]; + } irq_tbl[] __counted_by(total_irqs); }; /** From 9760e50db54f3a858e67703f74f99e65784fd873 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:32:10 -0700 Subject: [PATCH 33/80] drm/nouveau/pm: Annotate struct nvkm_perfdom with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct nvkm_perfdom. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Ben Skeggs Cc: Karol Herbst Cc: Lyude Paul Cc: David Airlie Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Cc: nouveau@lists.freedesktop.org Signed-off-by: Kees Cook Reviewed-by: Lyude Paul Reviewed-by: Gustavo A. R. Silva Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20230922173216.3823169-5-keescook@chromium.org --- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 6ae25d3e7f45..c011227f7052 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -82,7 +82,7 @@ struct nvkm_perfdom { u8 mode; u32 clk; u16 signal_nr; - struct nvkm_perfsig signal[]; + struct nvkm_perfsig signal[] __counted_by(signal_nr); }; struct nvkm_funcdom { From b16cc13baca7381737e2656c0095f787328a44b4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:32:11 -0700 Subject: [PATCH 34/80] drm/vc4: Annotate struct vc4_perfmon with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct vc4_perfmon. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Emma Anholt Cc: Maxime Ripard Cc: David Airlie Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20230922173216.3823169-6-keescook@chromium.org --- drivers/gpu/drm/vc4/vc4_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index bf66499765fb..ab61e96e7e14 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -76,7 +76,7 @@ struct vc4_perfmon { * Note that counter values can't be reset, but you can fake a reset by * destroying the perfmon and creating a new one. */ - u64 counters[]; + u64 counters[] __counted_by(ncounters); }; struct vc4_dev { From 25765dde572b2266c4619d85ef0b3aeb47e24f13 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:32:12 -0700 Subject: [PATCH 35/80] drm/virtio: Annotate struct virtio_gpu_object_array with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct virtio_gpu_object_array. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: David Airlie Cc: Gerd Hoffmann Cc: Gurchetan Singh Cc: Chia-I Wu Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Cc: virtualization@lists.linux-foundation.org Signed-off-by: Kees Cook Reviewed-by: Gustavo A. R. Silva Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20230922173216.3823169-7-keescook@chromium.org --- drivers/gpu/drm/virtio/virtgpu_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 8513b671f871..96365a772f77 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -119,7 +119,7 @@ struct virtio_gpu_object_array { struct ww_acquire_ctx ticket; struct list_head next; u32 nents, total; - struct drm_gem_object *objs[]; + struct drm_gem_object *objs[] __counted_by(total); }; struct virtio_gpu_vbuffer; From 45744668746b0bcb36d58a73c2cab603090da9ac Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:32:13 -0700 Subject: [PATCH 36/80] drm/vmwgfx: Annotate struct vmw_surface_dirty with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct vmw_surface_dirty. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Zack Rusin Cc: VMware Graphics Reviewers Cc: David Airlie Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Signed-off-by: Kees Cook Reviewed-by: Zack Rusin Reviewed-by: Gustavo A. R. Silva Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20230922173216.3823169-8-keescook@chromium.org --- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 5db403ee8261..2d1d857f99ae 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -77,7 +77,7 @@ struct vmw_surface_offset { struct vmw_surface_dirty { struct vmw_surface_cache cache; u32 num_subres; - SVGA3dBox boxes[]; + SVGA3dBox boxes[] __counted_by(num_subres); }; static void vmw_user_surface_free(struct vmw_resource *res); From 9586e2401700208fac72c5f78bbf15f8fb7007cb Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 22 Sep 2023 10:32:14 -0700 Subject: [PATCH 37/80] drm/v3d: Annotate struct v3d_perfmon with __counted_by MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prepare for the coming implementation by GCC and Clang of the __counted_by attribute. Flexible array members annotated with __counted_by can have their accesses bounds-checked at run-time checking via CONFIG_UBSAN_BOUNDS (for array indexing) and CONFIG_FORTIFY_SOURCE (for strcpy/memcpy-family functions). As found with Coccinelle[1], add __counted_by for struct v3d_perfmon. [1] https://github.com/kees/kernel-tools/blob/trunk/coccinelle/examples/counted_by.cocci Cc: Emma Anholt Cc: Melissa Wen Cc: David Airlie Cc: Daniel Vetter Cc: dri-devel@lists.freedesktop.org Signed-off-by: Kees Cook Reviewed-by: Maíra Canal Signed-off-by: Christian König Link: https://patchwork.freedesktop.org/patch/msgid/20230922173216.3823169-9-keescook@chromium.org --- drivers/gpu/drm/v3d/v3d_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/v3d/v3d_drv.h b/drivers/gpu/drm/v3d/v3d_drv.h index 7f664a4b2a75..106454f28956 100644 --- a/drivers/gpu/drm/v3d/v3d_drv.h +++ b/drivers/gpu/drm/v3d/v3d_drv.h @@ -59,7 +59,7 @@ struct v3d_perfmon { * values can't be reset, but you can fake a reset by * destroying the perfmon and creating a new one. */ - u64 values[]; + u64 values[] __counted_by(ncounters); }; struct v3d_dev { From e2272bfb18ee7010790ed53690fa3f62cfde30c5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 4 Oct 2023 19:21:49 +0300 Subject: [PATCH 38/80] drm/dp: switch drm_dp_downstream_*() helpers to struct drm_edid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefer struct drm_edid where possible. With limited users for the drm_dp_downstream_*() helpers, this is fairly straightforward. Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20231004162149.2802113-1-jani.nikula@intel.com --- drivers/gpu/drm/display/drm_dp_helper.c | 39 ++++++++++--------- .../drm/i915/display/intel_display_debugfs.c | 3 +- drivers/gpu/drm/i915/display/intel_dp.c | 10 ++--- include/drm/display/drm_dp_helper.h | 12 +++--- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c index e6a78fd32380..11104dce4278 100644 --- a/drivers/gpu/drm/display/drm_dp_helper.c +++ b/drivers/gpu/drm/display/drm_dp_helper.c @@ -746,8 +746,11 @@ int drm_dp_dpcd_read_phy_link_status(struct drm_dp_aux *aux, } EXPORT_SYMBOL(drm_dp_dpcd_read_phy_link_status); -static bool is_edid_digital_input_dp(const struct edid *edid) +static bool is_edid_digital_input_dp(const struct drm_edid *drm_edid) { + /* FIXME: get rid of drm_edid_raw() */ + const struct edid *edid = drm_edid_raw(drm_edid); + return edid && edid->revision >= 4 && edid->input & DRM_EDID_INPUT_DIGITAL && (edid->input & DRM_EDID_DIGITAL_TYPE_MASK) == DRM_EDID_DIGITAL_TYPE_DP; @@ -779,13 +782,13 @@ EXPORT_SYMBOL(drm_dp_downstream_is_type); * drm_dp_downstream_is_tmds() - is the downstream facing port TMDS? * @dpcd: DisplayPort configuration data * @port_cap: port capabilities - * @edid: EDID + * @drm_edid: EDID * * Returns: whether the downstream facing port is TMDS (HDMI/DVI). */ bool drm_dp_downstream_is_tmds(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid) + const struct drm_edid *drm_edid) { if (dpcd[DP_DPCD_REV] < 0x11) { switch (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_TYPE_MASK) { @@ -798,7 +801,7 @@ bool drm_dp_downstream_is_tmds(const u8 dpcd[DP_RECEIVER_CAP_SIZE], switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { case DP_DS_PORT_TYPE_DP_DUALMODE: - if (is_edid_digital_input_dp(edid)) + if (is_edid_digital_input_dp(drm_edid)) return false; fallthrough; case DP_DS_PORT_TYPE_DVI: @@ -1036,14 +1039,14 @@ EXPORT_SYMBOL(drm_dp_downstream_max_dotclock); * drm_dp_downstream_max_tmds_clock() - extract downstream facing port max TMDS clock * @dpcd: DisplayPort configuration data * @port_cap: port capabilities - * @edid: EDID + * @drm_edid: EDID * * Returns: HDMI/DVI downstream facing port max TMDS clock in kHz on success, * or 0 if max TMDS clock not defined */ int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid) + const struct drm_edid *drm_edid) { if (!drm_dp_is_branch(dpcd)) return 0; @@ -1059,7 +1062,7 @@ int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { case DP_DS_PORT_TYPE_DP_DUALMODE: - if (is_edid_digital_input_dp(edid)) + if (is_edid_digital_input_dp(drm_edid)) return 0; /* * It's left up to the driver to check the @@ -1101,14 +1104,14 @@ EXPORT_SYMBOL(drm_dp_downstream_max_tmds_clock); * drm_dp_downstream_min_tmds_clock() - extract downstream facing port min TMDS clock * @dpcd: DisplayPort configuration data * @port_cap: port capabilities - * @edid: EDID + * @drm_edid: EDID * * Returns: HDMI/DVI downstream facing port min TMDS clock in kHz on success, * or 0 if max TMDS clock not defined */ int drm_dp_downstream_min_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid) + const struct drm_edid *drm_edid) { if (!drm_dp_is_branch(dpcd)) return 0; @@ -1124,7 +1127,7 @@ int drm_dp_downstream_min_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], switch (port_cap[0] & DP_DS_PORT_TYPE_MASK) { case DP_DS_PORT_TYPE_DP_DUALMODE: - if (is_edid_digital_input_dp(edid)) + if (is_edid_digital_input_dp(drm_edid)) return 0; fallthrough; case DP_DS_PORT_TYPE_DVI: @@ -1145,13 +1148,13 @@ EXPORT_SYMBOL(drm_dp_downstream_min_tmds_clock); * bits per component * @dpcd: DisplayPort configuration data * @port_cap: downstream facing port capabilities - * @edid: EDID + * @drm_edid: EDID * * Returns: Max bpc on success or 0 if max bpc not defined */ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid) + const struct drm_edid *drm_edid) { if (!drm_dp_is_branch(dpcd)) return 0; @@ -1169,7 +1172,7 @@ int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], case DP_DS_PORT_TYPE_DP: return 0; case DP_DS_PORT_TYPE_DP_DUALMODE: - if (is_edid_digital_input_dp(edid)) + if (is_edid_digital_input_dp(drm_edid)) return 0; fallthrough; case DP_DS_PORT_TYPE_HDMI: @@ -1362,14 +1365,14 @@ EXPORT_SYMBOL(drm_dp_downstream_id); * @m: pointer for debugfs file * @dpcd: DisplayPort configuration data * @port_cap: port capabilities - * @edid: EDID + * @drm_edid: EDID * @aux: DisplayPort AUX channel * */ void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid, + const struct drm_edid *drm_edid, struct drm_dp_aux *aux) { bool detailed_cap_info = dpcd[DP_DOWNSTREAMPORT_PRESENT] & @@ -1432,15 +1435,15 @@ void drm_dp_downstream_debug(struct seq_file *m, if (clk > 0) seq_printf(m, "\t\tMax dot clock: %d kHz\n", clk); - clk = drm_dp_downstream_max_tmds_clock(dpcd, port_cap, edid); + clk = drm_dp_downstream_max_tmds_clock(dpcd, port_cap, drm_edid); if (clk > 0) seq_printf(m, "\t\tMax TMDS clock: %d kHz\n", clk); - clk = drm_dp_downstream_min_tmds_clock(dpcd, port_cap, edid); + clk = drm_dp_downstream_min_tmds_clock(dpcd, port_cap, drm_edid); if (clk > 0) seq_printf(m, "\t\tMin TMDS clock: %d kHz\n", clk); - bpc = drm_dp_downstream_max_bpc(dpcd, port_cap, edid); + bpc = drm_dp_downstream_max_bpc(dpcd, port_cap, drm_edid); if (bpc > 0) seq_printf(m, "\t\tMax bpc: %d\n", bpc); diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 165e2c7e3126..a9a4f73db236 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -233,14 +233,13 @@ static void intel_dp_info(struct seq_file *m, struct intel_connector *connector) { struct intel_encoder *intel_encoder = intel_attached_encoder(connector); struct intel_dp *intel_dp = enc_to_intel_dp(intel_encoder); - const struct edid *edid = drm_edid_raw(connector->detect_edid); seq_printf(m, "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]); seq_printf(m, "\taudio support: %s\n", str_yes_no(connector->base.display_info.has_audio)); drm_dp_downstream_debug(m, intel_dp->dpcd, intel_dp->downstream_ports, - edid, &intel_dp->aux); + connector->detect_edid, &intel_dp->aux); } static void intel_dp_mst_info(struct seq_file *m, diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 9f40da20e88d..391f97de7898 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -4708,14 +4708,10 @@ intel_dp_update_dfp(struct intel_dp *intel_dp, { struct drm_i915_private *i915 = dp_to_i915(intel_dp); struct intel_connector *connector = intel_dp->attached_connector; - const struct edid *edid; - - /* FIXME: Get rid of drm_edid_raw() */ - edid = drm_edid_raw(drm_edid); intel_dp->dfp.max_bpc = drm_dp_downstream_max_bpc(intel_dp->dpcd, - intel_dp->downstream_ports, edid); + intel_dp->downstream_ports, drm_edid); intel_dp->dfp.max_dotclock = drm_dp_downstream_max_dotclock(intel_dp->dpcd, @@ -4724,11 +4720,11 @@ intel_dp_update_dfp(struct intel_dp *intel_dp, intel_dp->dfp.min_tmds_clock = drm_dp_downstream_min_tmds_clock(intel_dp->dpcd, intel_dp->downstream_ports, - edid); + drm_edid); intel_dp->dfp.max_tmds_clock = drm_dp_downstream_max_tmds_clock(intel_dp->dpcd, intel_dp->downstream_ports, - edid); + drm_edid); intel_dp->dfp.pcon_max_frl_bw = drm_dp_get_pcon_max_frl_bw(intel_dp->dpcd, diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 86f24a759268..08cd6dfa0fe3 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -272,8 +272,8 @@ struct drm_dp_aux_msg { }; struct cec_adapter; -struct edid; struct drm_connector; +struct drm_edid; /** * struct drm_dp_aux_cec - DisplayPort CEC-Tunneling-over-AUX @@ -507,18 +507,18 @@ bool drm_dp_downstream_is_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], u8 type); bool drm_dp_downstream_is_tmds(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid); + const struct drm_edid *drm_edid); int drm_dp_downstream_max_dotclock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4]); int drm_dp_downstream_max_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid); + const struct drm_edid *drm_edid); int drm_dp_downstream_min_tmds_clock(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid); + const struct drm_edid *drm_edid); int drm_dp_downstream_max_bpc(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid); + const struct drm_edid *drm_edid); bool drm_dp_downstream_420_passthrough(const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4]); bool drm_dp_downstream_444_to_420_conversion(const u8 dpcd[DP_RECEIVER_CAP_SIZE], @@ -530,7 +530,7 @@ int drm_dp_downstream_id(struct drm_dp_aux *aux, char id[6]); void drm_dp_downstream_debug(struct seq_file *m, const u8 dpcd[DP_RECEIVER_CAP_SIZE], const u8 port_cap[4], - const struct edid *edid, + const struct drm_edid *drm_edid, struct drm_dp_aux *aux); enum drm_mode_subconnector drm_dp_subconnector_type(const u8 dpcd[DP_RECEIVER_CAP_SIZE], From 1b063368ee71f252c5a7f86e100b3b67271608ae Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Tue, 3 Oct 2023 11:33:54 -0500 Subject: [PATCH 39/80] dt-bindings: display: newvision,nv3051d: Add Anbernic 351V Document the Anbernic RG351V panel, which is identical to the panel used in their 353 series except for in inclusion of an additional DSI format flag. Signed-off-by: Chris Morgan Acked-by: Conor Dooley Link: https://lore.kernel.org/r/20231003163355.143704-2-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231003163355.143704-2-macroalpha82@gmail.com --- .../devicetree/bindings/display/panel/newvision,nv3051d.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml index 116c1b6030a2..cce775a87f87 100644 --- a/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml +++ b/Documentation/devicetree/bindings/display/panel/newvision,nv3051d.yaml @@ -7,9 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: NewVision NV3051D based LCD panel description: | - The NewVision NV3051D is a driver chip used to drive DSI panels. For now, - this driver only supports the 640x480 panels found in the Anbernic RG353 - based devices. + The NewVision NV3051D is a driver chip used to drive DSI panels. maintainers: - Chris Morgan @@ -21,6 +19,7 @@ properties: compatible: items: - enum: + - anbernic,rg351v-panel - anbernic,rg353p-panel - anbernic,rg353v-panel - const: newvision,nv3051d From eba90a7aa2258cae4caeaa8f748506c315c30bd1 Mon Sep 17 00:00:00 2001 From: Chris Morgan Date: Tue, 3 Oct 2023 11:33:55 -0500 Subject: [PATCH 40/80] drm/panel: nv3051d: Add Support for Anbernic 351V Add support for the Anbernic 351V. Just like the 353 series the underlying vendor is unknown/unmarked (at least not visible in a non-destructive manner). The panel had slightly different init sequences and timings in the BSP kernel, but works fine with the same ones used in the existing driver. The panel will not work without the inclusion of the MIPI_DSI_CLOCK_NON_CONTINUOUS flag, and this flag prevents the 353 series from working correctly, so a new compatible string is added. Tested colors and timings using modetest and all seem to work identical to the 353 otherwise. Signed-off-by: Chris Morgan Reviewed-by: Jessica Zhang Link: https://lore.kernel.org/r/20231003163355.143704-3-macroalpha82@gmail.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231003163355.143704-3-macroalpha82@gmail.com --- drivers/gpu/drm/panel/panel-newvision-nv3051d.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c index ad98dd9322b4..79de6c886292 100644 --- a/drivers/gpu/drm/panel/panel-newvision-nv3051d.c +++ b/drivers/gpu/drm/panel/panel-newvision-nv3051d.c @@ -388,6 +388,13 @@ static int panel_nv3051d_probe(struct mipi_dsi_device *dsi) dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; + /* + * The panel in the RG351V is identical to the 353P, except it + * requires MIPI_DSI_CLOCK_NON_CONTINUOUS to operate correctly. + */ + if (of_device_is_compatible(dev->of_node, "anbernic,rg351v-panel")) + dsi->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS; + drm_panel_init(&ctx->panel, &dsi->dev, &panel_nv3051d_funcs, DRM_MODE_CONNECTOR_DSI); From 9031e0013f819ca697a65046e5b86cd1a21b86ea Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Thu, 5 Oct 2023 16:04:05 +0800 Subject: [PATCH 41/80] drm/amd/display: Fix mst hub unplug warning [Why] Unplug mst hub will cause warning. That's because dm_helpers_construct_old_payload() is changed to be called after payload removement from dc link. In dm_helpers_construct_old_payload(), We refer to the vcpi in payload allocation table of dc link to construct the old payload and payload is no longer in the table when we call the function now. [How] Refer to the mst_state to construct the number of time slot for old payload now. Note that dm_helpers_construct_old_payload() is just a quick workaround before and we are going to abandon it soon. Fixes: 5aa1dfcdf0a4 ("drm/mst: Refactor the flow for payload allocation/removement") Reviewed-by: Jerry Zuo Signed-off-by: Wayne Lin Signed-off-by: Alex Deucher Link: https://patchwork.freedesktop.org/patch/msgid/20231005080405.169841-1-Wayne.Lin@amd.com --- .../amd/display/amdgpu_dm/amdgpu_dm_helpers.c | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index c4c35f6844f4..f91d759793f0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -204,15 +204,16 @@ void dm_helpers_dp_update_branch_info( {} static void dm_helpers_construct_old_payload( - struct dc_link *link, - int pbn_per_slot, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state, struct drm_dp_mst_atomic_payload *new_payload, struct drm_dp_mst_atomic_payload *old_payload) { - struct link_mst_stream_allocation_table current_link_table = - link->mst_stream_alloc_table; - struct link_mst_stream_allocation *dc_alloc; - int i; + struct drm_dp_mst_atomic_payload *pos; + int pbn_per_slot = mst_state->pbn_div; + u8 next_payload_vc_start = mgr->next_start_slot; + u8 payload_vc_start = new_payload->vc_start_slot; + u8 allocated_time_slots; *old_payload = *new_payload; @@ -221,20 +222,17 @@ static void dm_helpers_construct_old_payload( * struct drm_dp_mst_atomic_payload are don't care fields * while calling drm_dp_remove_payload_part2() */ - for (i = 0; i < current_link_table.stream_count; i++) { - dc_alloc = - ¤t_link_table.stream_allocations[i]; - - if (dc_alloc->vcp_id == new_payload->vcpi) { - old_payload->time_slots = dc_alloc->slot_count; - old_payload->pbn = dc_alloc->slot_count * pbn_per_slot; - break; - } + list_for_each_entry(pos, &mst_state->payloads, next) { + if (pos != new_payload && + pos->vc_start_slot > payload_vc_start && + pos->vc_start_slot < next_payload_vc_start) + next_payload_vc_start = pos->vc_start_slot; } - /* make sure there is an old payload*/ - ASSERT(i != current_link_table.stream_count); + allocated_time_slots = next_payload_vc_start - payload_vc_start; + old_payload->time_slots = allocated_time_slots; + old_payload->pbn = allocated_time_slots * pbn_per_slot; } /* @@ -271,8 +269,8 @@ bool dm_helpers_dp_mst_write_payload_allocation_table( drm_dp_add_payload_part1(mst_mgr, mst_state, new_payload); } else { /* construct old payload by VCPI*/ - dm_helpers_construct_old_payload(stream->link, mst_state->pbn_div, - new_payload, &old_payload); + dm_helpers_construct_old_payload(mst_mgr, mst_state, + new_payload, &old_payload); target_payload = &old_payload; drm_dp_remove_payload_part1(mst_mgr, mst_state, new_payload); @@ -364,7 +362,7 @@ bool dm_helpers_dp_mst_send_payload_allocation( if (enable) { ret = drm_dp_add_payload_part2(mst_mgr, mst_state->base.state, new_payload); } else { - dm_helpers_construct_old_payload(stream->link, mst_state->pbn_div, + dm_helpers_construct_old_payload(mst_mgr, mst_state, new_payload, &old_payload); drm_dp_remove_payload_part2(mst_mgr, mst_state, &old_payload, new_payload); } From c1698c73f4aaef2fd406da1c0a92e1c8f7b7780c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 19 Sep 2023 12:39:39 +0200 Subject: [PATCH 42/80] drm: exynos: dsi: Convert to platform remove callback returning void MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() is renamed to .remove(). samsung_dsim_remove() returned 0 unconditionally. Make it return void instead to convert the two related platform drivers to use .remove_new(). Signed-off-by: Uwe Kleine-König Reviewed-by: Inki Dae Acked-by: Inki Dae Link: https://lore.kernel.org/r/20230919103939.1367659-1-u.kleine-koenig@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230919103939.1367659-1-u.kleine-koenig@pengutronix.de --- drivers/gpu/drm/bridge/samsung-dsim.c | 6 ++---- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 2 +- include/drm/bridge/samsung-dsim.h | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index b1df91e37b1b..2b56a5bfe273 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -1998,7 +1998,7 @@ err_disable_runtime: } EXPORT_SYMBOL_GPL(samsung_dsim_probe); -int samsung_dsim_remove(struct platform_device *pdev) +void samsung_dsim_remove(struct platform_device *pdev) { struct samsung_dsim *dsi = platform_get_drvdata(pdev); @@ -2006,8 +2006,6 @@ int samsung_dsim_remove(struct platform_device *pdev) if (dsi->plat_data->host_ops && dsi->plat_data->host_ops->unregister_host) dsi->plat_data->host_ops->unregister_host(dsi); - - return 0; } EXPORT_SYMBOL_GPL(samsung_dsim_remove); @@ -2107,7 +2105,7 @@ MODULE_DEVICE_TABLE(of, samsung_dsim_of_match); static struct platform_driver samsung_dsim_driver = { .probe = samsung_dsim_probe, - .remove = samsung_dsim_remove, + .remove_new = samsung_dsim_remove, .driver = { .name = "samsung-dsim", .pm = &samsung_dsim_pm_ops, diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 69ea33cae651..2fe0e5f3f638 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -181,7 +181,7 @@ MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); struct platform_driver dsi_driver = { .probe = samsung_dsim_probe, - .remove = samsung_dsim_remove, + .remove_new = samsung_dsim_remove, .driver = { .name = "exynos-dsi", .owner = THIS_MODULE, diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 6fc9bb2979e4..3f8050d523eb 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -116,7 +116,7 @@ struct samsung_dsim { }; extern int samsung_dsim_probe(struct platform_device *pdev); -extern int samsung_dsim_remove(struct platform_device *pdev); +extern void samsung_dsim_remove(struct platform_device *pdev); extern const struct dev_pm_ops samsung_dsim_pm_ops; #endif /* __SAMSUNG_DSIM__ */ From 3683182a7254f728778452814abe2437a12502c3 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Fri, 6 Oct 2023 17:07:03 +0200 Subject: [PATCH 43/80] drm/bridge: samsung-dsim: add more mipi-dsi device debug information Since the MIPI configuration can be changed on demand it is very useful to print more MIPI settings during the MIPI device attach step. Signed-off-by: Marco Felsch Reviewed-by: Adam Ford #imx8mm-beacon Tested-by: Adam Ford #imx8mm-beacon Reviewed-by: Inki Dae Acked-by: Inki Dae Tested-by: Frieder Schrempf # Kontron BL i.MX8MM + Waveshare 10.1inch HDMI LCD (E) Reviewed-by: Marco Felsch Signed-off-by: Michael Tretter Tested-by: Marek Szyprowski Link: https://lore.kernel.org/r/20230818-samsung-dsim-v2-1-846603df0e0a@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230818-samsung-dsim-v2-1-846603df0e0a@pengutronix.de --- drivers/gpu/drm/bridge/samsung-dsim.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 2b56a5bfe273..59b51eb4cd7b 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -1721,7 +1721,10 @@ of_find_panel_or_bridge: return ret; } - DRM_DEV_INFO(dev, "Attached %s device\n", device->name); + DRM_DEV_INFO(dev, "Attached %s device (lanes:%d bpp:%d mode-flags:0x%lx)\n", + device->name, device->lanes, + mipi_dsi_pixel_format_to_bpp(device->format), + device->mode_flags); drm_bridge_add(&dsi->bridge); From eb26c6ab2a11e6c595ee88ce30c7de9578d957aa Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 6 Oct 2023 17:07:04 +0200 Subject: [PATCH 44/80] drm/bridge: samsung-dsim: reread ref clock before configuring PLL The PLL reference clock may change at runtime when its parent clock changes. For example, this may happen on the i.MX8M Nano if the reference clock is a child of the Video PLL. If the pixel clock changes, this may propagate to the Video PLL and as a side effect change the reference clock. Thus, reading the clock rate during probe is not sufficient to correctly configure the PLL for the expected hs clock. Read the actual rate of the reference clock before calculating the PLL configuration parameters. Note that the "samsung,pll-clock-frequency" is always preferred and PLL reference clock is only read from the clock tree if that device tree property is not set. Reviewed-by: Inki Dae Acked-by: Inki Dae Tested-by: Frieder Schrempf # Kontron BL i.MX8MM + Waveshare 10.1inch HDMI LCD (E) Reviewed-by: Marco Felsch Signed-off-by: Michael Tretter Tested-by: Marek Szyprowski Link: https://lore.kernel.org/r/20230818-samsung-dsim-v2-2-846603df0e0a@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230818-samsung-dsim-v2-2-846603df0e0a@pengutronix.de --- drivers/gpu/drm/bridge/samsung-dsim.c | 16 +++++++++------- include/drm/bridge/samsung-dsim.h | 1 + 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 59b51eb4cd7b..71fc0a8766ff 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -614,7 +614,12 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, u16 m; u32 reg; - fin = dsi->pll_clk_rate; + if (dsi->pll_clk) + fin = clk_get_rate(dsi->pll_clk); + else + fin = dsi->pll_clk_rate; + dev_dbg(dsi->dev, "PLL ref clock freq %lu\n", fin); + fout = samsung_dsim_pll_find_pms(dsi, fin, freq, &p, &m, &s); if (!fout) { dev_err(dsi->dev, @@ -1829,18 +1834,15 @@ static int samsung_dsim_parse_dt(struct samsung_dsim *dsi) u32 lane_polarities[5] = { 0 }; struct device_node *endpoint; int i, nr_lanes, ret; - struct clk *pll_clk; ret = samsung_dsim_of_read_u32(node, "samsung,pll-clock-frequency", &dsi->pll_clk_rate, 1); /* If it doesn't exist, read it from the clock instead of failing */ if (ret < 0) { dev_dbg(dev, "Using sclk_mipi for pll clock frequency\n"); - pll_clk = devm_clk_get(dev, "sclk_mipi"); - if (!IS_ERR(pll_clk)) - dsi->pll_clk_rate = clk_get_rate(pll_clk); - else - return PTR_ERR(pll_clk); + dsi->pll_clk = devm_clk_get(dev, "sclk_mipi"); + if (IS_ERR(dsi->pll_clk)) + return PTR_ERR(dsi->pll_clk); } /* If it doesn't exist, use pixel clock instead of failing */ diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 3f8050d523eb..757f87337fe5 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -88,6 +88,7 @@ struct samsung_dsim { void __iomem *reg_base; struct phy *phy; struct clk **clks; + struct clk *pll_clk; struct regulator_bulk_data supplies[2]; int irq; struct gpio_desc *te_gpio; From 846307185f0ffbbe6b34d53b97c31c0fc392cff0 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 6 Oct 2023 17:07:05 +0200 Subject: [PATCH 45/80] drm/bridge: samsung-dsim: update PLL reference clock The PLL requires a clock frequency in a certain platform-dependent range after the pre-divider. The reference clock for the PLL may change due to changes to it's parent clock. Thus, the frequency may be out of range or unsuited for generating the high speed clock for MIPI DSI. Try to keep the pre-devider small, and set the reference clock close to the upper limit before recalculating the PLL configuration. Use a divider with a power of two for the reference clock as this seems to work best in my tests. Reviewed-by: Marco Felsch Tested-by: Frieder Schrempf # Kontron BL i.MX8MM + Waveshare 10.1inch HDMI LCD (E) Signed-off-by: Michael Tretter Tested-by: Marek Szyprowski Link: https://lore.kernel.org/r/20230818-samsung-dsim-v2-3-846603df0e0a@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230818-samsung-dsim-v2-3-846603df0e0a@pengutronix.de --- drivers/gpu/drm/bridge/samsung-dsim.c | 27 +++++++++++++++++++++++++-- include/drm/bridge/samsung-dsim.h | 2 ++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 71fc0a8766ff..60d5ab2e0989 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -410,6 +410,8 @@ static const struct samsung_dsim_driver_data exynos3_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, .m_min = 41, .m_max = 125, .min_freq = 500, @@ -427,6 +429,8 @@ static const struct samsung_dsim_driver_data exynos4_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, .m_min = 41, .m_max = 125, .min_freq = 500, @@ -442,6 +446,8 @@ static const struct samsung_dsim_driver_data exynos5_dsi_driver_data = { .num_bits_resol = 11, .pll_p_offset = 13, .reg_values = reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, .m_min = 41, .m_max = 125, .min_freq = 500, @@ -457,6 +463,8 @@ static const struct samsung_dsim_driver_data exynos5433_dsi_driver_data = { .num_bits_resol = 12, .pll_p_offset = 13, .reg_values = exynos5433_reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, .m_min = 41, .m_max = 125, .min_freq = 500, @@ -472,6 +480,8 @@ static const struct samsung_dsim_driver_data exynos5422_dsi_driver_data = { .num_bits_resol = 12, .pll_p_offset = 13, .reg_values = exynos5422_reg_values, + .pll_fin_min = 6, + .pll_fin_max = 12, .m_min = 41, .m_max = 125, .min_freq = 500, @@ -491,6 +501,8 @@ static const struct samsung_dsim_driver_data imx8mm_dsi_driver_data = { */ .pll_p_offset = 14, .reg_values = imx8mm_dsim_reg_values, + .pll_fin_min = 2, + .pll_fin_max = 30, .m_min = 64, .m_max = 1023, .min_freq = 1050, @@ -614,10 +626,21 @@ static unsigned long samsung_dsim_set_pll(struct samsung_dsim *dsi, u16 m; u32 reg; - if (dsi->pll_clk) + if (dsi->pll_clk) { + /* + * Ensure that the reference clock is generated with a power of + * two divider from its parent, but close to the PLLs upper + * limit. + */ + fin = clk_get_rate(clk_get_parent(dsi->pll_clk)); + while (fin > driver_data->pll_fin_max * MHZ) + fin /= 2; + clk_set_rate(dsi->pll_clk, fin); + fin = clk_get_rate(dsi->pll_clk); - else + } else { fin = dsi->pll_clk_rate; + } dev_dbg(dsi->dev, "PLL ref clock freq %lu\n", fin); fout = samsung_dsim_pll_find_pms(dsi, fin, freq, &p, &m, &s); diff --git a/include/drm/bridge/samsung-dsim.h b/include/drm/bridge/samsung-dsim.h index 757f87337fe5..e0c105051246 100644 --- a/include/drm/bridge/samsung-dsim.h +++ b/include/drm/bridge/samsung-dsim.h @@ -61,6 +61,8 @@ struct samsung_dsim_driver_data { unsigned int num_bits_resol; unsigned int pll_p_offset; const unsigned int *reg_values; + unsigned int pll_fin_min; + unsigned int pll_fin_max; u16 m_min; u16 m_max; }; From 198e54282ae560958e64328fe8f72893661b9e8b Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 6 Oct 2023 17:07:06 +0200 Subject: [PATCH 46/80] drm/bridge: samsung-dsim: adjust porches by rounding up Rounding the porches up instead of down fixes the samsung-dsim at some more resolutions and refresh rates: The following resolutions are working with rounded-up porches, but don't work when the porches are rounded down: 1920x1080-59.94 1920x1080-30.00 1920x1080-29.97 1920x1080-25.00 1680x1050-59.88 1280x1024-75.02 1200x960-59.99 1280x720-50.00 1024x768-75.03 1024x768-60.00 640x480-60.00 640x480-59.94 Reviewed-by: Adam Ford #imx8mm-beacon Tested-by: Adam Ford #imx8mm-beacon Tested-by: Frieder Schrempf # Kontron BL i.MX8MM + Waveshare 10.1inch HDMI LCD (E) Reviewed-by: Marco Felsch Signed-off-by: Michael Tretter Tested-by: Marek Szyprowski Link: https://lore.kernel.org/r/20230818-samsung-dsim-v2-4-846603df0e0a@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230818-samsung-dsim-v2-4-846603df0e0a@pengutronix.de --- drivers/gpu/drm/bridge/samsung-dsim.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index 60d5ab2e0989..a0310f050693 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -989,9 +989,9 @@ static void samsung_dsim_set_display_mode(struct samsung_dsim *dsi) if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { int byte_clk_khz = dsi->hs_clock / 1000 / 8; - int hfp = (m->hsync_start - m->hdisplay) * byte_clk_khz / m->clock; - int hbp = (m->htotal - m->hsync_end) * byte_clk_khz / m->clock; - int hsa = (m->hsync_end - m->hsync_start) * byte_clk_khz / m->clock; + int hfp = DIV_ROUND_UP((m->hsync_start - m->hdisplay) * byte_clk_khz, m->clock); + int hbp = DIV_ROUND_UP((m->htotal - m->hsync_end) * byte_clk_khz, m->clock); + int hsa = DIV_ROUND_UP((m->hsync_end - m->hsync_start) * byte_clk_khz, m->clock); /* remove packet overhead when possible */ hfp = max(hfp - 6, 0); From 6acb691824933535219dfd94d9d97c922f5593d2 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 6 Oct 2023 17:07:07 +0200 Subject: [PATCH 47/80] drm/bridge: samsung-dsim: calculate porches in Hz Calculating the byte_clk in kHz is imprecise for a hs_clock of 55687500 Hz, which may be used with a pixel clock of 74.25 MHz with mode 1920x1080-30. Fix the calculation by using HZ instead of kHZ. This requires to change the type to u64 to prevent overflows of the integer type. Reviewed-by: Adam Ford #imx8mm-beacon Tested-by: Adam Ford #imx8mm-beacon Tested-by: Frieder Schrempf # Kontron BL i.MX8MM + Waveshare 10.1inch HDMI LCD (E) Reviewed-by: Marco Felsch Signed-off-by: Michael Tretter Tested-by: Marek Szyprowski Link: https://lore.kernel.org/r/20230818-samsung-dsim-v2-5-846603df0e0a@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230818-samsung-dsim-v2-5-846603df0e0a@pengutronix.de --- drivers/gpu/drm/bridge/samsung-dsim.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c index a0310f050693..3a5c7618e7aa 100644 --- a/drivers/gpu/drm/bridge/samsung-dsim.c +++ b/drivers/gpu/drm/bridge/samsung-dsim.c @@ -988,10 +988,12 @@ static void samsung_dsim_set_display_mode(struct samsung_dsim *dsi) u32 reg; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { - int byte_clk_khz = dsi->hs_clock / 1000 / 8; - int hfp = DIV_ROUND_UP((m->hsync_start - m->hdisplay) * byte_clk_khz, m->clock); - int hbp = DIV_ROUND_UP((m->htotal - m->hsync_end) * byte_clk_khz, m->clock); - int hsa = DIV_ROUND_UP((m->hsync_end - m->hsync_start) * byte_clk_khz, m->clock); + u64 byte_clk = dsi->hs_clock / 8; + u64 pix_clk = m->clock * 1000; + + int hfp = DIV64_U64_ROUND_UP((m->hsync_start - m->hdisplay) * byte_clk, pix_clk); + int hbp = DIV64_U64_ROUND_UP((m->htotal - m->hsync_end) * byte_clk, pix_clk); + int hsa = DIV64_U64_ROUND_UP((m->hsync_end - m->hsync_start) * byte_clk, pix_clk); /* remove packet overhead when possible */ hfp = max(hfp - 6, 0); From 5437d667a0cae87d34c321ce1819ea78011efdc1 Mon Sep 17 00:00:00 2001 From: Johannes Zink Date: Fri, 29 Sep 2023 14:33:31 +0200 Subject: [PATCH 48/80] dt-bindings: display: move LVDS data-mapping definition to separate file As the LVDS data-mapping property is required in multiple bindings: move it to separate file and include instead of duplicating it. Reviewed-by: Conor Dooley Reviewed-by: Laurent Pinchart Signed-off-by: Johannes Zink Link: https://lore.kernel.org/r/20230523-simplepanel_support_nondefault_datamapping-v5-1-0d7928edafab@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230523-simplepanel_support_nondefault_datamapping-v5-1-0d7928edafab@pengutronix.de --- .../bindings/display/lvds-data-mapping.yaml | 84 +++++++++++++++++++ .../devicetree/bindings/display/lvds.yaml | 77 ++--------------- 2 files changed, 93 insertions(+), 68 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/lvds-data-mapping.yaml diff --git a/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml b/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml new file mode 100644 index 000000000000..d68982fe2e9b --- /dev/null +++ b/Documentation/devicetree/bindings/display/lvds-data-mapping.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/lvds-data-mapping.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LVDS Data Mapping + +maintainers: + - Laurent Pinchart + - Thierry Reding + +description: | + LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple + incompatible data link layers have been used over time to transmit image data + to LVDS devices. This bindings supports devices compatible with the following + specifications. + + [JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February + 1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA) + [LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National + Semiconductor + [VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video + Electronics Standards Association (VESA) + + Device compatible with those specifications have been marketed under the + FPD-Link and FlatLink brands. + +properties: + data-mapping: + enum: + - jeida-18 + - jeida-24 + - vesa-24 + description: | + The color signals mapping order. + + LVDS data mappings are defined as follows. + + - "jeida-18" - 18-bit data mapping compatible with the [JEIDA], [LDI] and + [VESA] specifications. Data are transferred as follows on 3 LVDS lanes. + + Slot 0 1 2 3 4 5 6 + ________________ _________________ + Clock \_______________________/ + ______ ______ ______ ______ ______ ______ ______ + DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__>< + DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__>< + DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__>< + + - "jeida-24" - 24-bit data mapping compatible with the [DSIM] and [LDI] + specifications. Data are transferred as follows on 4 LVDS lanes. + + Slot 0 1 2 3 4 5 6 + ________________ _________________ + Clock \_______________________/ + ______ ______ ______ ______ ______ ______ ______ + DATA0 ><__G2__><__R7__><__R6__><__R5__><__R4__><__R3__><__R2__>< + DATA1 ><__B3__><__B2__><__G7__><__G6__><__G5__><__G4__><__G3__>< + DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B7__><__B6__><__B5__><__B4__>< + DATA3 ><_CTL3_><__B1__><__B0__><__G1__><__G0__><__R1__><__R0__>< + + - "vesa-24" - 24-bit data mapping compatible with the [VESA] specification. + Data are transferred as follows on 4 LVDS lanes. + + Slot 0 1 2 3 4 5 6 + ________________ _________________ + Clock \_______________________/ + ______ ______ ______ ______ ______ ______ ______ + DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__>< + DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__>< + DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__>< + DATA3 ><_CTL3_><__B7__><__B6__><__G7__><__G6__><__R7__><__R6__>< + + Control signals are mapped as follows. + + CTL0: HSync + CTL1: VSync + CTL2: Data Enable + CTL3: 0 + +additionalProperties: true + +... diff --git a/Documentation/devicetree/bindings/display/lvds.yaml b/Documentation/devicetree/bindings/display/lvds.yaml index 7cd2ce7e9c33..224db4932011 100644 --- a/Documentation/devicetree/bindings/display/lvds.yaml +++ b/Documentation/devicetree/bindings/display/lvds.yaml @@ -6,83 +6,24 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: LVDS Display Common Properties +allOf: + - $ref: lvds-data-mapping.yaml# + maintainers: - Laurent Pinchart - Thierry Reding -description: |+ - LVDS is a physical layer specification defined in ANSI/TIA/EIA-644-A. Multiple - incompatible data link layers have been used over time to transmit image data - to LVDS devices. This bindings supports devices compatible with the following - specifications. - - [JEIDA] "Digital Interface Standards for Monitor", JEIDA-59-1999, February - 1999 (Version 1.0), Japan Electronic Industry Development Association (JEIDA) - [LDI] "Open LVDS Display Interface", May 1999 (Version 0.95), National - Semiconductor - [VESA] "VESA Notebook Panel Standard", October 2007 (Version 1.0), Video - Electronics Standards Association (VESA) - - Device compatible with those specifications have been marketed under the - FPD-Link and FlatLink brands. +description: + This binding extends the data mapping defined in lvds-data-mapping.yaml. + It supports reversing the bit order on the formats defined there in order + to accomodate for even more specialized data formats, since a variety of + data formats and layouts is used to drive LVDS displays. properties: - data-mapping: - enum: - - jeida-18 - - jeida-24 - - vesa-24 - description: | - The color signals mapping order. - - LVDS data mappings are defined as follows. - - - "jeida-18" - 18-bit data mapping compatible with the [JEIDA], [LDI] and - [VESA] specifications. Data are transferred as follows on 3 LVDS lanes. - - Slot 0 1 2 3 4 5 6 - ________________ _________________ - Clock \_______________________/ - ______ ______ ______ ______ ______ ______ ______ - DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__>< - DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__>< - DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__>< - - - "jeida-24" - 24-bit data mapping compatible with the [DSIM] and [LDI] - specifications. Data are transferred as follows on 4 LVDS lanes. - - Slot 0 1 2 3 4 5 6 - ________________ _________________ - Clock \_______________________/ - ______ ______ ______ ______ ______ ______ ______ - DATA0 ><__G2__><__R7__><__R6__><__R5__><__R4__><__R3__><__R2__>< - DATA1 ><__B3__><__B2__><__G7__><__G6__><__G5__><__G4__><__G3__>< - DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B7__><__B6__><__B5__><__B4__>< - DATA3 ><_CTL3_><__B1__><__B0__><__G1__><__G0__><__R1__><__R0__>< - - - "vesa-24" - 24-bit data mapping compatible with the [VESA] specification. - Data are transferred as follows on 4 LVDS lanes. - - Slot 0 1 2 3 4 5 6 - ________________ _________________ - Clock \_______________________/ - ______ ______ ______ ______ ______ ______ ______ - DATA0 ><__G0__><__R5__><__R4__><__R3__><__R2__><__R1__><__R0__>< - DATA1 ><__B1__><__B0__><__G5__><__G4__><__G3__><__G2__><__G1__>< - DATA2 ><_CTL2_><_CTL1_><_CTL0_><__B5__><__B4__><__B3__><__B2__>< - DATA3 ><_CTL3_><__B7__><__B6__><__G7__><__G6__><__R7__><__R6__>< - - Control signals are mapped as follows. - - CTL0: HSync - CTL1: VSync - CTL2: Data Enable - CTL3: 0 - data-mirror: type: boolean description: - If set, reverse the bit order described in the data mappings below on all + If set, reverse the bit order described in the data mappings on all data lanes, transmitting bits for slots 6 to 0 instead of 0 to 6. additionalProperties: true From 66b66c97f4074c38b1c53c49625ebdd9a33ba56d Mon Sep 17 00:00:00 2001 From: Johannes Zink Date: Fri, 29 Sep 2023 14:33:32 +0200 Subject: [PATCH 49/80] dt-bindings: display: simple: support non-default data-mapping Some Displays support more than just a single default LVDS data mapping, which can be used to run displays on only 3 LVDS lanes in the jeida-18 data-mapping mode. Add an optional data-mapping property to allow overriding the default data mapping. As it does not generally apply to any display and bus, use it selectively on the innolux,g101ice-l01, which supports changing the data mapping via a strapping pin. Reviewed-by: Conor Dooley Signed-off-by: Johannes Zink Link: https://lore.kernel.org/r/20230523-simplepanel_support_nondefault_datamapping-v5-2-0d7928edafab@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230523-simplepanel_support_nondefault_datamapping-v5-2-0d7928edafab@pengutronix.de --- .../bindings/display/panel/panel-simple.yaml | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml index 50143fe67471..81ac402ceed1 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple.yaml @@ -21,9 +21,9 @@ description: | allOf: - $ref: panel-common.yaml# + - $ref: ../lvds-data-mapping.yaml# properties: - compatible: enum: # compatible must be listed in alphabetical order, ordered by compatible. @@ -359,6 +359,17 @@ properties: power-supply: true no-hpd: true hpd-gpios: true + data-mapping: true + +if: + not: + properties: + compatible: + contains: + const: innolux,g101ice-l01 +then: + properties: + data-mapping: false additionalProperties: false @@ -378,3 +389,16 @@ examples: }; }; }; + - | + panel_lvds: panel-lvds { + compatible = "innolux,g101ice-l01"; + power-supply = <&vcc_lcd_reg>; + + data-mapping = "jeida-24"; + + port { + panel_in_lvds: endpoint { + remote-endpoint = <<dc_out_lvds>; + }; + }; + }; From 1cd3ea3e4b124120dbdff3faf00a71c8fc6f6402 Mon Sep 17 00:00:00 2001 From: Johannes Zink Date: Fri, 29 Sep 2023 14:33:33 +0200 Subject: [PATCH 50/80] drm/panel-simple: allow LVDS format override Some panels support multiple LVDS data mapping formats, which can be used e.g. run displays on jeida-18 format when only 3 LVDS lanes are available. Add parsing of an optional data-mapping devicetree property, which also touches up the bits per color to match the bus format. Signed-off-by: Johannes Zink Link: https://lore.kernel.org/r/20230523-simplepanel_support_nondefault_datamapping-v5-3-0d7928edafab@pengutronix.de Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20230523-simplepanel_support_nondefault_datamapping-v5-3-0d7928edafab@pengutronix.de --- drivers/gpu/drm/panel/panel-simple.c | 53 ++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index bb89e6d047bc..de0b84599e53 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -40,6 +40,7 @@ #include #include #include +#include /** * struct panel_desc - Describes a simple panel. @@ -549,6 +550,51 @@ static void panel_simple_parse_panel_timing_node(struct device *dev, dev_err(dev, "Reject override mode: No display_timing found\n"); } +static int panel_simple_override_nondefault_lvds_datamapping(struct device *dev, + struct panel_simple *panel) +{ + int ret, bpc; + + ret = drm_of_lvds_get_data_mapping(dev->of_node); + if (ret < 0) { + if (ret == -EINVAL) + dev_warn(dev, "Ignore invalid data-mapping property\n"); + + /* + * Ignore non-existing or malformatted property, fallback to + * default data-mapping, and return 0. + */ + return 0; + } + + switch (ret) { + default: + WARN_ON(1); + fallthrough; + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: + fallthrough; + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: + bpc = 8; + break; + case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: + bpc = 6; + } + + if (panel->desc->bpc != bpc || panel->desc->bus_format != ret) { + struct panel_desc *override_desc; + + override_desc = devm_kmemdup(dev, panel->desc, sizeof(*panel->desc), GFP_KERNEL); + if (!override_desc) + return -ENOMEM; + + override_desc->bus_format = ret; + override_desc->bpc = bpc; + panel->desc = override_desc; + } + + return 0; +} + static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) { struct panel_simple *panel; @@ -601,6 +647,13 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) panel_simple_parse_panel_timing_node(dev, panel, &dt); } + if (desc->connector_type == DRM_MODE_CONNECTOR_LVDS) { + /* Optional data-mapping property for overriding bus format */ + err = panel_simple_override_nondefault_lvds_datamapping(dev, panel); + if (err) + goto free_ddc; + } + connector_type = desc->connector_type; /* Catch common mistakes for panels. */ switch (connector_type) { From 8badbaffbe490d76a54026e8988168d9493ad141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Larumbe?= Date: Thu, 5 Oct 2023 15:12:35 +0100 Subject: [PATCH 51/80] Documentation/gpu: fix Panfrost documentation build warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix issues revealed by `make htmldocs` after adding Panfrost DRM documentation file. Signed-off-by: Adrián Larumbe Fixes: f11b0417eec2 ("drm/panfrost: Add fdinfo support GPU load metrics") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202310030917.Txzlpoeq-lkp@intel.com Reviewed-by: Steven Price Signed-off-by: Boris Brezillon Link: https://patchwork.freedesktop.org/patch/msgid/20231005141239.132783-1-adrian.larumbe@collabora.com --- Documentation/gpu/drivers.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/gpu/drivers.rst b/Documentation/gpu/drivers.rst index 3a52f48215a3..45a12e552091 100644 --- a/Documentation/gpu/drivers.rst +++ b/Documentation/gpu/drivers.rst @@ -18,6 +18,7 @@ GPU Driver Documentation xen-front afbc komeda-kms + panfrost .. only:: subproject and html From eb23cffdd7f085149799e5eda12a9aff792cc34d Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Mon, 9 Oct 2023 12:37:53 +0200 Subject: [PATCH 52/80] drm/rockchip: vop2: Demote message in mod_supported to drm_dbg_kms Checking if a modifier is supported by a plane is normal behavior. It is normal that a plane may not support certain modifiers. Failing the check doesn't justify an error message in the kernel log and may mislead users. Demote the error message to drm_dbg_kms to only print the message if the respective debug messages are enabled. This is similar to the behavior in rockchip_drm_vop.c. Signed-off-by: Michael Tretter Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231009103753.830458-1-m.tretter@pengutronix.de --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index c306806aa3de..957e42886ec3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -469,8 +469,8 @@ static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format, return true; if (!rockchip_afbc(plane, modifier)) { - drm_err(vop2->drm, "Unsupported format modifier 0x%llx\n", - modifier); + drm_dbg_kms(vop2->drm, "Unsupported format modifier 0x%llx\n", + modifier); return false; } From 3d59c22bbb8d03f3f14e6d0845d44c146fb48f35 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 1 Oct 2023 01:42:50 +0200 Subject: [PATCH 53/80] drm/rockchip: vop2: Convert to use maple tree register cache The maple tree register cache is based on a much more modern data structure than the rbtree cache and makes optimisation choices which are probably more appropriate for modern systems than those made by the rbtree cache. Signed-off-by: Mark Brown Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20231001-drm-rockchip-maple-v1-1-ca396ab75be7@kernel.org --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 957e42886ec3..ec7e0e6149af 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2640,7 +2640,7 @@ static const struct regmap_config vop2_regmap_config = { .max_register = 0x3000, .name = "vop2", .volatile_table = &vop2_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int vop2_bind(struct device *dev, struct device *master, void *data) From 44b968d0d0868b7a9b7a5c64464ada464ff4d532 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 2 Sep 2023 19:34:31 +0200 Subject: [PATCH 54/80] drm/rockchip: cdn-dp: Fix some error handling paths in cdn_dp_probe() cdn_dp_audio_codec_init() can fail. So add some error handling. If component_add() fails, the previous cdn_dp_audio_codec_init() call should be undone, as already done in the remove function. Fixes: 88582f564692 ("drm/rockchip: cdn-dp: Don't unregister audio dev when unbinding") Signed-off-by: Christophe JAILLET Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/8494a41602fadb7439630921a9779640698f2f9f.1693676045.git.christophe.jaillet@wanadoo.fr --- drivers/gpu/drm/rockchip/cdn-dp-core.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index a29fbafce393..3793863c210e 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -1177,6 +1177,7 @@ static int cdn_dp_probe(struct platform_device *pdev) struct cdn_dp_device *dp; struct extcon_dev *extcon; struct phy *phy; + int ret; int i; dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); @@ -1217,9 +1218,19 @@ static int cdn_dp_probe(struct platform_device *pdev) mutex_init(&dp->lock); dev_set_drvdata(dev, dp); - cdn_dp_audio_codec_init(dp, dev); + ret = cdn_dp_audio_codec_init(dp, dev); + if (ret) + return ret; - return component_add(dev, &cdn_dp_component_ops); + ret = component_add(dev, &cdn_dp_component_ops); + if (ret) + goto err_audio_deinit; + + return 0; + +err_audio_deinit: + platform_device_unregister(dp->audio_pdev); + return ret; } static void cdn_dp_remove(struct platform_device *pdev) From 63a06c9fe30bf84d1ab6f07d0e408bd1d4ccaf85 Mon Sep 17 00:00:00 2001 From: Zhu Wang Date: Mon, 31 Jul 2023 20:53:04 +0800 Subject: [PATCH 55/80] drm/rockchip: remove redundant of_match_ptr The driver depends on CONFIG_OF, so it is not necessary to use of_match_ptr here. Even for drivers that do not depend on CONFIG_OF, it's almost always better to leave out the of_match_ptr(), since the only thing it can possibly do is to save a few bytes of .text if a driver can be used both with and without it. Hence we remove of_match_ptr. Signed-off-by: Zhu Wang Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20230731125304.87059-1-wangzhu9@huawei.com --- drivers/gpu/drm/rockchip/cdn-dp-core.c | 2 +- drivers/gpu/drm/rockchip/rockchip_lvds.c | 2 +- drivers/gpu/drm/rockchip/rockchip_vop2_reg.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 3793863c210e..21254e4e107a 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -1261,7 +1261,7 @@ struct platform_driver cdn_dp_driver = { .driver = { .name = "cdn-dp", .owner = THIS_MODULE, - .of_match_table = of_match_ptr(cdn_dp_dt_ids), + .of_match_table = cdn_dp_dt_ids, .pm = &cdn_dp_pm_ops, }, }; diff --git a/drivers/gpu/drm/rockchip/rockchip_lvds.c b/drivers/gpu/drm/rockchip/rockchip_lvds.c index 582859387792..f0f47e9abf5a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_lvds.c +++ b/drivers/gpu/drm/rockchip/rockchip_lvds.c @@ -752,6 +752,6 @@ struct platform_driver rockchip_lvds_driver = { .remove_new = rockchip_lvds_remove, .driver = { .name = "rockchip-lvds", - .of_match_table = of_match_ptr(rockchip_lvds_dt_ids), + .of_match_table = rockchip_lvds_dt_ids, }, }; diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 62b573f282a7..fcd4cf3072cd 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -274,6 +274,6 @@ struct platform_driver vop2_platform_driver = { .remove_new = vop2_remove, .driver = { .name = "rockchip-vop2", - .of_match_table = of_match_ptr(vop2_dt_match), + .of_match_table = vop2_dt_match, }, }; From 253a1d33e5cfdf62525f5d6ed2bf03acbadd1582 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 21 Apr 2023 16:13:03 +0800 Subject: [PATCH 56/80] drm/rockchip: dsi: Use devm_platform_get_and_ioremap_resource() Convert platform_get_resource(), devm_ioremap_resource() to a single call to devm_platform_get_and_ioremap_resource(), as this is exactly what this function does. Signed-off-by: Yang Li Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20230421081303.122452-1-yang.lee@linux.alibaba.com --- drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c index 8bafb2a2747f..6396f9324dab 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c @@ -1358,8 +1358,7 @@ static int dw_mipi_dsi_rockchip_probe(struct platform_device *pdev) if (!dsi) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dsi->base = devm_ioremap_resource(dev, res); + dsi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(dsi->base)) { DRM_DEV_ERROR(dev, "Unable to get dsi registers\n"); return PTR_ERR(dsi->base); From 924e5814d1f84e6fa5cb19c6eceb69f066225229 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Sat, 7 Oct 2023 11:31:05 +0800 Subject: [PATCH 57/80] drm/panel: fix a possible null pointer dereference In versatile_panel_get_modes(), the return value of drm_mode_duplicate() is assigned to mode, which will lead to a NULL pointer dereference on failure of drm_mode_duplicate(). Add a check to avoid npd. Signed-off-by: Ma Ke Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231007033105.3997998-1-make_ruc2021@163.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231007033105.3997998-1-make_ruc2021@163.com --- drivers/gpu/drm/panel/panel-arm-versatile.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c index abb0788843c6..503ecea72c5e 100644 --- a/drivers/gpu/drm/panel/panel-arm-versatile.c +++ b/drivers/gpu/drm/panel/panel-arm-versatile.c @@ -267,6 +267,8 @@ static int versatile_panel_get_modes(struct drm_panel *panel, connector->display_info.bus_flags = vpanel->panel_type->bus_flags; mode = drm_mode_duplicate(connector->dev, &vpanel->panel_type->mode); + if (!mode) + return -ENOMEM; drm_mode_set_name(mode); mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; From f22def5970c423ea7f87d5247bd0ef91416b0658 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Mon, 9 Oct 2023 17:04:46 +0800 Subject: [PATCH 58/80] drm/panel/panel-tpo-tpg110: fix a possible null pointer dereference In tpg110_get_modes(), the return value of drm_mode_duplicate() is assigned to mode, which will lead to a NULL pointer dereference on failure of drm_mode_duplicate(). Add a check to avoid npd. Signed-off-by: Ma Ke Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20231009090446.4043798-1-make_ruc2021@163.com Signed-off-by: Neil Armstrong Link: https://patchwork.freedesktop.org/patch/msgid/20231009090446.4043798-1-make_ruc2021@163.com --- drivers/gpu/drm/panel/panel-tpo-tpg110.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-tpo-tpg110.c b/drivers/gpu/drm/panel/panel-tpo-tpg110.c index 845304435e23..f6a212e542cb 100644 --- a/drivers/gpu/drm/panel/panel-tpo-tpg110.c +++ b/drivers/gpu/drm/panel/panel-tpo-tpg110.c @@ -379,6 +379,8 @@ static int tpg110_get_modes(struct drm_panel *panel, connector->display_info.bus_flags = tpg->panel_mode->bus_flags; mode = drm_mode_duplicate(connector->dev, &tpg->panel_mode->mode); + if (!mode) + return -ENOMEM; drm_mode_set_name(mode); mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; From 99403d747ae8c7b3bfb5cd14c8908930ec6801c6 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 31 Jan 2022 17:47:21 +0100 Subject: [PATCH 59/80] drm/panel: ltk050h3146w: add mipi_dsi_device.mode_flags to of_match_data To prepare for a new display to be supported by this driver which has a slightly different set of DSI mode related flags, let's move the currently hardcoded mode flags to the .data field of of_device_id structure. Cc: Quentin Schulz Signed-off-by: Quentin Schulz Reviewed-by: Paul Kocialkowski Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220131164723.714836-1-quentin.schulz@theobroma-systems.com --- drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index d41482d3a34f..d157bf53f9f9 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -24,6 +24,7 @@ struct ltk050h3146w_cmd { struct ltk050h3146w; struct ltk050h3146w_desc { + const unsigned long mode_flags; const struct drm_display_mode *mode; int (*init)(struct ltk050h3146w *ctx); }; @@ -330,6 +331,8 @@ static const struct drm_display_mode ltk050h3146w_mode = { static const struct ltk050h3146w_desc ltk050h3146w_data = { .mode = <k050h3146w_mode, .init = ltk050h3146w_init_sequence, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, }; static int ltk050h3146w_a2_select_page(struct ltk050h3146w *ctx, int page) @@ -424,6 +427,8 @@ static const struct drm_display_mode ltk050h3146w_a2_mode = { static const struct ltk050h3146w_desc ltk050h3146w_a2_data = { .mode = <k050h3146w_a2_mode, .init = ltk050h3146w_a2_init_sequence, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET, }; static int ltk050h3146w_unprepare(struct drm_panel *panel) @@ -583,8 +588,7 @@ static int ltk050h3146w_probe(struct mipi_dsi_device *dsi) dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | - MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; + dsi->mode_flags = ctx->panel_desc->mode_flags; drm_panel_init(&ctx->panel, &dsi->dev, <k050h3146w_funcs, DRM_MODE_CONNECTOR_DSI); From 29d8e38c36cb662331a833699c359ec1af1edbec Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Mon, 31 Jan 2022 17:47:23 +0100 Subject: [PATCH 60/80] dt-bindings: ltk050h3146w: add compatible for LTK050H3148W-CTA6 variant The LTK050H3148W-CTA6 is a 5.0" 720x1280 DSI display, whose driving controller is a Himax HX8394-F, slightly different from LTK050H3146W by its init sequence, mode details and mode flags. Cc: Quentin Schulz Signed-off-by: Quentin Schulz Reviewed-by: Paul Kocialkowski Acked-by: Rob Herring Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220131164723.714836-3-quentin.schulz@theobroma-systems.com --- .../devicetree/bindings/display/panel/leadtek,ltk050h3146w.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/panel/leadtek,ltk050h3146w.yaml b/Documentation/devicetree/bindings/display/panel/leadtek,ltk050h3146w.yaml index 3f6efbb942da..a40ab887ada7 100644 --- a/Documentation/devicetree/bindings/display/panel/leadtek,ltk050h3146w.yaml +++ b/Documentation/devicetree/bindings/display/panel/leadtek,ltk050h3146w.yaml @@ -17,6 +17,7 @@ properties: enum: - leadtek,ltk050h3146w - leadtek,ltk050h3146w-a2 + - leadtek,ltk050h3148w reg: true backlight: true reset-gpios: true From e5f9d543419c78ac58f3b3557bc5a76b20ff600b Mon Sep 17 00:00:00 2001 From: Klaus Goger Date: Mon, 31 Jan 2022 17:47:22 +0100 Subject: [PATCH 61/80] drm/panel: ltk050h3146w: add support for Leadtek LTK050H3148W-CTA6 variant The LTK050H3148W-CTA6 is a 5.0" 720x1280 DSI display, whose driving controller is a Himax HX8394-F, slightly different from LTK050H3146W by its init sequence, mode details and mode flags. Cc: Quentin Schulz Signed-off-by: Klaus Goger Signed-off-by: Quentin Schulz Reviewed-by: Paul Kocialkowski Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20220131164723.714836-2-quentin.schulz@theobroma-systems.com --- .../drm/panel/panel-leadtek-ltk050h3146w.c | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c index d157bf53f9f9..6e3670508e3a 100644 --- a/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c +++ b/drivers/gpu/drm/panel/panel-leadtek-ltk050h3146w.c @@ -244,6 +244,91 @@ struct ltk050h3146w *panel_to_ltk050h3146w(struct drm_panel *panel) return container_of(panel, struct ltk050h3146w, panel); } +static int ltk050h3148w_init_sequence(struct ltk050h3146w *ctx) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + /* + * Init sequence was supplied by the panel vendor without much + * documentation. + */ + mipi_dsi_dcs_write_seq(dsi, 0xb9, 0xff, 0x83, 0x94); + mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x50, 0x15, 0x75, 0x09, 0x32, 0x44, + 0x71, 0x31, 0x55, 0x2f); + mipi_dsi_dcs_write_seq(dsi, 0xba, 0x63, 0x03, 0x68, 0x6b, 0xb2, 0xc0); + mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x88); + mipi_dsi_dcs_write_seq(dsi, 0xb2, 0x00, 0x80, 0x64, 0x10, 0x07); + mipi_dsi_dcs_write_seq(dsi, 0xb4, 0x05, 0x70, 0x05, 0x70, 0x01, 0x70, + 0x01, 0x0c, 0x86, 0x75, 0x00, 0x3f, 0x01, 0x74, + 0x01, 0x74, 0x01, 0x74, 0x01, 0x0c, 0x86); + mipi_dsi_dcs_write_seq(dsi, 0xd3, 0x00, 0x00, 0x07, 0x07, 0x40, 0x1e, + 0x08, 0x00, 0x32, 0x10, 0x08, 0x00, 0x08, 0x54, + 0x15, 0x10, 0x05, 0x04, 0x02, 0x12, 0x10, 0x05, + 0x07, 0x33, 0x34, 0x0c, 0x0c, 0x37, 0x10, 0x07, + 0x17, 0x11, 0x40); + mipi_dsi_dcs_write_seq(dsi, 0xd5, 0x19, 0x19, 0x18, 0x18, 0x1b, 0x1b, + 0x1a, 0x1a, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, + 0x02, 0x03, 0x20, 0x21, 0x18, 0x18, 0x22, 0x23, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); + mipi_dsi_dcs_write_seq(dsi, 0xd6, 0x18, 0x18, 0x19, 0x19, 0x1b, 0x1b, + 0x1a, 0x1a, 0x03, 0x02, 0x01, 0x00, 0x07, 0x06, + 0x05, 0x04, 0x23, 0x22, 0x18, 0x18, 0x21, 0x20, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18); + mipi_dsi_dcs_write_seq(dsi, 0xe0, 0x00, 0x03, 0x09, 0x11, 0x11, 0x14, + 0x18, 0x16, 0x2e, 0x3d, 0x4d, 0x4d, 0x58, 0x6c, + 0x72, 0x78, 0x88, 0x8b, 0x86, 0xa4, 0xb2, 0x58, + 0x55, 0x59, 0x5b, 0x5d, 0x60, 0x64, 0x7f, 0x00, + 0x03, 0x09, 0x0f, 0x11, 0x14, 0x18, 0x16, 0x2e, + 0x3d, 0x4d, 0x4d, 0x58, 0x6d, 0x73, 0x78, 0x88, + 0x8b, 0x87, 0xa5, 0xb2, 0x58, 0x55, 0x58, 0x5b, + 0x5d, 0x61, 0x65, 0x7f); + mipi_dsi_dcs_write_seq(dsi, 0xcc, 0x0b); + mipi_dsi_dcs_write_seq(dsi, 0xc0, 0x1f, 0x31); + mipi_dsi_dcs_write_seq(dsi, 0xb6, 0xc4, 0xc4); + mipi_dsi_dcs_write_seq(dsi, 0xbd, 0x01); + mipi_dsi_dcs_write_seq(dsi, 0xb1, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xbd, 0x00); + mipi_dsi_dcs_write_seq(dsi, 0xc6, 0xef); + mipi_dsi_dcs_write_seq(dsi, 0xd4, 0x02); + mipi_dsi_dcs_write_seq(dsi, 0x11); + mipi_dsi_dcs_write_seq(dsi, 0x29); + + ret = mipi_dsi_dcs_set_tear_on(dsi, 1); + if (ret < 0) { + dev_err(ctx->dev, "failed to set tear on: %d\n", ret); + return ret; + } + + msleep(60); + + return 0; +} + +static const struct drm_display_mode ltk050h3148w_mode = { + .hdisplay = 720, + .hsync_start = 720 + 12, + .hsync_end = 720 + 12 + 6, + .htotal = 720 + 12 + 6 + 24, + .vdisplay = 1280, + .vsync_start = 1280 + 9, + .vsync_end = 1280 + 9 + 2, + .vtotal = 1280 + 9 + 2 + 16, + .clock = 59756, + .width_mm = 62, + .height_mm = 110, +}; + +static const struct ltk050h3146w_desc ltk050h3148w_data = { + .mode = <k050h3148w_mode, + .init = ltk050h3148w_init_sequence, + .mode_flags = MIPI_DSI_MODE_VIDEO_SYNC_PULSE, +}; + static int ltk050h3146w_init_sequence(struct ltk050h3146w *ctx) { struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); @@ -646,6 +731,10 @@ static const struct of_device_id ltk050h3146w_of_match[] = { .compatible = "leadtek,ltk050h3146w-a2", .data = <k050h3146w_a2_data, }, + { + .compatible = "leadtek,ltk050h3148w", + .data = <k050h3148w_data, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ltk050h3146w_of_match); From fc93835bb0d7e2c3e0a664a66d40da3c9f6ed053 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 9 Oct 2023 20:40:46 +0300 Subject: [PATCH 62/80] drm: Add HPD state to drm_connector_oob_hotplug_event() In some implementations, such as the Qualcomm platforms, the display driver has no way to query the current HPD state and as such it's impossible to distinguish between disconnect and attention events. Add a parameter to drm_connector_oob_hotplug_event() to pass the HPD state. Also push the test for unchanged state in the displayport altmode driver into the i915 driver, to allow other drivers to act upon each update. Signed-off-by: Bjorn Andersson Reviewed-by: Hans de Goede Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20231009174048.2695981-2-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231009174048.2695981-2-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_connector.c | 6 ++++-- .../gpu/drm/i915/display/intel_display_core.h | 3 +++ drivers/gpu/drm/i915/display/intel_dp.c | 17 ++++++++++++++--- drivers/usb/typec/altmodes/displayport.c | 17 +++++++++-------- include/drm/drm_connector.h | 6 ++++-- 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 9d4c7b0c5c05..c3725086f413 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -3060,6 +3060,7 @@ struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode) /** * drm_connector_oob_hotplug_event - Report out-of-band hotplug event to connector * @connector_fwnode: fwnode_handle to report the event on + * @status: hot plug detect logical state * * On some hardware a hotplug event notification may come from outside the display * driver / device. An example of this is some USB Type-C setups where the hardware @@ -3069,7 +3070,8 @@ struct drm_connector *drm_connector_find_by_fwnode(struct fwnode_handle *fwnode) * This function can be used to report these out-of-band events after obtaining * a drm_connector reference through calling drm_connector_find_by_fwnode(). */ -void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode) +void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode, + enum drm_connector_status status) { struct drm_connector *connector; @@ -3078,7 +3080,7 @@ void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode) return; if (connector->funcs->oob_hotplug_event) - connector->funcs->oob_hotplug_event(connector); + connector->funcs->oob_hotplug_event(connector, status); drm_connector_put(connector); } diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 53e5c33e08c3..ccfe27630fb6 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -175,6 +175,9 @@ struct intel_hotplug { /* Whether or not to count short HPD IRQs in HPD storms */ u8 hpd_short_storm_enabled; + /* Last state reported by oob_hotplug_event for each encoder */ + unsigned long oob_hotplug_last_state; + /* * if we get a HPD irq from DP and a HPD irq from non-DP * the non-DP HPD could block the workqueue on a mode config diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 65d80eef473b..9c174ff93398 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5723,15 +5723,26 @@ static int intel_dp_connector_atomic_check(struct drm_connector *conn, return intel_modeset_synced_crtcs(state, conn); } -static void intel_dp_oob_hotplug_event(struct drm_connector *connector) +static void intel_dp_oob_hotplug_event(struct drm_connector *connector, + enum drm_connector_status hpd_state) { struct intel_encoder *encoder = intel_attached_encoder(to_intel_connector(connector)); struct drm_i915_private *i915 = to_i915(connector->dev); + bool hpd_high = hpd_state == connector_status_connected; + unsigned int hpd_pin = encoder->hpd_pin; + bool need_work = false; spin_lock_irq(&i915->irq_lock); - i915->display.hotplug.event_bits |= BIT(encoder->hpd_pin); + if (hpd_high != test_bit(hpd_pin, &i915->display.hotplug.oob_hotplug_last_state)) { + i915->display.hotplug.event_bits |= BIT(hpd_pin); + + __assign_bit(hpd_pin, &i915->display.hotplug.oob_hotplug_last_state, hpd_high); + need_work = true; + } spin_unlock_irq(&i915->irq_lock); - queue_delayed_work(i915->unordered_wq, &i915->display.hotplug.hotplug_work, 0); + + if (need_work) + queue_delayed_work(i915->unordered_wq, &i915->display.hotplug.hotplug_work, 0); } static const struct drm_connector_funcs intel_dp_connector_funcs = { diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 426c88a516e5..29f40e658772 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -153,11 +153,11 @@ static int dp_altmode_status_update(struct dp_altmode *dp) } } } else { - if (dp->hpd != hpd) { - drm_connector_oob_hotplug_event(dp->connector_fwnode); - dp->hpd = hpd; - sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd"); - } + drm_connector_oob_hotplug_event(dp->connector_fwnode, + hpd ? connector_status_connected : + connector_status_disconnected); + dp->hpd = hpd; + sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd"); } return ret; @@ -173,7 +173,8 @@ static int dp_altmode_configured(struct dp_altmode *dp) * configuration is complete to signal HPD. */ if (dp->pending_hpd) { - drm_connector_oob_hotplug_event(dp->connector_fwnode); + drm_connector_oob_hotplug_event(dp->connector_fwnode, + connector_status_connected); sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd"); dp->pending_hpd = false; } @@ -618,8 +619,8 @@ void dp_altmode_remove(struct typec_altmode *alt) cancel_work_sync(&dp->work); if (dp->connector_fwnode) { - if (dp->hpd) - drm_connector_oob_hotplug_event(dp->connector_fwnode); + drm_connector_oob_hotplug_event(dp->connector_fwnode, + connector_status_disconnected); fwnode_handle_put(dp->connector_fwnode); } diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h index 6302caa0bd51..fe88d7fc6b8f 100644 --- a/include/drm/drm_connector.h +++ b/include/drm/drm_connector.h @@ -1336,7 +1336,8 @@ struct drm_connector_funcs { * This will get called when a hotplug-event for a drm-connector * has been received from a source outside the display driver / device. */ - void (*oob_hotplug_event)(struct drm_connector *connector); + void (*oob_hotplug_event)(struct drm_connector *connector, + enum drm_connector_status status); /** * @debugfs_init: @@ -1980,7 +1981,8 @@ drm_connector_is_unregistered(struct drm_connector *connector) DRM_CONNECTOR_UNREGISTERED; } -void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode); +void drm_connector_oob_hotplug_event(struct fwnode_handle *connector_fwnode, + enum drm_connector_status status); const char *drm_get_connector_type_name(unsigned int connector_type); const char *drm_get_connector_status_name(enum drm_connector_status status); const char *drm_get_subpixel_order_name(enum subpixel_order order); From 6ec2cf814210fc2df0a59beac895775b6a04d74d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 9 Oct 2023 20:40:47 +0300 Subject: [PATCH 63/80] drm/bridge_connector: stop filtering events in drm_bridge_connector_hpd_cb() In some cases the bridge drivers would like to receive hotplug events even in the case new status is equal to the old status. In the DP case this is used to deliver "attention" messages to the DP host. Stop filtering the events in the drm_bridge_connector_hpd_cb() and let drivers decide whether they would like to receive the event or not. Reviewed-by: Janne Grunau Link: https://lore.kernel.org/r/20231009174048.2695981-3-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231009174048.2695981-3-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_bridge_connector.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index 31baf1f5ff81..70582491d955 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -113,16 +113,11 @@ static void drm_bridge_connector_hpd_cb(void *cb_data, struct drm_bridge_connector *drm_bridge_connector = cb_data; struct drm_connector *connector = &drm_bridge_connector->base; struct drm_device *dev = connector->dev; - enum drm_connector_status old_status; mutex_lock(&dev->mode_config.mutex); - old_status = connector->status; connector->status = status; mutex_unlock(&dev->mode_config.mutex); - if (old_status == status) - return; - drm_bridge_connector_hpd_notify(connector, status); drm_kms_helper_connector_hotplug_event(connector); From ff5f9ae9812c7988049e0ce3c532493994e4b1f5 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Mon, 9 Oct 2023 20:40:48 +0300 Subject: [PATCH 64/80] drm/bridge_connector: implement oob_hotplug_event Implement the oob_hotplug_event() callback. Translate it to the HPD notification sent to the HPD bridge in the chain. Reviewed-by: Janne Grunau Link: https://lore.kernel.org/r/20231009174048.2695981-4-dmitry.baryshkov@linaro.org Signed-off-by: Dmitry Baryshkov Link: https://patchwork.freedesktop.org/patch/msgid/20231009174048.2695981-4-dmitry.baryshkov@linaro.org --- drivers/gpu/drm/drm_bridge_connector.c | 31 +++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c index 70582491d955..8239ad43aed5 100644 --- a/drivers/gpu/drm/drm_bridge_connector.c +++ b/drivers/gpu/drm/drm_bridge_connector.c @@ -5,6 +5,8 @@ #include #include +#include +#include #include #include @@ -107,10 +109,9 @@ static void drm_bridge_connector_hpd_notify(struct drm_connector *connector, } } -static void drm_bridge_connector_hpd_cb(void *cb_data, - enum drm_connector_status status) +static void drm_bridge_connector_handle_hpd(struct drm_bridge_connector *drm_bridge_connector, + enum drm_connector_status status) { - struct drm_bridge_connector *drm_bridge_connector = cb_data; struct drm_connector *connector = &drm_bridge_connector->base; struct drm_device *dev = connector->dev; @@ -123,6 +124,21 @@ static void drm_bridge_connector_hpd_cb(void *cb_data, drm_kms_helper_connector_hotplug_event(connector); } +static void drm_bridge_connector_hpd_cb(void *cb_data, + enum drm_connector_status status) +{ + drm_bridge_connector_handle_hpd(cb_data, status); +} + +static void drm_bridge_connector_oob_hotplug_event(struct drm_connector *connector, + enum drm_connector_status status) +{ + struct drm_bridge_connector *bridge_connector = + to_drm_bridge_connector(connector); + + drm_bridge_connector_handle_hpd(bridge_connector, status); +} + static void drm_bridge_connector_enable_hpd(struct drm_connector *connector) { struct drm_bridge_connector *bridge_connector = @@ -191,6 +207,8 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector) drm_connector_unregister(connector); drm_connector_cleanup(connector); + fwnode_handle_put(connector->fwnode); + kfree(bridge_connector); } @@ -216,6 +234,7 @@ static const struct drm_connector_funcs drm_bridge_connector_funcs = { .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .debugfs_init = drm_bridge_connector_debugfs_init, + .oob_hotplug_event = drm_bridge_connector_oob_hotplug_event, }; /* ----------------------------------------------------------------------------- @@ -352,6 +371,12 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm, if (!drm_bridge_get_next_bridge(bridge)) connector_type = bridge->type; +#ifdef CONFIG_OF + if (!drm_bridge_get_next_bridge(bridge) && + bridge->of_node) + connector->fwnode = fwnode_handle_get(of_fwnode_handle(bridge->of_node)); +#endif + if (bridge->ddc) ddc = bridge->ddc; From 195dd40c49ff6ee13300cb024d0e870e598621f3 Mon Sep 17 00:00:00 2001 From: Sui Jingfeng Date: Mon, 26 Jun 2023 22:33:31 +0800 Subject: [PATCH 65/80] drm/tegra: Remove surplus else after return else is not generally useful after return Signed-off-by: Sui Jingfeng Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20230626143331.640454-2-suijingfeng@loongson.cn --- drivers/gpu/drm/tegra/gem.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index a4023163493d..11296de59c5a 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -180,15 +180,15 @@ static void *tegra_bo_mmap(struct host1x_bo *bo) struct iosys_map map; int ret; - if (obj->vaddr) { + if (obj->vaddr) return obj->vaddr; - } else if (obj->gem.import_attach) { + + if (obj->gem.import_attach) { ret = dma_buf_vmap_unlocked(obj->gem.import_attach->dmabuf, &map); return ret ? NULL : map.vaddr; - } else { - return vmap(obj->pages, obj->num_pages, VM_MAP, - pgprot_writecombine(PAGE_KERNEL)); } + + return vmap(obj->pages, obj->num_pages, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); } static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) @@ -198,10 +198,11 @@ static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) if (obj->vaddr) return; - else if (obj->gem.import_attach) - dma_buf_vunmap_unlocked(obj->gem.import_attach->dmabuf, &map); - else - vunmap(addr); + + if (obj->gem.import_attach) + return dma_buf_vunmap_unlocked(obj->gem.import_attach->dmabuf, &map); + + vunmap(addr); } static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo) From 753c977b1536f6997380f6acb01c3b70dd7ca41a Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Wed, 9 Aug 2023 11:02:26 +0800 Subject: [PATCH 66/80] drm/tegra: Remove two unused function declarations Commit 776dc3840367 ("drm/tegra: Move subdevice infrastructure to host1x") removed the implementation but not the declaration. Signed-off-by: Yue Haibing Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20230809030226.3412-1-yuehaibing@huawei.com --- drivers/gpu/drm/tegra/drm.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index f9d18e8cf6ab..ccb5d74fa227 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -120,9 +120,6 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra, int host1x_client_iommu_attach(struct host1x_client *client); void host1x_client_iommu_detach(struct host1x_client *client); -int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); -int tegra_drm_exit(struct tegra_drm *tegra); - void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *iova); void tegra_drm_free(struct tegra_drm *tegra, size_t size, void *virt, dma_addr_t iova); From f170bed50f9bbc4b03673f40c91f84d4d0258409 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 24 Aug 2023 08:37:00 +0100 Subject: [PATCH 67/80] drm/tegra: hub: Increase buffer size to ensure all possible values can be stored MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When converting from int to string, we must allow for up to 10-chars (2147483647). Fixes the following W=1 kernel build warning(s): drivers/gpu/drm/tegra/hub.c: In function ‘tegra_display_hub_probe’: drivers/gpu/drm/tegra/hub.c:1106:47: warning: ‘%u’ directive output may be truncated writing between 1 and 10 bytes into a region of size 4 [-Wformat-truncation=] drivers/gpu/drm/tegra/hub.c:1106:42: note: directive argument in the range [0, 4294967294] drivers/gpu/drm/tegra/hub.c:1106:17: note: ‘snprintf’ output between 6 and 15 bytes into a destination of size 8 Signed-off-by: Lee Jones Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20230824073710.2677348-16-lee@kernel.org --- drivers/gpu/drm/tegra/hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index 1af5f8318d91..f21e57e8599e 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -1101,7 +1101,7 @@ static int tegra_display_hub_probe(struct platform_device *pdev) for (i = 0; i < hub->soc->num_wgrps; i++) { struct tegra_windowgroup *wgrp = &hub->wgrps[i]; - char id[8]; + char id[16]; snprintf(id, sizeof(id), "wgrp%u", i); mutex_init(&wgrp->lock); From 9764723de613d93b72e95923d25d589f539f07e9 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 1 Sep 2023 14:15:07 +0300 Subject: [PATCH 68/80] gpu: host1x: Add locking in channel allocation Add locking around channel allocation to avoid race conditions. Signed-off-by: Mikko Perttunen Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20230901111510.663401-1-cyndis@kapsi.fi --- drivers/gpu/host1x/channel.c | 7 +++++++ drivers/gpu/host1x/channel.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/drivers/gpu/host1x/channel.c b/drivers/gpu/host1x/channel.c index 2d0051d6314c..79501c957532 100644 --- a/drivers/gpu/host1x/channel.c +++ b/drivers/gpu/host1x/channel.c @@ -27,6 +27,8 @@ int host1x_channel_list_init(struct host1x_channel_list *chlist, return -ENOMEM; } + mutex_init(&chlist->lock); + return 0; } @@ -104,8 +106,11 @@ static struct host1x_channel *acquire_unused_channel(struct host1x *host) unsigned int max_channels = host->info->nb_channels; unsigned int index; + mutex_lock(&chlist->lock); + index = find_first_zero_bit(chlist->allocated_channels, max_channels); if (index >= max_channels) { + mutex_unlock(&chlist->lock); dev_err(host->dev, "failed to find free channel\n"); return NULL; } @@ -114,6 +119,8 @@ static struct host1x_channel *acquire_unused_channel(struct host1x *host) set_bit(index, chlist->allocated_channels); + mutex_unlock(&chlist->lock); + return &chlist->channels[index]; } diff --git a/drivers/gpu/host1x/channel.h b/drivers/gpu/host1x/channel.h index 39044ff6c3aa..b23a8071fbd0 100644 --- a/drivers/gpu/host1x/channel.h +++ b/drivers/gpu/host1x/channel.h @@ -10,6 +10,7 @@ #include #include +#include #include "cdma.h" @@ -18,6 +19,8 @@ struct host1x_channel; struct host1x_channel_list { struct host1x_channel *channels; + + struct mutex lock; unsigned long *allocated_channels; }; From 87fafcd53df8ca5b6695a71aa17f2e7aff464ecc Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 1 Sep 2023 14:15:08 +0300 Subject: [PATCH 69/80] gpu: host1x: Stop CDMA before suspending Before going into suspend, wait all CDMA to go idle and stop it. This will ensure no channel is still active while we enter suspend, and ensures the driver doesn't think that CDMA is still active when coming back from suspend (as HW state has been reset). Signed-off-by: Mikko Perttunen Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20230901111510.663401-2-cyndis@kapsi.fi --- drivers/gpu/host1x/channel.c | 19 +++++++++++++++++++ drivers/gpu/host1x/channel.h | 1 + drivers/gpu/host1x/dev.c | 1 + 3 files changed, 21 insertions(+) diff --git a/drivers/gpu/host1x/channel.c b/drivers/gpu/host1x/channel.c index 79501c957532..08077afe4cde 100644 --- a/drivers/gpu/host1x/channel.c +++ b/drivers/gpu/host1x/channel.c @@ -81,6 +81,25 @@ void host1x_channel_stop(struct host1x_channel *channel) } EXPORT_SYMBOL(host1x_channel_stop); +/** + * host1x_channel_stop_all() - disable CDMA on allocated channels + * @host: host1x instance + * + * Stop CDMA on allocated channels + */ +void host1x_channel_stop_all(struct host1x *host) +{ + struct host1x_channel_list *chlist = &host->channel_list; + int bit; + + mutex_lock(&chlist->lock); + + for_each_set_bit(bit, chlist->allocated_channels, host->info->nb_channels) + host1x_channel_stop(&chlist->channels[bit]); + + mutex_unlock(&chlist->lock); +} + static void release_channel(struct kref *kref) { struct host1x_channel *channel = diff --git a/drivers/gpu/host1x/channel.h b/drivers/gpu/host1x/channel.h index b23a8071fbd0..d7aede204d83 100644 --- a/drivers/gpu/host1x/channel.h +++ b/drivers/gpu/host1x/channel.h @@ -40,5 +40,6 @@ int host1x_channel_list_init(struct host1x_channel_list *chlist, void host1x_channel_list_free(struct host1x_channel_list *chlist); struct host1x_channel *host1x_channel_get_index(struct host1x *host, unsigned int index); +void host1x_channel_stop_all(struct host1x *host); #endif diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 7c6699aed7d2..6501bee9e8c1 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -655,6 +655,7 @@ static int __maybe_unused host1x_runtime_suspend(struct device *dev) struct host1x *host = dev_get_drvdata(dev); int err; + host1x_channel_stop_all(host); host1x_intr_stop(host); host1x_syncpt_save(host); From b7c00cdf6df58b1d48d31d57f9431a200b0d0c88 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 1 Sep 2023 14:15:09 +0300 Subject: [PATCH 70/80] gpu: host1x: Enable system suspend callbacks With the previous CDMA stop fix, executing runtime PM ops around system suspend now makes channel submissions work after system suspend, so do that. Signed-off-by: Mikko Perttunen Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20230901111510.663401-3-cyndis@kapsi.fi --- drivers/gpu/host1x/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 6501bee9e8c1..b8ac44e7d11a 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -720,7 +720,7 @@ release_reset: static const struct dev_pm_ops host1x_pm_ops = { SET_RUNTIME_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume, NULL) - /* TODO: add system suspend-resume once driver will be ready for that */ + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra_host1x_driver = { From f017f1e9cb3458a86f586a171e284e2ec46286db Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 1 Sep 2023 14:40:07 +0300 Subject: [PATCH 71/80] gpu: host1x: Syncpoint interrupt sharding Support sharded syncpoint interrupts on Tegra234+. This feature allows specifying one of eight interrupt lines for each syncpoint to lower processing latency of syncpoint threshold interrupts. Signed-off-by: Mikko Perttunen Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20230901114008.672433-1-cyndis@kapsi.fi --- drivers/gpu/host1x/dev.c | 29 ++++++++++++++++++--- drivers/gpu/host1x/dev.h | 3 ++- drivers/gpu/host1x/hw/intr_hw.c | 46 ++++++++++++++++++++++++--------- 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index b8ac44e7d11a..42fd504abbcd 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -488,7 +488,7 @@ static int host1x_get_resets(struct host1x *host) static int host1x_probe(struct platform_device *pdev) { struct host1x *host; - int err; + int err, i; host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); if (!host) @@ -516,9 +516,30 @@ static int host1x_probe(struct platform_device *pdev) return PTR_ERR(host->regs); } - host->syncpt_irq = platform_get_irq(pdev, 0); - if (host->syncpt_irq < 0) - return host->syncpt_irq; + for (i = 0; i < ARRAY_SIZE(host->syncpt_irqs); i++) { + char irq_name[] = "syncptX"; + + sprintf(irq_name, "syncpt%d", i); + + err = platform_get_irq_byname_optional(pdev, irq_name); + if (err == -ENXIO) + break; + if (err < 0) + return err; + + host->syncpt_irqs[i] = err; + } + + host->num_syncpt_irqs = i; + + /* Device tree without irq names */ + if (i == 0) { + host->syncpt_irqs[0] = platform_get_irq(pdev, 0); + if (host->syncpt_irqs[0] < 0) + return host->syncpt_irqs[0]; + + host->num_syncpt_irqs = 1; + } mutex_init(&host->devices_lock); INIT_LIST_HEAD(&host->devices); diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index 75de50fe03d0..c8e302de7625 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -124,7 +124,8 @@ struct host1x { void __iomem *regs; void __iomem *hv_regs; /* hypervisor region */ void __iomem *common_regs; - int syncpt_irq; + int syncpt_irqs[8]; + int num_syncpt_irqs; struct host1x_syncpt *syncpt; struct host1x_syncpt_base *bases; struct device *dev; diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c index b915ef7d0348..9880e0c47235 100644 --- a/drivers/gpu/host1x/hw/intr_hw.c +++ b/drivers/gpu/host1x/hw/intr_hw.c @@ -13,13 +13,20 @@ #include "../intr.h" #include "../dev.h" +struct host1x_intr_irq_data { + struct host1x *host; + u32 offset; +}; + static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) { - struct host1x *host = dev_id; + struct host1x_intr_irq_data *irq_data = dev_id; + struct host1x *host = irq_data->host; unsigned long reg; unsigned int i, id; - for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) { + for (i = irq_data->offset; i < DIV_ROUND_UP(host->info->nb_pts, 32); + i += host->num_syncpt_irqs) { reg = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); @@ -67,26 +74,41 @@ static void intr_hw_init(struct host1x *host, u32 cpm) /* * Program threshold interrupt destination among 8 lines per VM, - * per syncpoint. For now, just direct all to the first interrupt - * line. + * per syncpoint. For each group of 32 syncpoints (corresponding to one + * interrupt status register), direct to one interrupt line, going + * around in a round robin fashion. */ - for (id = 0; id < host->info->nb_pts; id++) - host1x_sync_writel(host, 0, HOST1X_SYNC_SYNCPT_INTR_DEST(id)); + for (id = 0; id < host->info->nb_pts; id++) { + u32 reg_offset = id / 32; + u32 irq_index = reg_offset % host->num_syncpt_irqs; + + host1x_sync_writel(host, irq_index, HOST1X_SYNC_SYNCPT_INTR_DEST(id)); + } #endif } static int host1x_intr_init_host_sync(struct host1x *host, u32 cpm) { - int err; + int err, i; + struct host1x_intr_irq_data *irq_data; + + irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL); + if (!irq_data) + return -ENOMEM; host1x_hw_intr_disable_all_syncpt_intrs(host); - err = devm_request_irq(host->dev, host->syncpt_irq, - syncpt_thresh_isr, IRQF_SHARED, - "host1x_syncpt", host); - if (err < 0) - return err; + for (i = 0; i < host->num_syncpt_irqs; i++) { + irq_data[i].host = host; + irq_data[i].offset = i; + + err = devm_request_irq(host->dev, host->syncpt_irqs[i], + syncpt_thresh_isr, IRQF_SHARED, + "host1x_syncpt", &irq_data[i]); + if (err < 0) + return err; + } intr_hw_init(host, cpm); From e889a311f74f4ae8bd40755a2c58d02e1c684fef Mon Sep 17 00:00:00 2001 From: Johnny Liu Date: Fri, 1 Sep 2023 14:59:09 +0300 Subject: [PATCH 72/80] gpu: host1x: Correct allocated size for contexts Original implementation over allocates the memory size for the contexts list. The size of memory for the contexts list is based on the number of iommu groups specified in the device tree. Fixes: 8aa5bcb61612 ("gpu: host1x: Add context device management code") Signed-off-by: Johnny Liu Signed-off-by: Mikko Perttunen Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20230901115910.701518-1-cyndis@kapsi.fi --- drivers/gpu/host1x/context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/host1x/context.c b/drivers/gpu/host1x/context.c index a3f336edd991..955c971c528d 100644 --- a/drivers/gpu/host1x/context.c +++ b/drivers/gpu/host1x/context.c @@ -34,10 +34,10 @@ int host1x_memory_context_list_init(struct host1x *host1x) if (err < 0) return 0; - cdl->devs = kcalloc(err, sizeof(*cdl->devs), GFP_KERNEL); + cdl->len = err / 4; + cdl->devs = kcalloc(cdl->len, sizeof(*cdl->devs), GFP_KERNEL); if (!cdl->devs) return -ENOMEM; - cdl->len = err / 4; for (i = 0; i < cdl->len; i++) { ctx = &cdl->devs[i]; From 3868ff006b572cf501a3327832d36c64a9eca86a Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 1 Sep 2023 14:59:10 +0300 Subject: [PATCH 73/80] drm/tegra: Zero-initialize iosys_map UBSAN reports an invalid load for bool, as the iosys_map is read later without being initialized. Zero-initialize it to avoid this. Reported-by: Ashish Mhetre Signed-off-by: Mikko Perttunen Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/20230901115910.701518-2-cyndis@kapsi.fi --- drivers/gpu/drm/tegra/gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 11296de59c5a..363e02f86382 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -177,7 +177,7 @@ static void tegra_bo_unpin(struct host1x_bo_mapping *map) static void *tegra_bo_mmap(struct host1x_bo *bo) { struct tegra_bo *obj = host1x_to_tegra_bo(bo); - struct iosys_map map; + struct iosys_map map = { 0 }; int ret; if (obj->vaddr) From 3f257bc63c0dcf50135971727e10e54f938d7fd7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 10 Oct 2023 17:26:14 +0200 Subject: [PATCH 74/80] drm/tegra: gem: Do not return NULL in tegra_bo_mmap() It's confusing for a function to return NULL and ERR_PTR()-encoded error codes on failure. Make sure we only ever return the latter since that's what callers already expect. Reported-by: Sui Jingfeng Reviewed-by: Sui Jingfeng Signed-off-by: Thierry Reding Link: https://patchwork.freedesktop.org/patch/msgid/ZSVuVcqdGfGtQIQj@orome.fritz.box --- drivers/gpu/drm/tegra/gem.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 363e02f86382..b4eb030ea961 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -178,6 +178,7 @@ static void *tegra_bo_mmap(struct host1x_bo *bo) { struct tegra_bo *obj = host1x_to_tegra_bo(bo); struct iosys_map map = { 0 }; + void *vaddr; int ret; if (obj->vaddr) @@ -185,10 +186,18 @@ static void *tegra_bo_mmap(struct host1x_bo *bo) if (obj->gem.import_attach) { ret = dma_buf_vmap_unlocked(obj->gem.import_attach->dmabuf, &map); - return ret ? NULL : map.vaddr; + if (ret < 0) + return ERR_PTR(ret); + + return map.vaddr; } - return vmap(obj->pages, obj->num_pages, VM_MAP, pgprot_writecombine(PAGE_KERNEL)); + vaddr = vmap(obj->pages, obj->num_pages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; } static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) From c205a67d28766ffaae3d02cdffc9c86d52ed6c2e Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 22 Sep 2023 10:04:55 +0200 Subject: [PATCH 75/80] fbdev: Avoid file argument in fb_pgprotect() Only PowerPC's fb_pgprotect() needs the file argument, although the implementation in either phys_mem_access_prot() or pci_phys_mem_access_prot() does not use it. Pass NULL to the internal helper in preparation of further updates. A later patch will remove the file parameter from fb_pgprotect(). While at it, replace the shift operation with PHYS_PFN(). v5: * state function names in commit description (Javier) Suggested-by: Christophe Leroy Signed-off-by: Thomas Zimmermann Reviewed-by: Arnd Bergmann Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20230922080636.26762-2-tzimmermann@suse.de --- arch/powerpc/include/asm/fb.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/fb.h b/arch/powerpc/include/asm/fb.h index 5f1a2e5f7654..61e3b8806db6 100644 --- a/arch/powerpc/include/asm/fb.h +++ b/arch/powerpc/include/asm/fb.h @@ -9,7 +9,12 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, unsigned long off) { - vma->vm_page_prot = phys_mem_access_prot(file, off >> PAGE_SHIFT, + /* + * PowerPC's implementation of phys_mem_access_prot() does + * not use the file argument. Set it to NULL in preparation + * of later updates to the interface. + */ + vma->vm_page_prot = phys_mem_access_prot(NULL, PHYS_PFN(off), vma->vm_end - vma->vm_start, vma->vm_page_prot); } From 052ddf7b86d2d9443bce77ef5b5b1ef61a3b79fc Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 22 Sep 2023 10:04:56 +0200 Subject: [PATCH 76/80] fbdev: Replace fb_pgprotect() with pgprot_framebuffer() Rename the fbdev mmap helper fb_pgprotect() to pgprot_framebuffer(). The helper sets VMA page-access flags for framebuffers in device I/O memory. Also clean up the helper's parameters and return value. Instead of the VMA instance, pass the individial parameters separately: existing page-access flags, the VMAs start and end addresses and the offset in the underlying device memory rsp file. Return the new page-access flags. These changes align pgprot_framebuffer() with other pgprot_() functions. v4: * fix commit message (Christophe) v3: * rename fb_pgprotect() to pgprot_framebuffer() (Arnd) Signed-off-by: Thomas Zimmermann Reviewed-by: Arnd Bergmann Acked-by: Geert Uytterhoeven # m68k Reviewed-by: Javier Martinez Canillas Link: https://patchwork.freedesktop.org/patch/msgid/20230922080636.26762-3-tzimmermann@suse.de --- arch/ia64/include/asm/fb.h | 15 +++++++-------- arch/m68k/include/asm/fb.h | 19 ++++++++++--------- arch/mips/include/asm/fb.h | 11 +++++------ arch/powerpc/include/asm/fb.h | 13 +++++-------- arch/sparc/include/asm/fb.h | 15 +++++++++------ arch/x86/include/asm/fb.h | 12 +++++++----- arch/x86/video/fbdev.c | 15 ++++++++------- drivers/video/fbdev/core/fb_chrdev.c | 3 ++- include/asm-generic/fb.h | 12 ++++++------ 9 files changed, 59 insertions(+), 56 deletions(-) diff --git a/arch/ia64/include/asm/fb.h b/arch/ia64/include/asm/fb.h index 1717b26fd423..7fce0d542359 100644 --- a/arch/ia64/include/asm/fb.h +++ b/arch/ia64/include/asm/fb.h @@ -8,17 +8,16 @@ #include -struct file; - -static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, - unsigned long off) +static inline pgprot_t pgprot_framebuffer(pgprot_t prot, + unsigned long vm_start, unsigned long vm_end, + unsigned long offset) { - if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start)) - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + if (efi_range_is_wc(vm_start, vm_end - vm_start)) + return pgprot_writecombine(prot); else - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + return pgprot_noncached(prot); } -#define fb_pgprotect fb_pgprotect +#define pgprot_framebuffer pgprot_framebuffer static inline void fb_memcpy_fromio(void *to, const volatile void __iomem *from, size_t n) { diff --git a/arch/m68k/include/asm/fb.h b/arch/m68k/include/asm/fb.h index 24273fc7ad91..9941b7434b69 100644 --- a/arch/m68k/include/asm/fb.h +++ b/arch/m68k/include/asm/fb.h @@ -5,26 +5,27 @@ #include #include -struct file; - -static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, - unsigned long off) +static inline pgprot_t pgprot_framebuffer(pgprot_t prot, + unsigned long vm_start, unsigned long vm_end, + unsigned long offset) { #ifdef CONFIG_MMU #ifdef CONFIG_SUN3 - pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE; + pgprot_val(prot) |= SUN3_PAGE_NOCACHE; #else if (CPU_IS_020_OR_030) - pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030; + pgprot_val(prot) |= _PAGE_NOCACHE030; if (CPU_IS_040_OR_060) { - pgprot_val(vma->vm_page_prot) &= _CACHEMASK040; + pgprot_val(prot) &= _CACHEMASK040; /* Use no-cache mode, serialized */ - pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S; + pgprot_val(prot) |= _PAGE_NOCACHE_S; } #endif /* CONFIG_SUN3 */ #endif /* CONFIG_MMU */ + + return prot; } -#define fb_pgprotect fb_pgprotect +#define pgprot_framebuffer pgprot_framebuffer #include diff --git a/arch/mips/include/asm/fb.h b/arch/mips/include/asm/fb.h index 18b7226403ba..d98d6681d64e 100644 --- a/arch/mips/include/asm/fb.h +++ b/arch/mips/include/asm/fb.h @@ -3,14 +3,13 @@ #include -struct file; - -static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, - unsigned long off) +static inline pgprot_t pgprot_framebuffer(pgprot_t prot, + unsigned long vm_start, unsigned long vm_end, + unsigned long offset) { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + return pgprot_noncached(prot); } -#define fb_pgprotect fb_pgprotect +#define pgprot_framebuffer pgprot_framebuffer /* * MIPS doesn't define __raw_ I/O macros, so the helpers diff --git a/arch/powerpc/include/asm/fb.h b/arch/powerpc/include/asm/fb.h index 61e3b8806db6..3cecf14d51de 100644 --- a/arch/powerpc/include/asm/fb.h +++ b/arch/powerpc/include/asm/fb.h @@ -2,23 +2,20 @@ #ifndef _ASM_FB_H_ #define _ASM_FB_H_ -#include - #include -static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, - unsigned long off) +static inline pgprot_t pgprot_framebuffer(pgprot_t prot, + unsigned long vm_start, unsigned long vm_end, + unsigned long offset) { /* * PowerPC's implementation of phys_mem_access_prot() does * not use the file argument. Set it to NULL in preparation * of later updates to the interface. */ - vma->vm_page_prot = phys_mem_access_prot(NULL, PHYS_PFN(off), - vma->vm_end - vma->vm_start, - vma->vm_page_prot); + return phys_mem_access_prot(NULL, PHYS_PFN(offset), vm_end - vm_start, prot); } -#define fb_pgprotect fb_pgprotect +#define pgprot_framebuffer pgprot_framebuffer #include diff --git a/arch/sparc/include/asm/fb.h b/arch/sparc/include/asm/fb.h index 572ecd3e1cc4..24440c0fda49 100644 --- a/arch/sparc/include/asm/fb.h +++ b/arch/sparc/include/asm/fb.h @@ -4,15 +4,18 @@ #include +#include + struct fb_info; -struct file; -struct vm_area_struct; #ifdef CONFIG_SPARC32 -static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, - unsigned long off) -{ } -#define fb_pgprotect fb_pgprotect +static inline pgprot_t pgprot_framebuffer(pgprot_t prot, + unsigned long vm_start, unsigned long vm_end, + unsigned long offset) +{ + return prot; +} +#define pgprot_framebuffer pgprot_framebuffer #endif int fb_is_primary_device(struct fb_info *info); diff --git a/arch/x86/include/asm/fb.h b/arch/x86/include/asm/fb.h index 23873da8fb77..c3b9582de7ef 100644 --- a/arch/x86/include/asm/fb.h +++ b/arch/x86/include/asm/fb.h @@ -2,12 +2,14 @@ #ifndef _ASM_X86_FB_H #define _ASM_X86_FB_H -struct fb_info; -struct file; -struct vm_area_struct; +#include -void fb_pgprotect(struct file *file, struct vm_area_struct *vma, unsigned long off); -#define fb_pgprotect fb_pgprotect +struct fb_info; + +pgprot_t pgprot_framebuffer(pgprot_t prot, + unsigned long vm_start, unsigned long vm_end, + unsigned long offset); +#define pgprot_framebuffer pgprot_framebuffer int fb_is_primary_device(struct fb_info *info); #define fb_is_primary_device fb_is_primary_device diff --git a/arch/x86/video/fbdev.c b/arch/x86/video/fbdev.c index 49a0452402e9..1dd6528cc947 100644 --- a/arch/x86/video/fbdev.c +++ b/arch/x86/video/fbdev.c @@ -13,16 +13,17 @@ #include #include -void fb_pgprotect(struct file *file, struct vm_area_struct *vma, unsigned long off) +pgprot_t pgprot_framebuffer(pgprot_t prot, + unsigned long vm_start, unsigned long vm_end, + unsigned long offset) { - unsigned long prot; - - prot = pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK; + pgprot_val(prot) &= ~_PAGE_CACHE_MASK; if (boot_cpu_data.x86 > 3) - pgprot_val(vma->vm_page_prot) = - prot | cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS); + pgprot_val(prot) |= cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS); + + return prot; } -EXPORT_SYMBOL(fb_pgprotect); +EXPORT_SYMBOL(pgprot_framebuffer); int fb_is_primary_device(struct fb_info *info) { diff --git a/drivers/video/fbdev/core/fb_chrdev.c b/drivers/video/fbdev/core/fb_chrdev.c index eadb81f53a82..32a7315b4b6d 100644 --- a/drivers/video/fbdev/core/fb_chrdev.c +++ b/drivers/video/fbdev/core/fb_chrdev.c @@ -365,7 +365,8 @@ static int fb_mmap(struct file *file, struct vm_area_struct *vma) mutex_unlock(&info->mm_lock); vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - fb_pgprotect(file, vma, start); + vma->vm_page_prot = pgprot_framebuffer(vma->vm_page_prot, vma->vm_start, + vma->vm_end, start); return vm_iomap_memory(vma, start, len); } diff --git a/include/asm-generic/fb.h b/include/asm-generic/fb.h index bb7ee9c70e60..6ccabb400aa6 100644 --- a/include/asm-generic/fb.h +++ b/include/asm-generic/fb.h @@ -12,14 +12,14 @@ #include struct fb_info; -struct file; -#ifndef fb_pgprotect -#define fb_pgprotect fb_pgprotect -static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, - unsigned long off) +#ifndef pgprot_framebuffer +#define pgprot_framebuffer pgprot_framebuffer +static inline pgprot_t pgprot_framebuffer(pgprot_t prot, + unsigned long vm_start, unsigned long vm_end, + unsigned long offset) { - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + return pgprot_writecombine(prot); } #endif From f2f455981a34ce8ca88a41458c09494b387d344f Mon Sep 17 00:00:00 2001 From: Carlos Eduardo Gallo Filho Date: Tue, 26 Sep 2023 11:15:18 -0300 Subject: [PATCH 77/80] drm: Remove plane hsub/vsub alignment requirement for core helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drm_format_info_plane_{height,width} functions was implemented using regular division for the plane size calculation, which cause issues [1][2] when used on contexts where the dimensions are misaligned with relation to the subsampling factors. So, replace the regular division by the DIV_ROUND_UP macro. This allows these functions to be used in more drivers, making further work to bring more core presence on them possible. [1] http://patchwork.freedesktop.org/patch/msgid/20170321181218.10042-3-ville.syrjala@linux.intel.com [2] https://patchwork.freedesktop.org/patch/msgid/20211026225105.2783797-2-imre.deak@intel.com Signed-off-by: Carlos Eduardo Gallo Filho Reviewed-by: André Almeida Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20230926141519.9315-2-gcarlos@disroot.org --- include/drm/drm_fourcc.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index 532ae78ca747..ccf91daa4307 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -22,6 +22,7 @@ #ifndef __DRM_FOURCC_H__ #define __DRM_FOURCC_H__ +#include #include #include @@ -279,7 +280,7 @@ int drm_format_info_plane_width(const struct drm_format_info *info, int width, if (plane == 0) return width; - return width / info->hsub; + return DIV_ROUND_UP(width, info->hsub); } /** @@ -301,7 +302,7 @@ int drm_format_info_plane_height(const struct drm_format_info *info, int height, if (plane == 0) return height; - return height / info->vsub; + return DIV_ROUND_UP(height, info->vsub); } const struct drm_format_info *__drm_format_info(u32 format); From 451921e7bbc74fd87bfc9b413e4d57cc498fcca8 Mon Sep 17 00:00:00 2001 From: Carlos Eduardo Gallo Filho Date: Tue, 26 Sep 2023 11:15:19 -0300 Subject: [PATCH 78/80] drm: Replace drm_framebuffer plane size functions with its equivalents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions drm_framebuffer_plane_{width,height} and fb_plane_{width,height} do exactly the same job of its equivalents drm_format_info_plane_{width,height} from drm_fourcc. The only reason to have these functions on drm_framebuffer would be if they would added a abstraction layer to call it just passing a drm_framebuffer pointer and the desired plane index, which is not the case, where these functions actually implements just part of it. In the actual implementation, every call to both drm_framebuffer_plane_{width,height} and fb_plane_{width,height} should pass some drm_framebuffer attribute, which is the same as calling the drm_format_info_plane_{width,height} functions. The drm_format_info_pane_{width,height} functions are much more consistent in both its implementation and its location on code. The kind of calculation that they do is intrinsically derivated from the drm_format_info struct and has not to do with drm_framebuffer, except by the potential motivation described above, which is still not a good justification to have drm_framebuffer functions to calculate it. So, replace each drm_framebuffer_plane_{width,height} and fb_plane_{width,height} call to drm_format_info_plane_{width,height} and remove them. Signed-off-by: Carlos Eduardo Gallo Filho Reviewed-by: André Almeida Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20230926141519.9315-3-gcarlos@disroot.org --- drivers/gpu/drm/drm_framebuffer.c | 64 ++----------------------- drivers/gpu/drm/i915/display/intel_fb.c | 2 +- include/drm/drm_framebuffer.h | 5 -- 3 files changed, 5 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/drm_framebuffer.c b/drivers/gpu/drm/drm_framebuffer.c index ba51deb6d042..d3ba0698b84b 100644 --- a/drivers/gpu/drm/drm_framebuffer.c +++ b/drivers/gpu/drm/drm_framebuffer.c @@ -151,24 +151,6 @@ int drm_mode_addfb_ioctl(struct drm_device *dev, return drm_mode_addfb(dev, data, file_priv); } -static int fb_plane_width(int width, - const struct drm_format_info *format, int plane) -{ - if (plane == 0) - return width; - - return DIV_ROUND_UP(width, format->hsub); -} - -static int fb_plane_height(int height, - const struct drm_format_info *format, int plane) -{ - if (plane == 0) - return height; - - return DIV_ROUND_UP(height, format->vsub); -} - static int framebuffer_check(struct drm_device *dev, const struct drm_mode_fb_cmd2 *r) { @@ -196,8 +178,8 @@ static int framebuffer_check(struct drm_device *dev, info = drm_get_format_info(dev, r); for (i = 0; i < info->num_planes; i++) { - unsigned int width = fb_plane_width(r->width, info, i); - unsigned int height = fb_plane_height(r->height, info, i); + unsigned int width = drm_format_info_plane_width(info, r->width, i); + unsigned int height = drm_format_info_plane_height(info, r->height, i); unsigned int block_size = info->char_per_block[i]; u64 min_pitch = drm_format_info_min_pitch(info, i, width); @@ -1136,44 +1118,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) } EXPORT_SYMBOL(drm_framebuffer_remove); -/** - * drm_framebuffer_plane_width - width of the plane given the first plane - * @width: width of the first plane - * @fb: the framebuffer - * @plane: plane index - * - * Returns: - * The width of @plane, given that the width of the first plane is @width. - */ -int drm_framebuffer_plane_width(int width, - const struct drm_framebuffer *fb, int plane) -{ - if (plane >= fb->format->num_planes) - return 0; - - return fb_plane_width(width, fb->format, plane); -} -EXPORT_SYMBOL(drm_framebuffer_plane_width); - -/** - * drm_framebuffer_plane_height - height of the plane given the first plane - * @height: height of the first plane - * @fb: the framebuffer - * @plane: plane index - * - * Returns: - * The height of @plane, given that the height of the first plane is @height. - */ -int drm_framebuffer_plane_height(int height, - const struct drm_framebuffer *fb, int plane) -{ - if (plane >= fb->format->num_planes) - return 0; - - return fb_plane_height(height, fb->format, plane); -} -EXPORT_SYMBOL(drm_framebuffer_plane_height); - void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, const struct drm_framebuffer *fb) { @@ -1189,8 +1133,8 @@ void drm_framebuffer_print_info(struct drm_printer *p, unsigned int indent, for (i = 0; i < fb->format->num_planes; i++) { drm_printf_indent(p, indent + 1, "size[%u]=%dx%d\n", i, - drm_framebuffer_plane_width(fb->width, fb, i), - drm_framebuffer_plane_height(fb->height, fb, i)); + drm_format_info_plane_width(fb->format, fb->width, i), + drm_format_info_plane_height(fb->format, fb->height, i)); drm_printf_indent(p, indent + 1, "pitch[%u]=%u\n", i, fb->pitches[i]); drm_printf_indent(p, indent + 1, "offset[%u]=%u\n", i, fb->offsets[i]); drm_printf_indent(p, indent + 1, "obj[%u]:%s\n", i, diff --git a/drivers/gpu/drm/i915/display/intel_fb.c b/drivers/gpu/drm/i915/display/intel_fb.c index e7678571b0d7..19b35ece31f1 100644 --- a/drivers/gpu/drm/i915/display/intel_fb.c +++ b/drivers/gpu/drm/i915/display/intel_fb.c @@ -1117,7 +1117,7 @@ static int intel_fb_offset_to_xy(int *x, int *y, return -EINVAL; } - height = drm_framebuffer_plane_height(fb->height, fb, color_plane); + height = drm_format_info_plane_height(fb->format, fb->height, color_plane); height = ALIGN(height, intel_tile_height(fb, color_plane)); /* Catch potential overflows early */ diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index 0dcc07b68654..80ece7b6dd9b 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -292,11 +292,6 @@ static inline void drm_framebuffer_assign(struct drm_framebuffer **p, &fb->head != (&(dev)->mode_config.fb_list); \ fb = list_next_entry(fb, head)) -int drm_framebuffer_plane_width(int width, - const struct drm_framebuffer *fb, int plane); -int drm_framebuffer_plane_height(int height, - const struct drm_framebuffer *fb, int plane); - /** * struct drm_afbc_framebuffer - a special afbc frame buffer object * From b9f29205c0182a2059b4dfa2883db5ef423574d4 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 30 Sep 2023 15:14:27 -0700 Subject: [PATCH 79/80] iosys-map: fix kernel-doc typos Correct spelling of "beginning". Signed-off-by: Randy Dunlap Cc: Thomas Zimmermann Cc: dri-devel@lists.freedesktop.org Reviewed-by: Thomas Zimmermann Signed-off-by: Thomas Zimmermann Link: https://patchwork.freedesktop.org/patch/msgid/20230930221428.18463-2-rdunlap@infradead.org --- include/linux/iosys-map.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/iosys-map.h b/include/linux/iosys-map.h index cb71aa616bd3..1b06d074ade0 100644 --- a/include/linux/iosys-map.h +++ b/include/linux/iosys-map.h @@ -426,7 +426,7 @@ static inline void iosys_map_memset(struct iosys_map *dst, size_t offset, * iosys_map_rd_field - Read a member from a struct in the iosys_map * * @map__: The iosys_map structure - * @struct_offset__: Offset from the beggining of the map, where the struct + * @struct_offset__: Offset from the beginning of the map, where the struct * is located * @struct_type__: The struct describing the layout of the mapping * @field__: Member of the struct to read @@ -494,7 +494,7 @@ static inline void iosys_map_memset(struct iosys_map *dst, size_t offset, * iosys_map_wr_field - Write to a member of a struct in the iosys_map * * @map__: The iosys_map structure - * @struct_offset__: Offset from the beggining of the map, where the struct + * @struct_offset__: Offset from the beginning of the map, where the struct * is located * @struct_type__: The struct describing the layout of the mapping * @field__: Member of the struct to read From c395c83aafbb9cdbe4230f044d5b8eaf9080c0c5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 11 Oct 2023 16:32:30 +0200 Subject: [PATCH 80/80] drm/simpledrm: Fix power domain device link validity check We need to check if a link is non-NULL before trying to delete it. Fixes: 61df9ca23107 ("drm/simpledrm: Add support for multiple "power-domains"") Signed-off-by: Thierry Reding Signed-off-by: Thomas Zimmermann Reviewed-by: Thomas Zimmermann Cc: Janne Grunau Cc: Eric Curtin Cc: Neal Gompa Cc: Sven Peter Cc: Javier Martinez Canillas Cc: dri-devel@lists.freedesktop.org Link: https://patchwork.freedesktop.org/patch/msgid/20231011143230.1107731-1-thierry.reding@gmail.com --- drivers/gpu/drm/tiny/simpledrm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tiny/simpledrm.c b/drivers/gpu/drm/tiny/simpledrm.c index 9c597461d1e2..8bdaf66044fc 100644 --- a/drivers/gpu/drm/tiny/simpledrm.c +++ b/drivers/gpu/drm/tiny/simpledrm.c @@ -506,7 +506,7 @@ static void simpledrm_device_detach_genpd(void *res) return; for (i = sdev->pwr_dom_count - 1; i >= 0; i--) { - if (!sdev->pwr_dom_links[i]) + if (sdev->pwr_dom_links[i]) device_link_del(sdev->pwr_dom_links[i]); if (!IS_ERR_OR_NULL(sdev->pwr_dom_devs[i])) dev_pm_domain_detach(sdev->pwr_dom_devs[i], true);