* [PATCH v3 0/8] drm/sun4i: update DE33 support
@ 2026-11-15 6:10 Jernej Skrabec
2026-11-15 6:10 ` [PATCH v3 1/8] clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions Jernej Skrabec
` (9 more replies)
0 siblings, 10 replies; 16+ messages in thread
From: Jernej Skrabec @ 2026-11-15 6:10 UTC (permalink / raw)
To: Chen-Yu Tsai, Samuel Holland
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
This is second series out of tree which aims at properly introducing
support for H616 Display Engine 3.3. Previous series [1] reorganized
driver so proper DE33 support can be easily implemented.
H616 DE33 support was actually introduced a while back, but it was done
without fully understanding hardware design. Issue with existing binding
is that it considers planes as resource which is hardwired to each mixer
as it was done on older Display Engine generations (DE3 and lower). That
is not the case anymore. This series introduces new driver for planes
management, which allows doing proper plane assignments.
Note that this series intentionally breaks existing H616 DE33 mixer
binding, which was released in v6.17. Old binding can't describe shared
planes, so second mixer can't be supported with it, and it never had any
user - there is no H616 Display Engine node in upstream DT, rest of H616
display pipeline is not upstream yet and no other known DT consumer
implements it. Reasons are documented in patch 7 and driver prints error
asking to update DT if old binding is detected (patch 8). See v2
discussion for more details.
Remaining patches, which introduce all the missing bits to fully support
display pipeline on H616 SoC, will be sent once this series is merged.
WIP patches, which can be used for testing purposes, can be found at [2].
Please take a look.
Best regards,
Jernej
Changes since v2:
- rebased on v7.4-rc3+ (mainline sun4i fixes)
- patch 1: explain in commit message that DE33 has only one bus clock
- patch 2: don't register regmap with syscon, drop preset plane mapping
and reword commit message
- patch 4: don't expose YCbCr color properties on planes without YUV
formats (kept Chen-Yu's R-b)
- patch 5: collected Krzysztof's R-b
- patch 6: renamed, get mapping regmap from display clocks device and
add device link instead of using syscon, defer probe until display
clocks are bound, set drvdata only after mapping is initialized,
register driver from mixer module instead of module_platform_driver()
- patch 7: explain in commit message why old binding is incompatible and
will not be supported
- patch 8: renamed, initialize blender pipe modes for DE33, add device
link to planes device, limit DE33 display regmap to its 128 KiB region,
print error asking to update DT when old binding is detected
Link to v2: https://lore.kernel.org/linux-sunxi/20260509190015.79086-1-jernej.skrabec@siol.net/
Link to v1: https://lore.kernel.org/linux-sunxi/20251115141347.13087-1-jernej.skrabec@gmail.com/
[1] https://lore.kernel.org/linux-sunxi/20251104180942.61538-1-jernej.skrabec@gmail.com/T/#t
[2] https://github.com/jernejsk/linux-1/commits/sun4i-drm-refactor/
Jernej Skrabec (8):
clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions
clk: sunxi-ng: de2: Export register regmap for DE33
drm/sun4i: Add support for DE33 CSC
drm/sun4i: vi_layer: Limit formats for DE33
dt-bindings: display: allwinner: Add DE33 planes
drm/sun4i: Add DE33 shared plane driver
dt-bindings: display: allwinner: Split H616 DE33 layer reg space
drm/sun4i: Switch DE33 to split plane bindings
.../allwinner,sun50i-h616-de33-planes.yaml | 46 ++++
.../allwinner,sun8i-a83t-de2-mixer.yaml | 16 +-
drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 82 ++++++-
drivers/gpu/drm/sun4i/Makefile | 3 +-
drivers/gpu/drm/sun4i/sun50i_planes.c | 215 ++++++++++++++++++
drivers/gpu/drm/sun4i/sun50i_planes.h | 43 ++++
drivers/gpu/drm/sun4i/sun8i_csc.c | 71 ++++++
drivers/gpu/drm/sun4i/sun8i_csc.h | 5 +
drivers/gpu/drm/sun4i/sun8i_mixer.c | 193 +++++++++++-----
drivers/gpu/drm/sun4i/sun8i_mixer.h | 10 +-
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 72 ++++--
11 files changed, 663 insertions(+), 93 deletions(-)
create mode 100644 Documentation/devicetree/bindings/display/allwinner,sun50i-h616-de33-planes.yaml
create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.c
create mode 100644 drivers/gpu/drm/sun4i/sun50i_planes.h
base-commit: b3dfbde62cf1981c4638939c159dfd087b7a72e9
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 1/8] clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions
2026-11-15 6:10 [PATCH v3 0/8] drm/sun4i: update DE33 support Jernej Skrabec
@ 2026-11-15 6:10 ` Jernej Skrabec
2026-11-15 6:10 ` [PATCH v3 2/8] clk: sunxi-ng: de2: Export register regmap for DE33 Jernej Skrabec
` (8 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Jernej Skrabec @ 2026-11-15 6:10 UTC (permalink / raw)
To: Chen-Yu Tsai, Samuel Holland
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
Positions of clocks and resets changed when version 3.3 was introduced.
However, old positions still work, just by luck.
Note that DE 3.3 actually has only one bus clock, which is shared among
all cores, even though it is named BUS_MIXER0.
Fix Display Engine 3.3 resets and clocks according vendor driver.
Fixes: be0e9a372787 ("clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support")
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 39 +++++++++++++++++++++++++---
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
index a6cd0f988859..6ec6c0dc4c26 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -36,6 +36,13 @@ static SUNXI_CCU_GATE(wb_clk, "wb", "wb-div",
static SUNXI_CCU_GATE(rot_clk, "rot", "rot-div",
0x00, BIT(3), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_GATE(mixer0_h616_clk, "mixer0", "de",
+ 0x04, BIT(0), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_GATE(mixer1_h616_clk, "mixer1", "de",
+ 0x04, BIT(1), CLK_SET_RATE_PARENT);
+static SUNXI_CCU_GATE(wb_h616_clk, "wb", "de",
+ 0x04, BIT(4), CLK_SET_RATE_PARENT);
+
static SUNXI_CCU_M(mixer0_div_clk, "mixer0-div", "de", 0x0c, 0, 4,
CLK_SET_RATE_PARENT);
static SUNXI_CCU_M(mixer1_div_clk, "mixer1-div", "de", 0x0c, 4, 4,
@@ -54,6 +61,9 @@ static SUNXI_CCU_M(wb_div_a83_clk, "wb-div", "pll-de", 0x0c, 8, 4,
static SUNXI_CCU_M(rot_div_a83_clk, "rot-div", "pll-de", 0x0c, 0x0c, 4,
CLK_SET_RATE_PARENT);
+static SUNXI_CCU_GATE(bus_mixer0_h616_clk, "bus-mixer0", "bus-de",
+ 0x08, BIT(0), 0);
+
static struct ccu_common *sun8i_de2_ccu_clks[] = {
&mixer0_clk.common,
&mixer1_clk.common,
@@ -74,6 +84,12 @@ static struct ccu_common *sun8i_de2_ccu_clks[] = {
&mixer1_div_a83_clk.common,
&wb_div_a83_clk.common,
&rot_div_a83_clk.common,
+
+ &mixer0_h616_clk.common,
+ &mixer1_h616_clk.common,
+ &wb_h616_clk.common,
+
+ &bus_mixer0_h616_clk.common
};
static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = {
@@ -147,6 +163,17 @@ static struct clk_hw_onecell_data sun50i_a64_de2_hw_clks = {
.num = CLK_NUMBER_WITH_ROT,
};
+static struct clk_hw_onecell_data sun50i_h616_de33_hw_clks = {
+ .hws = {
+ [CLK_MIXER0] = &mixer0_h616_clk.common.hw,
+ [CLK_MIXER1] = &mixer1_h616_clk.common.hw,
+ [CLK_WB] = &wb_h616_clk.common.hw,
+
+ [CLK_BUS_MIXER0] = &bus_mixer0_h616_clk.common.hw,
+ },
+ .num = CLK_NUMBER_WITHOUT_ROT,
+};
+
static const struct ccu_reset_map sun8i_a83t_de2_resets[] = {
[RST_MIXER0] = { 0x08, BIT(0) },
/*
@@ -180,6 +207,12 @@ static const struct ccu_reset_map sun50i_h5_de2_resets[] = {
[RST_WB] = { 0x08, BIT(2) },
};
+static const struct ccu_reset_map sun50i_h616_de33_resets[] = {
+ [RST_MIXER0] = { 0x00, BIT(0) },
+ [RST_MIXER1] = { 0x00, BIT(1) },
+ [RST_WB] = { 0x00, BIT(4) },
+};
+
static const struct sunxi_ccu_desc sun8i_a83t_de2_clk_desc = {
.ccu_clks = sun8i_de2_ccu_clks,
.num_ccu_clks = ARRAY_SIZE(sun8i_de2_ccu_clks),
@@ -244,10 +277,10 @@ static const struct sunxi_ccu_desc sun50i_h616_de33_clk_desc = {
.ccu_clks = sun8i_de2_ccu_clks,
.num_ccu_clks = ARRAY_SIZE(sun8i_de2_ccu_clks),
- .hw_clks = &sun8i_h3_de2_hw_clks,
+ .hw_clks = &sun50i_h616_de33_hw_clks,
- .resets = sun50i_h5_de2_resets,
- .num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
+ .resets = sun50i_h616_de33_resets,
+ .num_resets = ARRAY_SIZE(sun50i_h616_de33_resets),
};
static int sunxi_de2_clk_probe(struct platform_device *pdev)
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 2/8] clk: sunxi-ng: de2: Export register regmap for DE33
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 ` Jernej Skrabec
2026-11-15 6:10 ` [PATCH v3 3/8] drm/sun4i: Add support for DE33 CSC Jernej Skrabec
` (7 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Jernej Skrabec @ 2026-11-15 6:10 UTC (permalink / raw)
To: Chen-Yu Tsai, Samuel Holland
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
The DE33 clock driver presets the plane mapping, which is not something
that a clock driver should do. Remove that and export the mapping
registers through a regmap instead, so the DRM driver can set them
properly.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 43 ++++++++++++++++++++++++++--
1 file changed, 40 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
index 6ec6c0dc4c26..f17570efafaa 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -9,6 +9,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/reset.h>
#include "ccu_common.h"
@@ -283,6 +284,36 @@ static const struct sunxi_ccu_desc sun50i_h616_de33_clk_desc = {
.num_resets = ARRAY_SIZE(sun50i_h616_de33_resets),
};
+/*
+ * Add a regmap for the DE33 plane driver to access plane
+ * mapping registers.
+ * Only these registers are allowed to be written, to prevent
+ * overriding clock and reset configuration.
+ */
+
+#define SUN50I_DE33_CHN2CORE_REG 0x24
+#define SUN50I_DE33_PORT12CHN_REG 0x2c
+
+static const struct regmap_range sun8i_de2_ccu_regmap_accessible_ranges[] = {
+ regmap_reg_range(SUN50I_DE33_CHN2CORE_REG, SUN50I_DE33_PORT12CHN_REG),
+};
+
+static const struct regmap_access_table sun8i_de2_ccu_regmap_accessible_table = {
+ .yes_ranges = sun8i_de2_ccu_regmap_accessible_ranges,
+ .n_yes_ranges = ARRAY_SIZE(sun8i_de2_ccu_regmap_accessible_ranges),
+};
+
+static const struct regmap_config sun8i_de2_ccu_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SUN50I_DE33_PORT12CHN_REG,
+
+ /* other devices have no business accessing other registers */
+ .wr_table = &sun8i_de2_ccu_regmap_accessible_table,
+ .rd_table = &sun8i_de2_ccu_regmap_accessible_table,
+};
+
static int sunxi_de2_clk_probe(struct platform_device *pdev)
{
struct clk *bus_clk, *mod_clk;
@@ -336,13 +367,19 @@ static int sunxi_de2_clk_probe(struct platform_device *pdev)
}
/*
- * The DE33 requires these additional (unknown) registers set
+ * The DE33 requires these additional plane mapping registers set
* during initialisation.
*/
if (of_device_is_compatible(pdev->dev.of_node,
"allwinner,sun50i-h616-de33-clk")) {
- writel(0, reg + 0x24);
- writel(0x0000a980, reg + 0x28);
+ struct regmap *regmap;
+
+ regmap = devm_regmap_init_mmio(&pdev->dev, reg,
+ &sun8i_de2_ccu_regmap_config);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ goto err_assert_reset;
+ }
}
ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 3/8] drm/sun4i: Add support for DE33 CSC
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:10 ` Jernej Skrabec
2026-11-15 6:10 ` [PATCH v3 4/8] drm/sun4i: vi_layer: Limit formats for DE33 Jernej Skrabec
` (6 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Jernej Skrabec @ 2026-11-15 6:10 UTC (permalink / raw)
To: Chen-Yu Tsai, Samuel Holland
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
DE33 has channel CSC units (for each plane separately) so pipeline can
be configured to output in desired colorspace.
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
drivers/gpu/drm/sun4i/sun8i_csc.c | 71 +++++++++++++++++++++++++++++++
drivers/gpu/drm/sun4i/sun8i_csc.h | 5 +++
2 files changed, 76 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index ce81c12f511d..70fc9b017d17 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -205,6 +205,72 @@ static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
mask, val);
}
+/* extract constant from high word and invert sign if necessary */
+static u32 sun8i_de33_ccsc_get_constant(u32 value)
+{
+ value >>= 16;
+
+ if (value & BIT(15))
+ return 0x400 - (value & 0x3ff);
+
+ return value;
+}
+
+static void sun8i_de33_convert_table(const u32 *src, u32 *dst)
+{
+ dst[0] = sun8i_de33_ccsc_get_constant(src[3]);
+ dst[1] = sun8i_de33_ccsc_get_constant(src[7]);
+ dst[2] = sun8i_de33_ccsc_get_constant(src[11]);
+ memcpy(&dst[3], src, sizeof(u32) * 12);
+ dst[6] &= 0xffff;
+ dst[10] &= 0xffff;
+ dst[14] &= 0xffff;
+}
+
+static void sun8i_de33_ccsc_setup(struct regmap *map, int layer,
+ enum sun8i_csc_mode mode,
+ enum drm_color_encoding encoding,
+ enum drm_color_range range)
+{
+ u32 addr, val, base, csc[15];
+ const u32 *table;
+ int i;
+
+ table = yuv2rgb_de3[range][encoding];
+ base = DE33_CCSC_BASE + layer * DE33_CH_SIZE;
+
+ switch (mode) {
+ case SUN8I_CSC_MODE_OFF:
+ val = 0;
+ break;
+ case SUN8I_CSC_MODE_YUV2RGB:
+ val = SUN8I_CSC_CTRL_EN;
+ sun8i_de33_convert_table(table, csc);
+ regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+ break;
+ case SUN8I_CSC_MODE_YVU2RGB:
+ val = SUN8I_CSC_CTRL_EN;
+ sun8i_de33_convert_table(table, csc);
+ for (i = 0; i < 15; i++) {
+ addr = SUN50I_CSC_COEFF(base, i);
+ if (i > 3) {
+ if (((i - 3) & 3) == 1)
+ addr = SUN50I_CSC_COEFF(base, i + 1);
+ else if (((i - 3) & 3) == 2)
+ addr = SUN50I_CSC_COEFF(base, i - 1);
+ }
+ regmap_write(map, addr, csc[i]);
+ }
+ break;
+ default:
+ val = 0;
+ DRM_WARN("Wrong CSC mode specified.\n");
+ return;
+ }
+
+ regmap_write(map, SUN8I_CSC_CTRL(base), val);
+}
+
static u32 sun8i_csc_get_mode(struct drm_plane_state *state)
{
const struct drm_format_info *format;
@@ -238,6 +304,11 @@ void sun8i_csc_config(struct sun8i_layer *layer,
mode, state->color_encoding,
state->color_range);
return;
+ } else if (layer->cfg->de_type == SUN8I_MIXER_DE33) {
+ sun8i_de33_ccsc_setup(layer->regs, layer->channel,
+ mode, state->color_encoding,
+ state->color_range);
+ return;
}
base = ccsc_base[layer->cfg->ccsc][layer->channel];
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h b/drivers/gpu/drm/sun4i/sun8i_csc.h
index 2a4b79599610..d2ba5f8611aa 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
@@ -18,9 +18,14 @@ struct sun8i_layer;
#define CCSC10_OFFSET 0xA0000
#define CCSC11_OFFSET 0xF0000
+#define DE33_CCSC_BASE 0x800
+
#define SUN8I_CSC_CTRL(base) ((base) + 0x0)
#define SUN8I_CSC_COEFF(base, i) ((base) + 0x10 + 4 * (i))
+#define SUN50I_CSC_COEFF(base, i) ((base) + 0x04 + 4 * (i))
+#define SUN50I_CSC_ALPHA(base) ((base) + 0x40)
+
#define SUN8I_CSC_CTRL_EN BIT(0)
void sun8i_csc_config(struct sun8i_layer *layer,
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 4/8] drm/sun4i: vi_layer: Limit formats for DE33
2026-11-15 6:10 [PATCH v3 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (2 preceding siblings ...)
2026-11-15 6:10 ` [PATCH v3 3/8] drm/sun4i: Add support for DE33 CSC Jernej Skrabec
@ 2026-11-15 6:10 ` Jernej Skrabec
2026-11-15 14:04 ` Chen-Yu Tsai
2026-11-15 6:10 ` [PATCH v3 5/8] dt-bindings: display: allwinner: Add DE33 planes Jernej Skrabec
` (5 subsequent siblings)
9 siblings, 1 reply; 16+ messages in thread
From: Jernej Skrabec @ 2026-11-15 6:10 UTC (permalink / raw)
To: Chen-Yu Tsai, Samuel Holland
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
YUV formats need scaler support due to chroma upscaling, but that's not
yet supported in the driver. Remove them from supported list until
DE33 scaler is properly supported.
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 72 ++++++++++++++++++++------
1 file changed, 56 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 6b19fafd50ad..09d94f7f9977 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -380,6 +380,33 @@ static const u32 sun8i_vi_layer_de3_formats[] = {
DRM_FORMAT_YVU422,
};
+static const u32 sun8i_vi_layer_de3_no_yuv_formats[] = {
+ DRM_FORMAT_ABGR1555,
+ DRM_FORMAT_ABGR2101010,
+ DRM_FORMAT_ABGR4444,
+ DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_ARGB2101010,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_BGR565,
+ DRM_FORMAT_BGR888,
+ DRM_FORMAT_BGRA1010102,
+ DRM_FORMAT_BGRA5551,
+ DRM_FORMAT_BGRA4444,
+ DRM_FORMAT_BGRA8888,
+ DRM_FORMAT_BGRX8888,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_RGBA1010102,
+ DRM_FORMAT_RGBA4444,
+ DRM_FORMAT_RGBA5551,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_RGBX8888,
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_XRGB8888,
+};
+
static const uint64_t sun8i_layer_modifiers[] = {
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_MOD_INVALID
@@ -395,6 +422,7 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
u32 supported_encodings, supported_ranges;
unsigned int format_count;
struct sun8i_layer *layer;
+ bool yuv_support = true;
const u32 *formats;
int ret;
@@ -410,8 +438,18 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
layer->cfg = cfg;
if (layer->cfg->de_type >= SUN8I_MIXER_DE3) {
- formats = sun8i_vi_layer_de3_formats;
- format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
+ /*
+ * TODO: DE33 drivers doesn't support scaling yet, which is a
+ * requirement for YUV support.
+ */
+ yuv_support = layer->cfg->scaler_mask & BIT(phy_index);
+ if (yuv_support) {
+ formats = sun8i_vi_layer_de3_formats;
+ format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
+ } else {
+ formats = sun8i_vi_layer_de3_no_yuv_formats;
+ format_count = ARRAY_SIZE(sun8i_vi_layer_de3_no_yuv_formats);
+ }
} else {
formats = sun8i_vi_layer_formats;
format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
@@ -443,22 +481,24 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
return ERR_PTR(ret);
}
- supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
- BIT(DRM_COLOR_YCBCR_BT709);
- if (layer->cfg->de_type >= SUN8I_MIXER_DE3)
- supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020);
+ if (yuv_support) {
+ supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
+ BIT(DRM_COLOR_YCBCR_BT709);
+ if (layer->cfg->de_type >= SUN8I_MIXER_DE3)
+ supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020);
- supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
- BIT(DRM_COLOR_YCBCR_FULL_RANGE);
+ supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
+ BIT(DRM_COLOR_YCBCR_FULL_RANGE);
- ret = drm_plane_create_color_properties(&layer->plane,
- supported_encodings,
- supported_ranges,
- DRM_COLOR_YCBCR_BT709,
- DRM_COLOR_YCBCR_LIMITED_RANGE);
- if (ret) {
- dev_err(drm->dev, "Couldn't add encoding and range properties!\n");
- return ERR_PTR(ret);
+ ret = drm_plane_create_color_properties(&layer->plane,
+ supported_encodings,
+ supported_ranges,
+ DRM_COLOR_YCBCR_BT709,
+ DRM_COLOR_YCBCR_LIMITED_RANGE);
+ if (ret) {
+ dev_err(drm->dev, "Couldn't add encoding and range properties!\n");
+ return ERR_PTR(ret);
+ }
}
drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 5/8] dt-bindings: display: allwinner: Add DE33 planes
2026-11-15 6:10 [PATCH v3 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (3 preceding siblings ...)
2026-11-15 6:10 ` [PATCH v3 4/8] drm/sun4i: vi_layer: Limit formats for DE33 Jernej Skrabec
@ 2026-11-15 6:10 ` Jernej Skrabec
2026-11-15 6:11 ` [PATCH v3 6/8] drm/sun4i: Add DE33 shared plane driver Jernej Skrabec
` (4 subsequent siblings)
9 siblings, 0 replies; 16+ messages in thread
From: Jernej Skrabec @ 2026-11-15 6:10 UTC (permalink / raw)
To: Chen-Yu Tsai, Samuel Holland
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk, Krzysztof Kozlowski
Allwinner Display Engine 3.3 contains planes, which are shared resources
between all mixers present in SoC. They can be assigned to specific
mixer by using registers which reside in display clocks MMIO.
Add a binding for them.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
.../allwinner,sun50i-h616-de33-planes.yaml | 46 +++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/allwinner,sun50i-h616-de33-planes.yaml
diff --git a/Documentation/devicetree/bindings/display/allwinner,sun50i-h616-de33-planes.yaml b/Documentation/devicetree/bindings/display/allwinner,sun50i-h616-de33-planes.yaml
new file mode 100644
index 000000000000..0a07cb8a5f79
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/allwinner,sun50i-h616-de33-planes.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/allwinner,sun50i-h616-de33-planes.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner H616 Display Engine 3.3 planes
+
+maintainers:
+ - Jernej Skrabec <jernej.skrabec@gmail.com>
+
+description:
+ Display Engine 3.3 planes are independent of mixers, contrary to
+ previous generations of Display Engine. Planes can be assigned to
+ mixers independently and even dynamically during runtime.
+
+properties:
+ compatible:
+ enum:
+ - allwinner,sun50i-h616-de33-planes
+
+ reg:
+ maxItems: 1
+
+ allwinner,plane-mapping:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ Phandle of the device responsible for assigning (mapping) planes
+ between mixers.
+
+required:
+ - compatible
+ - reg
+ - allwinner,plane-mapping
+
+additionalProperties: false
+
+examples:
+ - |
+ planes: planes@100000 {
+ compatible = "allwinner,sun50i-h616-de33-planes";
+ reg = <0x100000 0x180000>;
+ allwinner,plane-mapping = <&display_clocks>;
+ };
+
+...
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 6/8] drm/sun4i: Add DE33 shared plane driver
2026-11-15 6:10 [PATCH v3 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (4 preceding siblings ...)
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
2026-11-15 14:01 ` Chen-Yu Tsai
2026-11-15 6:11 ` [PATCH v3 7/8] dt-bindings: display: allwinner: Split H616 DE33 layer reg space Jernej Skrabec
` (3 subsequent siblings)
9 siblings, 1 reply; 16+ messages in thread
From: Jernej Skrabec @ 2026-11-15 6:11 UTC (permalink / raw)
To: Chen-Yu Tsai, Samuel Holland
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
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
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 7/8] dt-bindings: display: allwinner: Split H616 DE33 layer reg space
2026-11-15 6:10 [PATCH v3 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (5 preceding siblings ...)
2026-11-15 6:11 ` [PATCH v3 6/8] drm/sun4i: Add DE33 shared plane driver Jernej Skrabec
@ 2026-11-15 6:11 ` Jernej Skrabec
2026-11-15 14:06 ` Chen-Yu Tsai
2026-11-15 6:11 ` [PATCH v3 8/8] drm/sun4i: Switch DE33 to split plane bindings Jernej Skrabec
` (2 subsequent siblings)
9 siblings, 1 reply; 16+ messages in thread
From: Jernej Skrabec @ 2026-11-15 6:11 UTC (permalink / raw)
To: Chen-Yu Tsai, Samuel Holland
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
As it turns out, current H616 DE33 binding was written based on
incomplete understanding of DE33 design. Namely, planes are shared
resource and not tied to specific mixer, which was the case for previous
generations of Display Engine (DE3 and earlier).
This means that current DE33 binding doesn't properly reflect HW and
using it would mean that second mixer (used for second display output)
can't be supported.
Remove layer register space, which will be represented with additional
node, and replace it with phandle, which will point to that new, shared
node. That way, all mixers can share same layers.
This change is intentionally not backward compatible and the old binding
will not be supported by the driver, for the following reasons:
- It can't describe the hardware. Plane register space is shared
between all mixers, but the old binding puts it in the mixer node, so
only one mixer can ever claim it. The second mixer can't be supported
with the old binding at all. It also has no way to reference plane to
mixer mapping registers, which live in display clocks register space.
- Supporting it would mean keeping a second, mixer-local plane
management path in the driver, with hardcoded plane mapping, which
doesn't match the hardware and which can't be tested, since nothing
uses it.
- It was never used. Upstream H616 DT has no Display Engine nodes and
the rest of H616 display pipeline (TCON, HDMI, PHY) is not supported
upstream yet, so the old binding never produced a working display.
Vendor BSP kernels use a completely different DT structure and no
other known DT consumer (U-Boot, *BSD, Zephyr, TF-A, ...) implements
H616 display support. Only out of tree WIP patches used it and those
are updated together with the kernel.
The driver will print an error, asking to update the device tree, when
the old binding is detected.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
.../display/allwinner,sun8i-a83t-de2-mixer.yaml | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
index cbd18fd83e52..064e4ca7e419 100644
--- a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
+++ b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
@@ -46,6 +46,10 @@ properties:
resets:
maxItems: 1
+ allwinner,planes:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description: Phandle of Display Engine 3.3 planes node
+
ports:
$ref: /schemas/graph.yaml#/properties/ports
@@ -74,22 +78,22 @@ allOf:
properties:
reg:
description: |
- Registers for controlling individual layers of the display
- engine (layers), global control (top), and display blending
- control (display). Names are from Allwinner BSP kernel.
- maxItems: 3
+ Registers for display blending control (display) and global
+ control (top). Names are from Allwinner BSP kernel.
+ maxItems: 2
reg-names:
items:
- - const: layers
- - const: top
- const: display
+ - const: top
required:
- reg-names
+ - allwinner,planes
else:
properties:
reg:
maxItems: 1
+ allwinner,planes: false
required:
- compatible
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v3 8/8] drm/sun4i: Switch DE33 to split plane bindings
2026-11-15 6:10 [PATCH v3 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (6 preceding siblings ...)
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 ` Jernej Skrabec
2026-11-15 14:26 ` Chen-Yu Tsai
2026-11-15 12:09 ` (subset) [PATCH v3 0/8] drm/sun4i: update DE33 support Chen-Yu Tsai
2026-11-15 14:42 ` Chen-Yu Tsai
9 siblings, 1 reply; 16+ messages in thread
From: Jernej Skrabec @ 2026-11-15 6:11 UTC (permalink / raw)
To: Chen-Yu Tsai, Samuel Holland
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
The shared plane driver and split register resources are now in place.
Switch DE33 mixer discovery to the new bindings and remove the legacy
per-mixer plane setup. Mixer register space now covers only display
blending control, so limit its regmap accordingly.
The old DE33 binding is not supported anymore, since it can't describe
shared planes and was never used by any device tree. If it's detected,
print an error asking the user to update the device tree, instead of
failing silently or misusing the plane register space as blender
registers.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 195 ++++++++++++++++++++--------
drivers/gpu/drm/sun4i/sun8i_mixer.h | 10 +-
2 files changed, 140 insertions(+), 65 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index dbde80b32080..0970be6aa035 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -13,6 +13,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
@@ -25,6 +26,7 @@
#include <drm/drm_probe_helper.h>
#include "sun4i_drv.h"
+#include "sun50i_planes.h"
#include "sun8i_mixer.h"
#include "sun8i_ui_layer.h"
#include "sun8i_vi_layer.h"
@@ -257,7 +259,6 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
{
struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
u32 bld_base = sun8i_blender_base(mixer);
- struct regmap *bld_regs = sun8i_blender_regmap(mixer);
struct drm_plane_state *plane_state;
struct drm_plane *plane;
u32 route = 0, pipe_en = 0;
@@ -294,16 +295,16 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
route |= layer->index << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
- regmap_write(bld_regs,
+ regmap_write(engine->regs,
SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
SUN8I_MIXER_COORD(x, y));
- regmap_write(bld_regs,
+ regmap_write(engine->regs,
SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
SUN8I_MIXER_SIZE(w, h));
}
- regmap_write(bld_regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
- regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
+ regmap_write(engine->regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
+ regmap_write(engine->regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
if (mixer->cfg->de_type != SUN8I_MIXER_DE33)
@@ -318,7 +319,6 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
int plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
enum drm_plane_type type;
- unsigned int phy_index;
int i;
planes = devm_kzalloc_objs(drm->dev, *planes, plane_cnt + 1);
@@ -333,12 +333,8 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
else
type = DRM_PLANE_TYPE_OVERLAY;
- phy_index = i;
- if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
- phy_index = mixer->cfg->map[i];
-
layer = sun8i_vi_layer_init_one(drm, type, mixer->engine.regs,
- i, phy_index, plane_cnt,
+ i, i, plane_cnt,
&mixer->cfg->lay_cfg);
if (IS_ERR(layer)) {
dev_err(drm->dev,
@@ -358,12 +354,8 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
else
type = DRM_PLANE_TYPE_OVERLAY;
- phy_index = index;
- if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
- phy_index = mixer->cfg->map[index];
-
layer = sun8i_ui_layer_init_one(drm, type, mixer->engine.regs,
- index, phy_index, plane_cnt,
+ index, index, plane_cnt,
&mixer->cfg->lay_cfg);
if (IS_ERR(layer)) {
dev_err(drm->dev, "Couldn't initialize %s plane\n",
@@ -377,16 +369,34 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
return planes;
}
+static struct drm_plane **sun50i_layers_init(struct drm_device *drm,
+ struct sunxi_engine *engine)
+{
+ struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+ unsigned int base = sun8i_blender_base(mixer);
+ struct drm_plane **planes;
+ int i;
+
+ planes = sun50i_planes_setup(mixer->planes_dev, drm, engine->id);
+ if (IS_ERR(planes))
+ return planes;
+
+ for (i = 0; planes[i]; i++)
+ regmap_write(engine->regs,
+ SUN8I_MIXER_BLEND_MODE(base, i),
+ SUN8I_MIXER_BLEND_MODE_DEF);
+
+ return planes;
+}
+
static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
const struct drm_display_mode *mode)
{
struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
- struct regmap *bld_regs;
u32 bld_base, size, val;
bool interlaced;
bld_base = sun8i_blender_base(mixer);
- bld_regs = sun8i_blender_regmap(mixer);
interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
size = SUN8I_MIXER_SIZE(mode->hdisplay, mode->vdisplay);
@@ -398,14 +408,14 @@ static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
else
regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE, size);
- regmap_write(bld_regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
+ regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
if (interlaced)
val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
else
val = 0;
- regmap_update_bits(bld_regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
+ regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
@@ -418,6 +428,12 @@ static const struct sunxi_engine_ops sun8i_engine_ops = {
.mode_set = sun8i_mixer_mode_set,
};
+static const struct sunxi_engine_ops sun50i_engine_ops = {
+ .commit = sun8i_mixer_commit,
+ .layers_init = sun50i_layers_init,
+ .mode_set = sun8i_mixer_mode_set,
+};
+
static const struct regmap_config sun8i_mixer_regmap_config = {
.name = "layers",
.reg_bits = 32,
@@ -434,12 +450,12 @@ static const struct regmap_config sun8i_top_regmap_config = {
.max_register = 0x3c,
};
-static const struct regmap_config sun8i_disp_regmap_config = {
+static const struct regmap_config sun50i_mixer33_regmap_config = {
.name = "display",
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
- .max_register = 0x20000,
+ .max_register = 0x1fffc,
};
static int sun8i_mixer_of_get_id(struct device_node *node)
@@ -464,17 +480,14 @@ static int sun8i_mixer_of_get_id(struct device_node *node)
static void sun8i_mixer_init(struct sun8i_mixer *mixer)
{
- struct regmap *top_regs, *disp_regs;
unsigned int base = sun8i_blender_base(mixer);
+ struct regmap *top_regs;
int plane_cnt, i;
- if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
+ if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
top_regs = mixer->top_regs;
- disp_regs = mixer->disp_regs;
- } else {
+ else
top_regs = mixer->engine.regs;
- disp_regs = mixer->engine.regs;
- }
/* Enable the mixer */
regmap_write(top_regs, SUN8I_MIXER_GLOBAL_CTL,
@@ -484,25 +497,29 @@ static void sun8i_mixer_init(struct sun8i_mixer *mixer)
regmap_write(top_regs, SUN50I_MIXER_GLOBAL_CLK, 1);
/* Set background color to black */
- regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
SUN8I_MIXER_BLEND_COLOR_BLACK);
/*
* Set fill color of bottom plane to black. Generally not needed
* except when VI plane is at bottom (zpos = 0) and enabled.
*/
- regmap_write(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
- regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
+ regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
SUN8I_MIXER_BLEND_COLOR_BLACK);
+ /*
+ * plane_cnt is 0 for DE33. Blend mode will be initialized in
+ * layer init function, where the number of planes is known.
+ */
plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
for (i = 0; i < plane_cnt; i++)
- regmap_write(disp_regs,
+ regmap_write(mixer->engine.regs,
SUN8I_MIXER_BLEND_MODE(base, i),
SUN8I_MIXER_BLEND_MODE_DEF);
- regmap_update_bits(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+ regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
}
@@ -533,7 +550,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
if (!mixer)
return -ENOMEM;
dev_set_drvdata(dev, mixer);
- mixer->engine.ops = &sun8i_engine_ops;
mixer->engine.node = dev->of_node;
/*
@@ -566,12 +582,34 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
if (!mixer->cfg)
return -EINVAL;
+ if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
+ /*
+ * The original DE33 binding described planes as part of
+ * the mixer, which can't work with more than one mixer.
+ * It was never used by any device tree, so it's not
+ * supported.
+ */
+ if (of_property_match_string(dev->of_node, "reg-names",
+ "layers") >= 0 ||
+ !of_property_present(dev->of_node, "allwinner,planes"))
+ return dev_err_probe(dev, -EINVAL,
+ "Unsupported DE33 mixer binding, please update the device tree\n");
+
+ mixer->engine.ops = &sun50i_engine_ops;
+ } else {
+ mixer->engine.ops = &sun8i_engine_ops;
+ }
+
regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs))
return PTR_ERR(regs);
- mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
- &sun8i_mixer_regmap_config);
+ if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
+ mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
+ &sun50i_mixer33_regmap_config);
+ else
+ mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
+ &sun8i_mixer_regmap_config);
if (IS_ERR(mixer->engine.regs)) {
dev_err(dev, "Couldn't create the mixer regmap\n");
return PTR_ERR(mixer->engine.regs);
@@ -588,17 +626,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
dev_err(dev, "Couldn't create the top regmap\n");
return PTR_ERR(mixer->top_regs);
}
-
- regs = devm_platform_ioremap_resource_byname(pdev, "display");
- if (IS_ERR(regs))
- return PTR_ERR(regs);
-
- mixer->disp_regs = devm_regmap_init_mmio(dev, regs,
- &sun8i_disp_regmap_config);
- if (IS_ERR(mixer->disp_regs)) {
- dev_err(dev, "Couldn't create the disp regmap\n");
- return PTR_ERR(mixer->disp_regs);
- }
}
mixer->reset = devm_reset_control_get(dev, NULL);
@@ -638,6 +665,40 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
clk_prepare_enable(mixer->mod_clk);
+ if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
+ struct platform_device *pdev;
+ struct device_link *link;
+ struct device_node *np;
+ void *data;
+
+ np = of_parse_phandle(dev->of_node, "allwinner,planes", 0);
+ if (!np) {
+ ret = -ENODEV;
+ goto err_disable_mod_clk;
+ }
+
+ pdev = of_find_device_by_node(np);
+ of_node_put(np);
+ if (!pdev) {
+ ret = -EPROBE_DEFER;
+ goto err_disable_mod_clk;
+ }
+ mixer->planes_dev = &pdev->dev;
+
+ data = platform_get_drvdata(pdev);
+ if (!data) {
+ ret = -EPROBE_DEFER;
+ goto err_put_device;
+ }
+
+ link = device_link_add(dev, &pdev->dev,
+ DL_FLAG_AUTOREMOVE_CONSUMER);
+ if (!link) {
+ ret = -EINVAL;
+ goto err_put_device;
+ }
+ }
+
list_add_tail(&mixer->engine.list, &drv->engine_list);
/* Reset registers and disable unused sub-engines */
@@ -672,6 +733,10 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
return 0;
+err_put_device:
+ put_device(mixer->planes_dev);
+err_disable_mod_clk:
+ clk_disable_unprepare(mixer->mod_clk);
err_disable_bus_clk:
clk_disable_unprepare(mixer->bus_clk);
err_assert_reset:
@@ -686,6 +751,9 @@ static void sun8i_mixer_unbind(struct device *dev, struct device *master,
list_del(&mixer->engine.list);
+ if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
+ put_device(mixer->planes_dev);
+
clk_disable_unprepare(mixer->mod_clk);
clk_disable_unprepare(mixer->bus_clk);
reset_control_assert(mixer->reset);
@@ -867,16 +935,8 @@ static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
};
static const struct sun8i_mixer_cfg sun50i_h616_mixer0_cfg = {
- .lay_cfg = {
- .de_type = SUN8I_MIXER_DE33,
- .scaler_mask = 0xf,
- .scanline_yuv = 4096,
- },
.de_type = SUN8I_MIXER_DE33,
.mod_rate = 600000000,
- .ui_num = 3,
- .vi_num = 1,
- .map = {0, 6, 7, 8},
};
static const struct of_device_id sun8i_mixer_of_table[] = {
@@ -940,7 +1000,30 @@ static struct platform_driver sun8i_mixer_platform_driver = {
.of_match_table = sun8i_mixer_of_table,
},
};
-module_platform_driver(sun8i_mixer_platform_driver);
+
+static int __init sun8i_mixer_module_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&sun50i_planes_platform_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&sun8i_mixer_platform_driver);
+ if (ret)
+ platform_driver_unregister(&sun50i_planes_platform_driver);
+
+ return ret;
+}
+
+static void __exit sun8i_mixer_module_exit(void)
+{
+ platform_driver_unregister(&sun8i_mixer_platform_driver);
+ platform_driver_unregister(&sun50i_planes_platform_driver);
+}
+
+module_init(sun8i_mixer_module_init);
+module_exit(sun8i_mixer_module_exit);
MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
MODULE_DESCRIPTION("Allwinner DE2 Mixer driver");
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index e2f83301aae8..7abc88c898d9 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -202,7 +202,6 @@ struct sun8i_mixer_cfg {
int ui_num;
unsigned int de_type;
unsigned long mod_rate;
- unsigned int map[6];
};
struct sun8i_mixer {
@@ -216,7 +215,7 @@ struct sun8i_mixer {
struct clk *mod_clk;
struct regmap *top_regs;
- struct regmap *disp_regs;
+ struct device *planes_dev;
};
enum {
@@ -252,13 +251,6 @@ sun8i_blender_base(struct sun8i_mixer *mixer)
return mixer->cfg->de_type == SUN8I_MIXER_DE3 ? DE3_BLD_BASE : DE2_BLD_BASE;
}
-static inline struct regmap *
-sun8i_blender_regmap(struct sun8i_mixer *mixer)
-{
- return mixer->cfg->de_type == SUN8I_MIXER_DE33 ?
- mixer->disp_regs : mixer->engine.regs;
-}
-
static inline u32
sun8i_channel_base(struct sun8i_layer *layer)
{
--
2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: (subset) [PATCH v3 0/8] drm/sun4i: update DE33 support
2026-11-15 6:10 [PATCH v3 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (7 preceding siblings ...)
2026-11-15 6:11 ` [PATCH v3 8/8] drm/sun4i: Switch DE33 to split plane bindings Jernej Skrabec
@ 2026-11-15 12:09 ` Chen-Yu Tsai
2026-11-15 14:42 ` Chen-Yu Tsai
9 siblings, 0 replies; 16+ messages in thread
From: Chen-Yu Tsai @ 2026-11-15 12:09 UTC (permalink / raw)
To: Samuel Holland, Jernej Skrabec
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
On Sun, 15 Nov 2026 07:10:54 +0100, Jernej Skrabec wrote:
> This is second series out of tree which aims at properly introducing
> support for H616 Display Engine 3.3. Previous series [1] reorganized
> driver so proper DE33 support can be easily implemented.
>
> H616 DE33 support was actually introduced a while back, but it was done
> without fully understanding hardware design. Issue with existing binding
> is that it considers planes as resource which is hardwired to each mixer
> as it was done on older Display Engine generations (DE3 and lower). That
> is not the case anymore. This series introduces new driver for planes
> management, which allows doing proper plane assignments.
>
> [...]
Applied to sunxi/clk-for-7.5 in sunxi, thanks!
[1/8] clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions
https://git.kernel.org/sunxi/linux/c/c6d21e8bb03e
[2/8] clk: sunxi-ng: de2: Export register regmap for DE33
https://git.kernel.org/sunxi/linux/c/63a29fbb4ecd
Best regards,
--
Chen-Yu Tsai <wens@kernel.org>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 6/8] drm/sun4i: Add DE33 shared plane driver
2026-11-15 6:11 ` [PATCH v3 6/8] drm/sun4i: Add DE33 shared plane driver Jernej Skrabec
@ 2026-11-15 14:01 ` Chen-Yu Tsai
0 siblings, 0 replies; 16+ messages in thread
From: Chen-Yu Tsai @ 2026-11-15 14:01 UTC (permalink / raw)
To: Jernej Skrabec
Cc: Samuel Holland, mripard, maarten.lankhorst, tzimmermann, airlied,
simona, robh, krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
On Sun, Nov 15, 2026 at 2:11 PM Jernej Skrabec <jernej.skrabec@gmail.com> wrote:
>
> 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.
Just some nits.
This should mention that this driver only gets hooked up in the last
patch of the series. This patch alone doesn't register the driver.
> 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> */
Need to update the year.
> +
> +#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>
This is unused. Leftover from an older version?
> +#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);
return dev_err_probe();
> + }
> +
> + if (!planes) {
> + dev_err(dev, "Planes driver is not loaded yet!\n");
> + return ERR_PTR(-EINVAL);
return dev_err_probe();
> + }
> +
> + if (mixer > 1) {
Use ">= MAX_DISP" or "!(mixer < MAX_DISP)" here?
> + dev_err(dev, "Mixer index is too high!\n");
> + return ERR_PTR(-EINVAL);
return dev_err_probe();
> + }
> +
> + 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);
return dev_err_probe();
Otherwise,
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
> + }
> +
> + 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> */
2026 now (and almost over ...)
> +
> +#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
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 4/8] drm/sun4i: vi_layer: Limit formats for DE33
2026-11-15 6:10 ` [PATCH v3 4/8] drm/sun4i: vi_layer: Limit formats for DE33 Jernej Skrabec
@ 2026-11-15 14:04 ` Chen-Yu Tsai
0 siblings, 0 replies; 16+ messages in thread
From: Chen-Yu Tsai @ 2026-11-15 14:04 UTC (permalink / raw)
To: Jernej Skrabec
Cc: Samuel Holland, mripard, maarten.lankhorst, tzimmermann, airlied,
simona, robh, krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
On Sun, Nov 15, 2026 at 2:11 PM Jernej Skrabec <jernej.skrabec@gmail.com> wrote:
>
> YUV formats need scaler support due to chroma upscaling, but that's not
> yet supported in the driver. Remove them from supported list until
> DE33 scaler is properly supported.
Somewhat related, but I think you also need a patch to block fractional
coordinates? IIRC that also uses the scaler.
This was flagged by my review agent, but I vaguely remember it being the
case from working on the DRM DMA helpers.
ChenYu
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 7/8] dt-bindings: display: allwinner: Split H616 DE33 layer reg space
2026-11-15 6:11 ` [PATCH v3 7/8] dt-bindings: display: allwinner: Split H616 DE33 layer reg space Jernej Skrabec
@ 2026-11-15 14:06 ` Chen-Yu Tsai
0 siblings, 0 replies; 16+ messages in thread
From: Chen-Yu Tsai @ 2026-11-15 14:06 UTC (permalink / raw)
To: Jernej Skrabec
Cc: Samuel Holland, mripard, maarten.lankhorst, tzimmermann, airlied,
simona, robh, krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
On Sun, Nov 15, 2026 at 2:11 PM Jernej Skrabec <jernej.skrabec@gmail.com> wrote:
>
> As it turns out, current H616 DE33 binding was written based on
> incomplete understanding of DE33 design. Namely, planes are shared
> resource and not tied to specific mixer, which was the case for previous
> generations of Display Engine (DE3 and earlier).
>
> This means that current DE33 binding doesn't properly reflect HW and
> using it would mean that second mixer (used for second display output)
> can't be supported.
>
> Remove layer register space, which will be represented with additional
> node, and replace it with phandle, which will point to that new, shared
> node. That way, all mixers can share same layers.
>
> This change is intentionally not backward compatible and the old binding
> will not be supported by the driver, for the following reasons:
>
> - It can't describe the hardware. Plane register space is shared
> between all mixers, but the old binding puts it in the mixer node, so
> only one mixer can ever claim it. The second mixer can't be supported
> with the old binding at all. It also has no way to reference plane to
> mixer mapping registers, which live in display clocks register space.
>
> - Supporting it would mean keeping a second, mixer-local plane
> management path in the driver, with hardcoded plane mapping, which
> doesn't match the hardware and which can't be tested, since nothing
> uses it.
>
> - It was never used. Upstream H616 DT has no Display Engine nodes and
> the rest of H616 display pipeline (TCON, HDMI, PHY) is not supported
> upstream yet, so the old binding never produced a working display.
> Vendor BSP kernels use a completely different DT structure and no
> other known DT consumer (U-Boot, *BSD, Zephyr, TF-A, ...) implements
> H616 display support. Only out of tree WIP patches used it and those
> are updated together with the kernel.
>
> The driver will print an error, asking to update the device tree, when
> the old binding is detected.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
> ---
> .../display/allwinner,sun8i-a83t-de2-mixer.yaml | 16 ++++++++++------
> 1 file changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
> index cbd18fd83e52..064e4ca7e419 100644
> --- a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
> +++ b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
> @@ -46,6 +46,10 @@ properties:
> resets:
> maxItems: 1
>
> + allwinner,planes:
> + $ref: /schemas/types.yaml#/definitions/phandle
> + description: Phandle of Display Engine 3.3 planes node
> +
> ports:
> $ref: /schemas/graph.yaml#/properties/ports
>
> @@ -74,22 +78,22 @@ allOf:
> properties:
> reg:
> description: |
> - Registers for controlling individual layers of the display
> - engine (layers), global control (top), and display blending
> - control (display). Names are from Allwinner BSP kernel.
> - maxItems: 3
> + Registers for display blending control (display) and global
> + control (top). Names are from Allwinner BSP kernel.
> + maxItems: 2
> reg-names:
> items:
> - - const: layers
> - - const: top
> - const: display
> + - const: top
> required:
> - reg-names
> + - allwinner,planes
>
> else:
> properties:
> reg:
> maxItems: 1
> + allwinner,planes: false
>
> required:
> - compatible
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 8/8] drm/sun4i: Switch DE33 to split plane bindings
2026-11-15 6:11 ` [PATCH v3 8/8] drm/sun4i: Switch DE33 to split plane bindings Jernej Skrabec
@ 2026-11-15 14:26 ` Chen-Yu Tsai
2026-11-15 14:37 ` Chen-Yu Tsai
0 siblings, 1 reply; 16+ messages in thread
From: Chen-Yu Tsai @ 2026-11-15 14:26 UTC (permalink / raw)
To: Jernej Skrabec
Cc: Samuel Holland, mripard, maarten.lankhorst, tzimmermann, airlied,
simona, robh, krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
On Sun, Nov 15, 2026 at 2:11 PM Jernej Skrabec <jernej.skrabec@gmail.com> wrote:
>
> The shared plane driver and split register resources are now in place.
> Switch DE33 mixer discovery to the new bindings and remove the legacy
> per-mixer plane setup. Mixer register space now covers only display
> blending control, so limit its regmap accordingly.
>
> The old DE33 binding is not supported anymore, since it can't describe
> shared planes and was never used by any device tree. If it's detected,
> print an error asking the user to update the device tree, instead of
> failing silently or misusing the plane register space as blender
> registers.
>
> Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
> ---
> drivers/gpu/drm/sun4i/sun8i_mixer.c | 195 ++++++++++++++++++++--------
> drivers/gpu/drm/sun4i/sun8i_mixer.h | 10 +-
> 2 files changed, 140 insertions(+), 65 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> index dbde80b32080..0970be6aa035 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> @@ -13,6 +13,7 @@
> #include <linux/of.h>
> #include <linux/of_device.h>
> #include <linux/of_graph.h>
> +#include <linux/of_platform.h>
> #include <linux/platform_device.h>
> #include <linux/reset.h>
>
> @@ -25,6 +26,7 @@
> #include <drm/drm_probe_helper.h>
>
> #include "sun4i_drv.h"
> +#include "sun50i_planes.h"
Nit: doesn't seem to follow the order we use elsewhere. I think we normally
would do:
sun4i_drv.h
sun8i_*
sun50i_planes.h
> #include "sun8i_mixer.h"
> #include "sun8i_ui_layer.h"
> #include "sun8i_vi_layer.h"
[...]
> @@ -566,12 +582,34 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
> if (!mixer->cfg)
> return -EINVAL;
>
> + if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
> + /*
> + * The original DE33 binding described planes as part of
> + * the mixer, which can't work with more than one mixer.
> + * It was never used by any device tree, so it's not
> + * supported.
> + */
> + if (of_property_match_string(dev->of_node, "reg-names",
> + "layers") >= 0 ||
No need to wrap this bit.
> + !of_property_present(dev->of_node, "allwinner,planes"))
> + return dev_err_probe(dev, -EINVAL,
> + "Unsupported DE33 mixer binding, please update the device tree\n");
> +
> + mixer->engine.ops = &sun50i_engine_ops;
> + } else {
> + mixer->engine.ops = &sun8i_engine_ops;
> + }
> +
> regs = devm_platform_ioremap_resource(pdev, 0);
> if (IS_ERR(regs))
> return PTR_ERR(regs);
>
> - mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
> - &sun8i_mixer_regmap_config);
> + if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> + mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
> + &sun50i_mixer33_regmap_config);
> + else
> + mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
> + &sun8i_mixer_regmap_config);
At some point we need to move most of the bind function to the probe function.
None of the devm_* stuff gets released if the bind function fails.
We can also switch to the combined devm_* helpers for clks and resets.
> if (IS_ERR(mixer->engine.regs)) {
> dev_err(dev, "Couldn't create the mixer regmap\n");
> return PTR_ERR(mixer->engine.regs);
> @@ -588,17 +626,6 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
> dev_err(dev, "Couldn't create the top regmap\n");
> return PTR_ERR(mixer->top_regs);
> }
> -
> - regs = devm_platform_ioremap_resource_byname(pdev, "display");
> - if (IS_ERR(regs))
> - return PTR_ERR(regs);
> -
> - mixer->disp_regs = devm_regmap_init_mmio(dev, regs,
> - &sun8i_disp_regmap_config);
> - if (IS_ERR(mixer->disp_regs)) {
> - dev_err(dev, "Couldn't create the disp regmap\n");
> - return PTR_ERR(mixer->disp_regs);
> - }
> }
>
> mixer->reset = devm_reset_control_get(dev, NULL);
> @@ -638,6 +665,40 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
>
> clk_prepare_enable(mixer->mod_clk);
>
> + if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
> + struct platform_device *pdev;
> + struct device_link *link;
> + struct device_node *np;
> + void *data;
> +
> + np = of_parse_phandle(dev->of_node, "allwinner,planes", 0);
> + if (!np) {
> + ret = -ENODEV;
> + goto err_disable_mod_clk;
> + }
> +
> + pdev = of_find_device_by_node(np);
> + of_node_put(np);
> + if (!pdev) {
> + ret = -EPROBE_DEFER;
> + goto err_disable_mod_clk;
> + }
> + mixer->planes_dev = &pdev->dev;
> +
> + data = platform_get_drvdata(pdev);
> + if (!data) {
"device_is_bound(&pdev->dev)" is probably more straightforward.
> + ret = -EPROBE_DEFER;
> + goto err_put_device;
> + }
> +
> + link = device_link_add(dev, &pdev->dev,
> + DL_FLAG_AUTOREMOVE_CONSUMER);
> + if (!link) {
> + ret = -EINVAL;
> + goto err_put_device;
> + }
> + }
> +
> list_add_tail(&mixer->engine.list, &drv->engine_list);
>
> /* Reset registers and disable unused sub-engines */
> @@ -672,6 +733,10 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
>
> return 0;
>
> +err_put_device:
> + put_device(mixer->planes_dev);
Should you have matching "if (mixer->cfg->de_type == SUN8I_MIXER_DE33)"
like in the .unbind callback?
Once fixed,
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v3 8/8] drm/sun4i: Switch DE33 to split plane bindings
2026-11-15 14:26 ` Chen-Yu Tsai
@ 2026-11-15 14:37 ` Chen-Yu Tsai
0 siblings, 0 replies; 16+ messages in thread
From: Chen-Yu Tsai @ 2026-11-15 14:37 UTC (permalink / raw)
To: Jernej Skrabec
Cc: Samuel Holland, mripard, maarten.lankhorst, tzimmermann, airlied,
simona, robh, krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
On Sun, Nov 15, 2026 at 10:26 PM Chen-Yu Tsai <wens@kernel.org> wrote:
>
> On Sun, Nov 15, 2026 at 2:11 PM Jernej Skrabec <jernej.skrabec@gmail.com> wrote:
> >
> > The shared plane driver and split register resources are now in place.
> > Switch DE33 mixer discovery to the new bindings and remove the legacy
> > per-mixer plane setup. Mixer register space now covers only display
> > blending control, so limit its regmap accordingly.
> >
> > The old DE33 binding is not supported anymore, since it can't describe
> > shared planes and was never used by any device tree. If it's detected,
> > print an error asking the user to update the device tree, instead of
> > failing silently or misusing the plane register space as blender
> > registers.
> >
> > Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
> > ---
> > drivers/gpu/drm/sun4i/sun8i_mixer.c | 195 ++++++++++++++++++++--------
> > drivers/gpu/drm/sun4i/sun8i_mixer.h | 10 +-
> > 2 files changed, 140 insertions(+), 65 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> > index dbde80b32080..0970be6aa035 100644
> > --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
> > +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> > @@ -13,6 +13,7 @@
> > #include <linux/of.h>
> > #include <linux/of_device.h>
> > #include <linux/of_graph.h>
> > +#include <linux/of_platform.h>
> > #include <linux/platform_device.h>
> > #include <linux/reset.h>
> >
> > @@ -25,6 +26,7 @@
> > #include <drm/drm_probe_helper.h>
> >
> > #include "sun4i_drv.h"
> > +#include "sun50i_planes.h"
>
> Nit: doesn't seem to follow the order we use elsewhere. I think we normally
> would do:
>
> sun4i_drv.h
> sun8i_*
> sun50i_planes.h
>
> > #include "sun8i_mixer.h"
> > #include "sun8i_ui_layer.h"
> > #include "sun8i_vi_layer.h"
>
> [...]
>
> > @@ -566,12 +582,34 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
> > if (!mixer->cfg)
> > return -EINVAL;
> >
> > + if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
> > + /*
> > + * The original DE33 binding described planes as part of
> > + * the mixer, which can't work with more than one mixer.
> > + * It was never used by any device tree, so it's not
> > + * supported.
> > + */
> > + if (of_property_match_string(dev->of_node, "reg-names",
> > + "layers") >= 0 ||
>
> No need to wrap this bit.
>
> > + !of_property_present(dev->of_node, "allwinner,planes"))
> > + return dev_err_probe(dev, -EINVAL,
> > + "Unsupported DE33 mixer binding, please update the device tree\n");
> > +
> > + mixer->engine.ops = &sun50i_engine_ops;
> > + } else {
> > + mixer->engine.ops = &sun8i_engine_ops;
> > + }
> > +
> > regs = devm_platform_ioremap_resource(pdev, 0);
> > if (IS_ERR(regs))
> > return PTR_ERR(regs);
> >
> > - mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
> > - &sun8i_mixer_regmap_config);
> > + if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> > + mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
> > + &sun50i_mixer33_regmap_config);
> > + else
> > + mixer->engine.regs = devm_regmap_init_mmio(dev, regs,
> > + &sun8i_mixer_regmap_config);
>
> At some point we need to move most of the bind function to the probe function.
> None of the devm_* stuff gets released if the bind function fails.
It seems I was wrong. Though it probably still makes sense to move anything
that could return -EPROBE_DEFER to the probe function to make it fail / retry
early.
ChenYu
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: (subset) [PATCH v3 0/8] drm/sun4i: update DE33 support
2026-11-15 6:10 [PATCH v3 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (8 preceding siblings ...)
2026-11-15 12:09 ` (subset) [PATCH v3 0/8] drm/sun4i: update DE33 support Chen-Yu Tsai
@ 2026-11-15 14:42 ` Chen-Yu Tsai
9 siblings, 0 replies; 16+ messages in thread
From: Chen-Yu Tsai @ 2026-11-15 14:42 UTC (permalink / raw)
To: Samuel Holland, Jernej Skrabec
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, bmasney+clk, jbrunet+clk, sboyd,
Andre Przywara, dri-devel, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel, linux-clk
On Sun, 15 Nov 2026 07:10:54 +0100, Jernej Skrabec wrote:
> This is second series out of tree which aims at properly introducing
> support for H616 Display Engine 3.3. Previous series [1] reorganized
> driver so proper DE33 support can be easily implemented.
>
> H616 DE33 support was actually introduced a while back, but it was done
> without fully understanding hardware design. Issue with existing binding
> is that it considers planes as resource which is hardwired to each mixer
> as it was done on older Display Engine generations (DE3 and lower). That
> is not the case anymore. This series introduces new driver for planes
> management, which allows doing proper plane assignments.
>
> [...]
Applied to drm-misc-next in drm-misc, thanks!
[3/8] drm/sun4i: Add support for DE33 CSC
commit: ea008133ef8078934a0dc2924a8263d645f0ee1c
[4/8] drm/sun4i: vi_layer: Limit formats for DE33
commit: b1ba050890684fc7615fe4c7d523f4f46c1696b1
Best regards,
--
Chen-Yu Tsai <wens@kernel.org>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2026-11-15 14:42 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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: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 14:04 ` Chen-Yu Tsai
2026-11-15 6:10 ` [PATCH v3 5/8] dt-bindings: display: allwinner: Add DE33 planes Jernej Skrabec
2026-11-15 6:11 ` [PATCH v3 6/8] drm/sun4i: Add DE33 shared plane driver Jernej Skrabec
2026-11-15 14:01 ` Chen-Yu Tsai
2026-11-15 6:11 ` [PATCH v3 7/8] dt-bindings: display: allwinner: Split H616 DE33 layer reg space Jernej Skrabec
2026-11-15 14:06 ` Chen-Yu Tsai
2026-11-15 6:11 ` [PATCH v3 8/8] drm/sun4i: Switch DE33 to split plane bindings Jernej Skrabec
2026-11-15 14:26 ` Chen-Yu Tsai
2026-11-15 14:37 ` Chen-Yu Tsai
2026-11-15 12:09 ` (subset) [PATCH v3 0/8] drm/sun4i: update DE33 support Chen-Yu Tsai
2026-11-15 14:42 ` Chen-Yu Tsai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®