From: Jernej Skrabec <jernej.skrabec@gmail.com>
To: Chen-Yu Tsai <wens@kernel.org>, Samuel Holland <samuel@sholland.org>
Cc: mripard@kernel.org, maarten.lankhorst@linux.intel.com,
tzimmermann@suse.de, airlied@gmail.com, simona@ffwll.ch,
robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
bmasney+clk@redhat.com, jbrunet+clk@baylibre.com,
sboyd@kernel.org, Andre Przywara <andre.przywara@arm.com>,
dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-sunxi@lists.linux.dev, linux-kernel@vger.kernel.org,
linux-clk@vger.kernel.org
Subject: [PATCH v3 6/8] drm/sun4i: Add DE33 shared plane driver
Date: Sun, 15 Nov 2026 07:11:00 +0100 [thread overview]
Message-ID: <20261115061102.229680-7-jernej.skrabec@gmail.com> (raw)
In-Reply-To: <20261115061102.229680-1-jernej.skrabec@gmail.com>
DE33 makes its plane channels shared resources that mixers select through
routing registers in the display clock block. The existing mixer-local
plane initialization cannot represent that topology.
Add a component that owns the shared plane register space, programs the
default channel-to-mixer mapping and creates each mixer's DRM planes
from that mapping.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
drivers/gpu/drm/sun4i/Makefile | 3 +-
drivers/gpu/drm/sun4i/sun50i_planes.c | 215 ++++++++++++++++++++++++++
drivers/gpu/drm/sun4i/sun50i_planes.h | 43 ++++++
3 files changed, 260 insertions(+), 1 deletion(-)
create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.c
create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.h
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index bad7497a0d11..501e3d867918 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -16,7 +16,8 @@ sun8i-drm-hdmi-y += sun8i_hdmi_phy_clk.o
sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
sun8i_vi_layer.o sun8i_ui_scaler.o \
- sun8i_vi_scaler.o sun8i_csc.o
+ sun8i_vi_scaler.o sun8i_csc.o \
+ sun50i_planes.o
sun4i-tcon-y += sun4i_crtc.o
sun4i-tcon-y += sun4i_tcon_dclk.o
diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.c b/drivers/gpu/drm/sun4i/sun50i_planes.c
new file mode 100644
index 000000000000..22b9f104a391
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_planes.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (c) 2025 Jernej Skrabec <jernej.skrabec@gmail.com> */
+
+#include <drm/drm_device.h>
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "sun50i_planes.h"
+#include "sun8i_ui_layer.h"
+#include "sun8i_vi_layer.h"
+
+static const struct sun50i_planes_quirks sun50i_h616_planes_quirks = {
+ .def_map = {
+ {
+ .map = {0, 6, 7},
+ .num_ch = 3,
+ },
+ {
+ .map = {1, 2, 8},
+ .num_ch = 3,
+ },
+ },
+ .cfg = {
+ .de_type = SUN8I_MIXER_DE33,
+ /*
+ * TODO: All planes support scaling, but driver needs
+ * improvements to properly support it.
+ */
+ .scaler_mask = 0,
+ .scanline_yuv = 4096,
+ },
+};
+
+static const struct of_device_id sun50i_planes_of_table[] = {
+ {
+ .compatible = "allwinner,sun50i-h616-de33-planes",
+ .data = &sun50i_h616_planes_quirks
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, sun50i_planes_of_table);
+
+struct drm_plane **
+sun50i_planes_setup(struct device *dev, struct drm_device *drm,
+ unsigned int mixer)
+{
+ struct sun50i_planes *planes = dev_get_drvdata(dev);
+ const struct sun50i_planes_quirks *quirks;
+ struct drm_plane **drm_planes;
+ const struct default_map *map;
+ unsigned int i;
+
+ if (!of_match_node(sun50i_planes_of_table, dev->of_node)) {
+ dev_err(dev, "Device is not planes driver!\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!planes) {
+ dev_err(dev, "Planes driver is not loaded yet!\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (mixer > 1) {
+ dev_err(dev, "Mixer index is too high!\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ quirks = planes->quirks;
+ map = &quirks->def_map[mixer];
+
+ drm_planes = devm_kcalloc(drm->dev, map->num_ch + 1,
+ sizeof(*drm_planes), GFP_KERNEL);
+ if (!drm_planes)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < map->num_ch; i++) {
+ unsigned int phy_ch = map->map[i];
+ struct sun8i_layer *layer;
+ enum drm_plane_type type;
+
+ if ((i == 0 && map->num_ch == 1) || i == 1)
+ type = DRM_PLANE_TYPE_PRIMARY;
+ else
+ type = DRM_PLANE_TYPE_OVERLAY;
+
+ if (phy_ch < UI_PLANE_OFFSET)
+ layer = sun8i_vi_layer_init_one(drm, type, planes->regs,
+ i, phy_ch, map->num_ch,
+ &quirks->cfg);
+ else
+ layer = sun8i_ui_layer_init_one(drm, type, planes->regs,
+ i, phy_ch, map->num_ch,
+ &quirks->cfg);
+
+ if (IS_ERR(layer)) {
+ dev_err(drm->dev,
+ "Couldn't initialize DRM plane\n");
+ return ERR_CAST(layer);
+ }
+
+ drm_planes[i] = &layer->plane;
+ }
+
+ return drm_planes;
+}
+
+static void sun50i_planes_init_mapping(struct sun50i_planes *planes)
+{
+ const struct sun50i_planes_quirks *quirks = planes->quirks;
+ unsigned int i, j;
+ u32 mapping;
+
+ mapping = 0;
+ for (j = 0; j < MAX_DISP; j++)
+ for (i = 0; i < quirks->def_map[j].num_ch; i++) {
+ unsigned int ch = quirks->def_map[j].map[i];
+
+ if (ch < UI_PLANE_OFFSET)
+ mapping |= j << (ch * 2);
+ else
+ mapping |= j << ((ch - UI_PLANE_OFFSET) * 2 + 16);
+ }
+ regmap_write(planes->mapping, SUNXI_DE33_DE_CHN2CORE_MUX_REG, mapping);
+
+ for (j = 0; j < MAX_DISP; j++) {
+ mapping = 0;
+ for (i = 0; i < quirks->def_map[j].num_ch; i++) {
+ unsigned int ch = quirks->def_map[j].map[i];
+
+ if (ch >= UI_PLANE_OFFSET)
+ ch += 2;
+
+ mapping |= ch << (i * 4);
+ }
+ regmap_write(planes->mapping, SUNXI_DE33_DE_PORT02CHN_MUX_REG + j * 4, mapping);
+ }
+}
+
+static const struct regmap_config sun50i_planes_regmap_config = {
+ .name = "planes",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x17fffc,
+};
+
+static int sun50i_planes_probe(struct platform_device *pdev)
+{
+ struct platform_device *clk_pdev;
+ struct device *dev = &pdev->dev;
+ struct sun50i_planes *planes;
+ struct device_node *np;
+ void __iomem *regs;
+
+ planes = devm_kzalloc(dev, sizeof(*planes), GFP_KERNEL);
+ if (!planes)
+ return -ENOMEM;
+
+ planes->quirks = of_device_get_match_data(dev);
+ if (!planes->quirks)
+ return dev_err_probe(dev, -EINVAL, "Unable to get quirks\n");
+
+ np = of_parse_phandle(dev->of_node,
+ "allwinner,plane-mapping", 0);
+ if (!np)
+ return dev_err_probe(dev, -EINVAL, "Missing mapping phandle\n");
+
+ clk_pdev = of_find_device_by_node(np);
+ of_node_put(np);
+ if (!clk_pdev)
+ return dev_err_probe(dev, -EPROBE_DEFER, "Unable to get mapping\n");
+
+ /* Regmap is registered by display clocks driver during its probe. */
+ planes->mapping = dev_get_regmap(&clk_pdev->dev, NULL);
+ if (!planes->mapping) {
+ platform_device_put(clk_pdev);
+ return dev_err_probe(dev, -EPROBE_DEFER, "Unable to get regmap\n");
+ }
+
+ if (!device_link_add(dev, &clk_pdev->dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER)) {
+ platform_device_put(clk_pdev);
+ return dev_err_probe(dev, -EINVAL, "Failed to create link\n");
+ }
+ platform_device_put(clk_pdev);
+
+ regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ planes->regs = devm_regmap_init_mmio(dev, regs, &sun50i_planes_regmap_config);
+ if (IS_ERR(planes->regs))
+ return PTR_ERR(planes->regs);
+
+ sun50i_planes_init_mapping(planes);
+
+ dev_set_drvdata(dev, planes);
+
+ return 0;
+}
+
+struct platform_driver sun50i_planes_platform_driver = {
+ .probe = sun50i_planes_probe,
+ .driver = {
+ .name = "sun50i-planes",
+ .of_match_table = sun50i_planes_of_table,
+ },
+};
diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.h b/drivers/gpu/drm/sun4i/sun50i_planes.h
new file mode 100644
index 000000000000..7be969491f9c
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_planes.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2025 Jernej Skrabec <jernej.skrabec@gmail.com> */
+
+#ifndef _SUN50I_PLANES_H_
+#define _SUN50I_PLANES_H_
+
+#include "sun8i_mixer.h"
+
+/* mapping registers, located in clock register space */
+#define SUNXI_DE33_DE_CHN2CORE_MUX_REG 0x24
+#define SUNXI_DE33_DE_PORT02CHN_MUX_REG 0x28
+#define SUNXI_DE33_DE_PORT12CHN_MUX_REG 0x2c
+
+#define MAX_DISP 2
+#define MAX_CHANNELS 8
+#define UI_PLANE_OFFSET 6
+
+struct regmap;
+struct drm_device;
+
+struct default_map {
+ unsigned int map[MAX_CHANNELS];
+ unsigned int num_ch;
+};
+
+struct sun50i_planes_quirks {
+ struct default_map def_map[MAX_DISP];
+ struct sun8i_layer_cfg cfg;
+};
+
+struct sun50i_planes {
+ struct regmap *regs;
+ struct regmap *mapping;
+ const struct sun50i_planes_quirks *quirks;
+};
+
+struct drm_plane **
+sun50i_planes_setup(struct device *dev, struct drm_device *drm,
+ unsigned int mixer);
+
+extern struct platform_driver sun50i_planes_platform_driver;
+
+#endif /* _SUN50I_PLANES_H_ */
--
2.43.0
next prev parent reply other threads:[~2026-11-15 6:11 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-15 6:10 [PATCH v3 0/8] drm/sun4i: update DE33 support Jernej Skrabec
2026-11-15 6:10 ` [PATCH v3 1/8] clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions Jernej Skrabec
2026-11-15 6:10 ` [PATCH v3 2/8] clk: sunxi-ng: de2: Export register regmap for DE33 Jernej Skrabec
2026-11-15 6:27 ` sashiko-bot
2026-11-15 6:10 ` [PATCH v3 3/8] drm/sun4i: Add support for DE33 CSC Jernej Skrabec
2026-11-15 6:10 ` [PATCH v3 4/8] drm/sun4i: vi_layer: Limit formats for DE33 Jernej Skrabec
2026-11-15 6:10 ` [PATCH v3 5/8] dt-bindings: display: allwinner: Add DE33 planes Jernej Skrabec
2026-11-15 6:11 ` Jernej Skrabec [this message]
2026-11-15 6:11 ` [PATCH v3 7/8] dt-bindings: display: allwinner: Split H616 DE33 layer reg space Jernej Skrabec
2026-11-15 6:11 ` [PATCH v3 8/8] drm/sun4i: Switch DE33 to split plane bindings Jernej Skrabec
2026-11-15 6:26 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261115061102.229680-7-jernej.skrabec@gmail.com \
--to=jernej.skrabec@gmail.com \
--cc=airlied@gmail.com \
--cc=andre.przywara@arm.com \
--cc=bmasney+clk@redhat.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=jbrunet+clk@baylibre.com \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-sunxi@lists.linux.dev \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=robh@kernel.org \
--cc=samuel@sholland.org \
--cc=sboyd@kernel.org \
--cc=simona@ffwll.ch \
--cc=tzimmermann@suse.de \
--cc=wens@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.