[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250623-simple-drm-fb-icc-v2-3-f69b86cd3d7d@fairphone.com>
Date: Mon, 23 Jun 2025 08:44:47 +0200
From: Luca Weiss <luca.weiss@...rphone.com>
To: Hans de Goede <hdegoede@...hat.com>,
Maarten Lankhorst <maarten.lankhorst@...ux.intel.com>,
Maxime Ripard <mripard@...nel.org>, Thomas Zimmermann <tzimmermann@...e.de>,
David Airlie <airlied@...il.com>, Simona Vetter <simona@...ll.ch>,
Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>,
Conor Dooley <conor+dt@...nel.org>,
Javier Martinez Canillas <javierm@...hat.com>, Helge Deller <deller@....de>
Cc: linux-fbdev@...r.kernel.org, dri-devel@...ts.freedesktop.org,
devicetree@...r.kernel.org, linux-kernel@...r.kernel.org,
Luca Weiss <luca.weiss@...rphone.com>
Subject: [PATCH v2 3/5] drm/sysfb: simpledrm: Add support for interconnect
paths
Some devices might require keeping an interconnect path alive so that
the framebuffer continues working. Add support for that by setting the
bandwidth requirements appropriately for all provided interconnect
paths.
Reviewed-by: Thomas Zimmermann <tzimmermann@...e.de>
Signed-off-by: Luca Weiss <luca.weiss@...rphone.com>
---
drivers/gpu/drm/sysfb/simpledrm.c | 83 +++++++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git a/drivers/gpu/drm/sysfb/simpledrm.c b/drivers/gpu/drm/sysfb/simpledrm.c
index 349219330314e3421a6bb26ad5cf39a679a5cb7a..47d213e20cab1dd1e19528674a95edea00f4bb30 100644
--- a/drivers/gpu/drm/sysfb/simpledrm.c
+++ b/drivers/gpu/drm/sysfb/simpledrm.c
@@ -2,6 +2,7 @@
#include <linux/aperture.h>
#include <linux/clk.h>
+#include <linux/interconnect.h>
#include <linux/minmax.h>
#include <linux/of_address.h>
#include <linux/of_clk.h>
@@ -225,6 +226,10 @@ struct simpledrm_device {
struct device **pwr_dom_devs;
struct device_link **pwr_dom_links;
#endif
+#if defined CONFIG_OF && defined CONFIG_INTERCONNECT
+ unsigned int icc_count;
+ struct icc_path **icc_paths;
+#endif
/* modesetting */
u32 formats[DRM_SYSFB_PLANE_NFORMATS(1)];
@@ -547,6 +552,81 @@ static int simpledrm_device_attach_genpd(struct simpledrm_device *sdev)
}
#endif
+#if defined CONFIG_OF && defined CONFIG_INTERCONNECT
+/*
+ * Generic interconnect path handling code.
+ */
+static void simpledrm_device_detach_icc(void *res)
+{
+ struct simpledrm_device *sdev = res;
+ int i;
+
+ for (i = sdev->icc_count - 1; i >= 0; i--) {
+ if (!IS_ERR_OR_NULL(sdev->icc_paths[i]))
+ icc_put(sdev->icc_paths[i]);
+ }
+}
+
+static int simpledrm_device_attach_icc(struct simpledrm_device *sdev)
+{
+ struct device *dev = sdev->sysfb.dev.dev;
+ int ret, count, i;
+
+ count = of_count_phandle_with_args(dev->of_node, "interconnects",
+ "#interconnect-cells");
+ if (count < 0)
+ return 0;
+
+ /* An interconnect path consists of two elements */
+ if (count % 2) {
+ drm_err(&sdev->sysfb.dev,
+ "invalid interconnects value\n");
+ return -EINVAL;
+ }
+ sdev->icc_count = count / 2;
+
+ sdev->icc_paths = devm_kcalloc(dev, sdev->icc_count,
+ sizeof(*sdev->icc_paths),
+ GFP_KERNEL);
+ if (!sdev->icc_paths)
+ return -ENOMEM;
+
+ for (i = 0; i < sdev->icc_count; i++) {
+ sdev->icc_paths[i] = of_icc_get_by_index(dev, i);
+ if (IS_ERR_OR_NULL(sdev->icc_paths[i])) {
+ ret = PTR_ERR(sdev->icc_paths[i]);
+ if (ret == -EPROBE_DEFER)
+ goto err;
+ drm_err(&sdev->sysfb.dev, "failed to get interconnect path %u: %d\n",
+ i, ret);
+ continue;
+ }
+
+ ret = icc_set_bw(sdev->icc_paths[i], 0, UINT_MAX);
+ if (ret) {
+ drm_err(&sdev->sysfb.dev, "failed to set interconnect bandwidth %u: %d\n",
+ i, ret);
+ continue;
+ }
+ }
+
+ return devm_add_action_or_reset(dev, simpledrm_device_detach_icc, sdev);
+
+err:
+ while (i) {
+ --i;
+ if (!IS_ERR_OR_NULL(sdev->icc_paths[i]))
+ icc_put(sdev->icc_paths[i]);
+ }
+ return ret;
+}
+#else
+static int simpledrm_device_attach_icc(struct simpledrm_device *sdev)
+{
+ return 0;
+}
+#endif
+
/*
* Modesetting
*/
@@ -633,6 +713,9 @@ static struct simpledrm_device *simpledrm_device_create(struct drm_driver *drv,
if (ret)
return ERR_PTR(ret);
ret = simpledrm_device_attach_genpd(sdev);
+ if (ret)
+ return ERR_PTR(ret);
+ ret = simpledrm_device_attach_icc(sdev);
if (ret)
return ERR_PTR(ret);
--
2.50.0
Powered by blists - more mailing lists