* [PATCH v2 1/8] clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions
2026-05-09 19:00 [PATCH v2 0/8] drm/sun4i: update DE33 support Jernej Skrabec
@ 2026-05-09 19:00 ` Jernej Skrabec
2026-05-09 19:44 ` sashiko-bot
2026-05-09 19:00 ` [PATCH v2 2/8] clk: sunxi-ng: de2: Export register regmap for DE33 Jernej Skrabec
` (6 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Jernej Skrabec @ 2026-05-09 19:00 UTC (permalink / raw)
To: wens, samuel
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, mturquette, sboyd, dri-devel, devicetree,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-clk,
jernej.skrabec
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Positions of clocks and resets changed when version 3.3 was introduced.
However, old positions still work, just by luck.
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>
---
Changes from v1:
- new patch
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.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v2 1/8] clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions
2026-05-09 19:00 ` [PATCH v2 1/8] clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions Jernej Skrabec
@ 2026-05-09 19:44 ` sashiko-bot
2026-05-10 19:11 ` Jernej Škrabec
0 siblings, 1 reply; 16+ messages in thread
From: sashiko-bot @ 2026-05-09 19:44 UTC (permalink / raw)
To: Jernej Skrabec; +Cc: devicetree, krzk+dt, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The new DE33 clock definitions omit the bus clocks for MIXER1 and WB, leaving their bus interfaces unclocked and breaking hardware support.
--
commit 7e5df4616faf2d32c9447b44291572215aac8a17
Author: Jernej Skrabec <jernej.skrabec@gmail.com>
clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions
This commit fixes the Display Engine 3.3 resets and clocks to match
the vendor driver, as the positions of clocks and resets changed in
version 3.3.
> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
> index a6cd0f988859d..6ec6c0dc4c261 100644
> --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
> +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
[ ... ]
> @@ -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);
> +
Will this omission cause a regression for mixer1 and wb?
It looks like the bus clocks for mixer1 (BIT(1)) and wb (BIT(4)) at register
offset 0x08 are missing here.
Since RST_MIXER1 was previously mapped to 0x08 BIT(1), the DRM driver
deasserting that reset was inadvertently enabling the DE33 bus clock for
mixer1.
Now that RST_MIXER1 is correctly moved to 0x00, will accessing the
unclocked MIXER1 or WB hardware blocks cause a hard system hang due to MMIO
access failures?
[ ... ]
> @@ -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,
Similarly, should the bus clocks for mixer1 and wb be populated in this
array so the DRM driver can properly request and enable them?
> + },
> + .num = CLK_NUMBER_WITHOUT_ROT,
> +};
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509190015.79086-1-jernej.skrabec@siol.net?part=1
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 1/8] clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions
2026-05-09 19:44 ` sashiko-bot
@ 2026-05-10 19:11 ` Jernej Škrabec
0 siblings, 0 replies; 16+ messages in thread
From: Jernej Škrabec @ 2026-05-10 19:11 UTC (permalink / raw)
To: sashiko; +Cc: devicetree, krzk+dt, robh, conor+dt
Dne sobota, 9. maj 2026 ob 21:44:02 Srednjeevropski poletni čas je sashiko-bot@kernel.org napisal(a):
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] The new DE33 clock definitions omit the bus clocks for MIXER1 and WB, leaving their bus interfaces unclocked and breaking hardware support.
> --
>
> commit 7e5df4616faf2d32c9447b44291572215aac8a17
> Author: Jernej Skrabec <jernej.skrabec@gmail.com>
>
> clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions
>
> This commit fixes the Display Engine 3.3 resets and clocks to match
> the vendor driver, as the positions of clocks and resets changed in
> version 3.3.
>
> > diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
> > index a6cd0f988859d..6ec6c0dc4c261 100644
> > --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
> > +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
>
> [ ... ]
>
> > @@ -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);
> > +
>
> Will this omission cause a regression for mixer1 and wb?
No, I should explain in commit message that there is only one bus clock,
shared among mixer0, mixer1 and wb. CLK_BUS_MIXER0 is used for all
cores.
>
> It looks like the bus clocks for mixer1 (BIT(1)) and wb (BIT(4)) at register
> offset 0x08 are missing here.
>
> Since RST_MIXER1 was previously mapped to 0x08 BIT(1), the DRM driver
> deasserting that reset was inadvertently enabling the DE33 bus clock for
> mixer1.
>
> Now that RST_MIXER1 is correctly moved to 0x00, will accessing the
> unclocked MIXER1 or WB hardware blocks cause a hard system hang due to MMIO
> access failures?
There are no such issues, as hardware testing showed. Old code worked by luck.
Best regards,
Jernej
>
> [ ... ]
>
> > @@ -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,
>
> Similarly, should the bus clocks for mixer1 and wb be populated in this
> array so the DRM driver can properly request and enable them?
>
> > + },
> > + .num = CLK_NUMBER_WITHOUT_ROT,
> > +};
>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 2/8] clk: sunxi-ng: de2: Export register regmap for DE33
2026-05-09 19:00 [PATCH v2 0/8] drm/sun4i: update DE33 support Jernej Skrabec
2026-05-09 19:00 ` [PATCH v2 1/8] clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions Jernej Skrabec
@ 2026-05-09 19:00 ` Jernej Skrabec
2026-05-09 20:05 ` sashiko-bot
2026-05-09 19:00 ` [PATCH v2 3/8] drm/sun4i: Add support for DE33 CSC Jernej Skrabec
` (5 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Jernej Skrabec @ 2026-05-09 19:00 UTC (permalink / raw)
To: wens, samuel
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, mturquette, sboyd, dri-devel, devicetree,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-clk,
jernej.skrabec
From: Jernej Skrabec <jernej.skrabec@gmail.com>
DE33 clock pre-set plane mapping, which is not something that we want
from clock driver. Export registers instead, so DRM driver can set them
properly.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
Changes from v1:
- used access tables instead of functions
- used macro for max register
- used dev_of_node() instead of open coding
drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 48 ++++++++++++++++++++++++++--
1 file changed, 45 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..26d8abd5fac6 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -6,9 +6,11 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
+#include <linux/mfd/syscon.h>
#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 +285,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 +368,23 @@ 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 = of_syscon_register_regmap(dev_of_node(&pdev->dev), regmap);
+ if (ret)
+ goto err_assert_reset;
}
ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v2 2/8] clk: sunxi-ng: de2: Export register regmap for DE33
2026-05-09 19:00 ` [PATCH v2 2/8] clk: sunxi-ng: de2: Export register regmap for DE33 Jernej Skrabec
@ 2026-05-09 20:05 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-05-09 20:05 UTC (permalink / raw)
To: Jernej Skrabec; +Cc: devicetree, krzk+dt, robh, conor+dt
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] Use-after-free and permanent probe failure due to registering a devm-managed regmap with syscon.
- [High] Unconditional probe failure if `CONFIG_MFD_SYSCON` is disabled.
--
commit ef866c925d5c9b0231c3dc8c7b9a9590e11b86ec
Author: Jernej Skrabec <jernej.skrabec@gmail.com>
clk: sunxi-ng: de2: Export register regmap for DE33
This commit adds a regmap for DE33 plane mapping registers and registers
it via syscon so the DRM driver can access them.
> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
> --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
> +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
[ ... ]
> @@ -336,13 +368,23 @@ 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 = of_syscon_register_regmap(dev_of_node(&pdev->dev), regmap);
> + if (ret)
> + goto err_assert_reset;
If syscon is disabled in the kernel configuration, the inline stub for
of_syscon_register_regmap() returns -EOPNOTSUPP. Will this unconditionally
fail the probe for the core display clock controller on systems without syscon
enabled?
Additionally, is it safe to register a devm-managed regmap with syscon?
of_syscon_register_regmap() adds the regmap to a global list but provides no
deregistration mechanism, as syscon assumes permanent mappings.
If the driver module is unbound by a user via sysfs, or if the subsequent
devm_sunxi_ccu_probe() call fails, devres will automatically free the regmap
and unmap the MMIO.
Would this leave a dangling pointer in the global syscon list, leading to a
use-after-free when the DRM driver looks it up? Also, wouldn't a subsequent
attempt to re-bind fail permanently with -EEXIST?
> }
>
> ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509190015.79086-1-jernej.skrabec@siol.net?part=2
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 3/8] drm/sun4i: Add support for DE33 CSC
2026-05-09 19:00 [PATCH v2 0/8] drm/sun4i: update DE33 support Jernej Skrabec
2026-05-09 19:00 ` [PATCH v2 1/8] clk: sunxi-ng: de2: Fix Display Engine 3.3 definitions Jernej Skrabec
2026-05-09 19:00 ` [PATCH v2 2/8] clk: sunxi-ng: de2: Export register regmap for DE33 Jernej Skrabec
@ 2026-05-09 19:00 ` Jernej Skrabec
2026-05-09 19:00 ` [PATCH v2 4/8] drm/sun4i: vi_layer: Limit formats for DE33 Jernej Skrabec
` (4 subsequent siblings)
7 siblings, 0 replies; 16+ messages in thread
From: Jernej Skrabec @ 2026-05-09 19:00 UTC (permalink / raw)
To: wens, samuel
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, mturquette, sboyd, dri-devel, devicetree,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-clk,
jernej.skrabec, Chen-Yu Tsai
From: Jernej Skrabec <jernej.skrabec@gmail.com>
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>
---
Changes from v1:
- collected tag
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.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 4/8] drm/sun4i: vi_layer: Limit formats for DE33
2026-05-09 19:00 [PATCH v2 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (2 preceding siblings ...)
2026-05-09 19:00 ` [PATCH v2 3/8] drm/sun4i: Add support for DE33 CSC Jernej Skrabec
@ 2026-05-09 19:00 ` Jernej Skrabec
2026-05-09 20:58 ` sashiko-bot
2026-05-09 19:00 ` [PATCH v2 5/8] dt-bindings: display: allwinner: Add DE33 planes Jernej Skrabec
` (3 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Jernej Skrabec @ 2026-05-09 19:00 UTC (permalink / raw)
To: wens, samuel
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, mturquette, sboyd, dri-devel, devicetree,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-clk,
jernej.skrabec, Chen-Yu Tsai
From: Jernej Skrabec <jernej.skrabec@gmail.com>
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>
---
Changes from v1:
- collected tag
- generalize check to be dependant on scaler feature
drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 40 ++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index cd8d6c2da0c7..afbd41a18a0e 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
@@ -410,8 +437,17 @@ 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.
+ */
+ if (layer->cfg->scaler_mask & BIT(phy_index)) {
+ 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);
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v2 4/8] drm/sun4i: vi_layer: Limit formats for DE33
2026-05-09 19:00 ` [PATCH v2 4/8] drm/sun4i: vi_layer: Limit formats for DE33 Jernej Skrabec
@ 2026-05-09 20:58 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-05-09 20:58 UTC (permalink / raw)
To: Jernej Skrabec; +Cc: devicetree, robh, krzk+dt, conor+dt
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Exposing YCBCR color properties on a plane that does not support YUV formats introduces UAPI inconsistency.
--
commit 929b63037079ff8fc9eaecabce5ad91bde84083f
Author: Jernej Skrabec <jernej.skrabec@gmail.com>
drm/sun4i: vi_layer: Limit formats for DE33
This commit removes YUV formats from the supported list for DE33 planes
without scaler support. A new format array containing only RGB formats is
introduced and used when scaling is unavailable.
> diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
> --- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
> +++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
[ ... ]
> @@ -410,8 +437,17 @@ 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.
> + */
> + if (layer->cfg->scaler_mask & BIT(phy_index)) {
> + 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);
> + }
Since sun8i_vi_layer_de3_no_yuv_formats only contains RGB formats, should
the driver skip calling drm_plane_create_color_properties() for this
configuration?
Later in sun8i_vi_layer_init_one(), the driver unconditionally calls
drm_plane_create_color_properties(), which exposes YCBCR color encoding and
range UAPI properties. Could this expose confusing or meaningless YUV
properties to userspace for planes where only RGB formats are supported?
> } else {
> formats = sun8i_vi_layer_formats;
> format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509190015.79086-1-jernej.skrabec@siol.net?part=4
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 5/8] dt-bindings: display: allwinner: Add DE33 planes
2026-05-09 19:00 [PATCH v2 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (3 preceding siblings ...)
2026-05-09 19:00 ` [PATCH v2 4/8] drm/sun4i: vi_layer: Limit formats for DE33 Jernej Skrabec
@ 2026-05-09 19:00 ` Jernej Skrabec
2026-05-09 21:12 ` sashiko-bot
2026-05-09 19:00 ` [PATCH v2 6/8] drm/sun4i: Add planes driver Jernej Skrabec
` (2 subsequent siblings)
7 siblings, 1 reply; 16+ messages in thread
From: Jernej Skrabec @ 2026-05-09 19:00 UTC (permalink / raw)
To: wens, samuel
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, mturquette, sboyd, dri-devel, devicetree,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-clk,
jernej.skrabec
From: Jernej Skrabec <jernej.skrabec@gmail.com>
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.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
Changes from v1:
- dropped | for description
- better description for allwinner,plane-mapping
.../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.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v2 5/8] dt-bindings: display: allwinner: Add DE33 planes
2026-05-09 19:00 ` [PATCH v2 5/8] dt-bindings: display: allwinner: Add DE33 planes Jernej Skrabec
@ 2026-05-09 21:12 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-05-09 21:12 UTC (permalink / raw)
To: Jernej Skrabec; +Cc: devicetree, conor+dt, krzk+dt, robh
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] The binding specifies an independent memory-mapped region (`reg`) but completely omits required hardware dependencies like `clocks` and `resets`.
--
commit c4cb2c3df2e7559ecf6e92deffc259a4516494c5
Author: Jernej Skrabec <jernej.skrabec@gmail.com>
dt-bindings: display: allwinner: Add DE33 planes
This commit adds a new device tree binding for the Allwinner Display Engine
3.3 planes. These planes act as shared resources between mixers and are
assigned using registers within the display clocks MMIO space.
> 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 0000000000000..0a07cb8a5f798
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/allwinner,sun50i-h616-de33-planes.yaml
[ ... ]
> +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
Does this binding also need to specify clocks and resets as required
properties?
Since this node represents an independent MMIO hardware block, omitting its
hardware dependencies relies on the sibling mixer driver to implicitly power
the bus.
If the sun8i-mixer driver is unbound or fails to probe, the shared display
bus clock is left disabled. Would a subsequent read of the planes regmap
exposed to userspace via debugfs perform an MMIO read on an unclocked bus
and result in a fatal external abort (SError)?
Should clocks and resets be added to the binding so the planes driver can
manage its own bus access safely (for example, by using
regmap_mmio_attach_clk())?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509190015.79086-1-jernej.skrabec@siol.net?part=5
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 6/8] drm/sun4i: Add planes driver
2026-05-09 19:00 [PATCH v2 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (4 preceding siblings ...)
2026-05-09 19:00 ` [PATCH v2 5/8] dt-bindings: display: allwinner: Add DE33 planes Jernej Skrabec
@ 2026-05-09 19:00 ` Jernej Skrabec
2026-05-09 21:31 ` sashiko-bot
2026-05-09 19:00 ` [PATCH v2 7/8] dt-bindings: display: allwinner: Split H616 DE33 layer reg space Jernej Skrabec
2026-05-09 19:00 ` [PATCH v2 8/8] drm/sun4i: switch DE33 to new bindings Jernej Skrabec
7 siblings, 1 reply; 16+ messages in thread
From: Jernej Skrabec @ 2026-05-09 19:00 UTC (permalink / raw)
To: wens, samuel
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, mturquette, sboyd, dri-devel, devicetree,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-clk,
jernej.skrabec
From: Jernej Skrabec <jernej.skrabec@gmail.com>
This driver serves just as planes sharing manager, needed for Display
Engine 3.3 and newer.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
Changes from v1:
- removed CONFIG_DRM_SUN50I_PLANES Kconfig entirely
- make sun50i_planes_of_table[] static
- folded sun50i_planes_node_is_planes() into sun50i_planes_setup()
- sun50i_planes_setup() error returns now ERR_PTR(-EINVAL) instead of NULL
at first three checks
- quirks and of_device_id table moved on top to avoid forward declaration
drivers/gpu/drm/sun4i/Makefile | 3 +-
drivers/gpu/drm/sun4i/sun50i_planes.c | 201 ++++++++++++++++++++++++++
drivers/gpu/drm/sun4i/sun50i_planes.h | 41 ++++++
3 files changed, 244 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..6469de1baf03
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_planes.c
@@ -0,0 +1,201 @@
+// 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/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.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;
+}
+EXPORT_SYMBOL(sun50i_planes_setup);
+
+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 device *dev = &pdev->dev;
+ struct sun50i_planes *planes;
+ void __iomem *regs;
+
+ planes = devm_kzalloc(dev, sizeof(*planes), GFP_KERNEL);
+ if (!planes)
+ return -ENOMEM;
+
+ planes->quirks = of_device_get_match_data(&pdev->dev);
+ if (!planes->quirks)
+ return dev_err_probe(dev, -EINVAL, "Unable to get quirks\n");
+
+ planes->mapping = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "allwinner,plane-mapping");
+ if (IS_ERR(planes->mapping))
+ return dev_err_probe(dev, PTR_ERR(planes->mapping),
+ "Unable to get mapping\n");
+
+ 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);
+
+ dev_set_drvdata(dev, planes);
+
+ sun50i_planes_init_mapping(planes);
+
+ return 0;
+}
+
+static struct platform_driver sun50i_planes_platform_driver = {
+ .probe = sun50i_planes_probe,
+ .driver = {
+ .name = "sun50i-planes",
+ .of_match_table = sun50i_planes_of_table,
+ },
+};
+module_platform_driver(sun50i_planes_platform_driver);
+
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@gmail.com>");
+MODULE_DESCRIPTION("Allwinner DE33 planes driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.h b/drivers/gpu/drm/sun4i/sun50i_planes.h
new file mode 100644
index 000000000000..e5b54ed16178
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_planes.h
@@ -0,0 +1,41 @@
+/* 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);
+
+#endif /* _SUN50I_PLANES_H_ */
--
2.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v2 6/8] drm/sun4i: Add planes driver
2026-05-09 19:00 ` [PATCH v2 6/8] drm/sun4i: Add planes driver Jernej Skrabec
@ 2026-05-09 21:31 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-05-09 21:31 UTC (permalink / raw)
To: Jernej Skrabec; +Cc: robh, conor+dt, krzk+dt, devicetree
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Use-After-Free vulnerability when the `sun50i-planes` driver is unbound via sysfs.
- [Medium] Race condition during probe exposing uninitialized hardware state.
- [Low] Multiple definition build failure due to duplicate `module_platform_driver()` in the same module.
--
commit 19bad84553b057724d61d90ba01ff45aacdcaa90
Author: Jernej Skrabec <jernej.skrabec@gmail.com>
drm/sun4i: Add planes driver
This driver serves just as planes sharing manager, needed for Display Engine
3.3 and newer.
> diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
> index bad7497a0d11e..501e3d8679185 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
[ ... ]
> diff --git a/drivers/gpu/drm/sun4i/sun50i_planes.c b/drivers/gpu/drm/sun4i/sun50i_planes.c
> new file mode 100644
> index 0000000000000..6469de1baf030
> --- /dev/null
> +++ b/drivers/gpu/drm/sun4i/sun50i_planes.c
> @@ -0,0 +1,201 @@
[ ... ]
> +static int sun50i_planes_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct sun50i_planes *planes;
> + void __iomem *regs;
> +
> + planes = devm_kzalloc(dev, sizeof(*planes), GFP_KERNEL);
> + if (!planes)
> + return -ENOMEM;
> +
> + planes->quirks = of_device_get_match_data(&pdev->dev);
> + if (!planes->quirks)
> + return dev_err_probe(dev, -EINVAL, "Unable to get quirks\n");
> +
> + planes->mapping = syscon_regmap_lookup_by_phandle(dev->of_node,
> + "allwinner,plane-mapping");
> + if (IS_ERR(planes->mapping))
> + return dev_err_probe(dev, PTR_ERR(planes->mapping),
> + "Unable to get mapping\n");
> +
> + 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 the sun50i-planes driver is unbound via sysfs, devres will clean up this
regmap. Since the driver doesn't seem to integrate with the component
framework or establish device links with the DRM master, could the active DRM
device dereference the freed regmap pointer during atomic plane updates and
cause a use-after-free?
> + if (IS_ERR(planes->regs))
> + return PTR_ERR(planes->regs);
> +
> + dev_set_drvdata(dev, planes);
> +
> + sun50i_planes_init_mapping(planes);
Is there a potential race condition here? If the DRM mixer driver checks for
the availability of this driver data to determine if the planes driver has
finished probing, it might proceed to use the DRM planes while the hardware's
channel-to-core mapping is still uninitialized.
Should dev_set_drvdata() be called after sun50i_planes_init_mapping()?
> +
> + return 0;
> +}
> +
> +static struct platform_driver sun50i_planes_platform_driver = {
> + .probe = sun50i_planes_probe,
> + .driver = {
> + .name = "sun50i-planes",
> + .of_match_table = sun50i_planes_of_table,
> + },
> +};
> +module_platform_driver(sun50i_planes_platform_driver);
Since sun50i_planes.o is added to sun8i-mixer-y in the Makefile, it will be
linked into the same module as sun8i_mixer.o. Will invoking
module_platform_driver() here cause a multiple definition linker error for
init_module and cleanup_module?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509190015.79086-1-jernej.skrabec@siol.net?part=6
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 7/8] dt-bindings: display: allwinner: Split H616 DE33 layer reg space
2026-05-09 19:00 [PATCH v2 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (5 preceding siblings ...)
2026-05-09 19:00 ` [PATCH v2 6/8] drm/sun4i: Add planes driver Jernej Skrabec
@ 2026-05-09 19:00 ` Jernej Skrabec
2026-05-09 19:00 ` [PATCH v2 8/8] drm/sun4i: switch DE33 to new bindings Jernej Skrabec
7 siblings, 0 replies; 16+ messages in thread
From: Jernej Skrabec @ 2026-05-09 19:00 UTC (permalink / raw)
To: wens, samuel
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, mturquette, sboyd, dri-devel, devicetree,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-clk,
jernej.skrabec
From: Jernej Skrabec <jernej.skrabec@gmail.com>
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.
There is no user of this binding yet, so changes can be made safely,
without breaking any backward compatibility.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
Changes in v1:
- update commit subject
- reword commit message
.../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.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 8/8] drm/sun4i: switch DE33 to new bindings
2026-05-09 19:00 [PATCH v2 0/8] drm/sun4i: update DE33 support Jernej Skrabec
` (6 preceding siblings ...)
2026-05-09 19:00 ` [PATCH v2 7/8] dt-bindings: display: allwinner: Split H616 DE33 layer reg space Jernej Skrabec
@ 2026-05-09 19:00 ` Jernej Skrabec
2026-05-09 22:00 ` sashiko-bot
7 siblings, 1 reply; 16+ messages in thread
From: Jernej Skrabec @ 2026-05-09 19:00 UTC (permalink / raw)
To: wens, samuel
Cc: mripard, maarten.lankhorst, tzimmermann, airlied, simona, robh,
krzk+dt, conor+dt, mturquette, sboyd, dri-devel, devicetree,
linux-arm-kernel, linux-sunxi, linux-kernel, linux-clk,
jernej.skrabec
From: Jernej Skrabec <jernej.skrabec@gmail.com>
Now that everything is in place, switch DE33 to new bindings.
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
---
Changes from v1:
- remove CONFIG_DRM_SUN50I_PLANES guard
- fix error path
drivers/gpu/drm/sun4i/sun8i_mixer.c | 131 +++++++++++++++-------------
drivers/gpu/drm/sun4i/sun8i_mixer.h | 10 +--
2 files changed, 72 insertions(+), 69 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 4071ab38b4ae..957db0938455 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_kcalloc(drm->dev, plane_cnt + 1, sizeof(*planes), GFP_KERNEL);
@@ -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,22 @@ 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);
+
+ return sun50i_planes_setup(mixer->planes_dev, drm, engine->id);
+}
+
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 +396,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,8 +416,14 @@ 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",
+ .name = "display",
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
@@ -434,14 +438,6 @@ static const struct regmap_config sun8i_top_regmap_config = {
.max_register = 0x3c,
};
-static const struct regmap_config sun8i_disp_regmap_config = {
- .name = "display",
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
- .max_register = 0x20000,
-};
-
static int sun8i_mixer_of_get_id(struct device_node *node)
{
struct device_node *ep, *remote;
@@ -464,17 +460,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 +477,25 @@ 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 = 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 +526,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,6 +558,11 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
if (!mixer->cfg)
return -EINVAL;
+ if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
+ 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);
@@ -588,17 +585,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 +624,34 @@ 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_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;
+ }
+
+ data = platform_get_drvdata(pdev);
+ if (!data) {
+ put_device(&pdev->dev);
+ ret = -EPROBE_DEFER;
+ goto err_disable_mod_clk;
+ }
+
+ mixer->planes_dev = &pdev->dev;
+ }
+
list_add_tail(&mixer->engine.list, &drv->engine_list);
/* Reset registers and disable unused sub-engines */
@@ -672,6 +686,8 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
return 0;
+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 +702,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 +886,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[] = {
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.54.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v2 8/8] drm/sun4i: switch DE33 to new bindings
2026-05-09 19:00 ` [PATCH v2 8/8] drm/sun4i: switch DE33 to new bindings Jernej Skrabec
@ 2026-05-09 22:00 ` sashiko-bot
0 siblings, 0 replies; 16+ messages in thread
From: sashiko-bot @ 2026-05-09 22:00 UTC (permalink / raw)
To: Jernej Skrabec; +Cc: krzk+dt, devicetree, conor+dt, robh
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Uninitialized blender mode registers for DE33 due to zero plane_cnt.
- [High] Missing device link to the planes device creates a Use-After-Free vulnerability.
--
commit c691a21629b6216c482f2beb09752658d71b6425
Author: Jernej Skrabec <jernej.skrabec@gmail.com>
drm/sun4i: switch DE33 to new bindings
Now that everything is in place, switch DE33 to new bindings.
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> index 4071ab38b4ae5..957db09384552 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
[ ... ]
> @@ -638,6 +624,34 @@ 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_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;
> + }
> +
> + data = platform_get_drvdata(pdev);
> + if (!data) {
> + put_device(&pdev->dev);
> + ret = -EPROBE_DEFER;
> + goto err_disable_mod_clk;
> + }
> +
> + mixer->planes_dev = &pdev->dev;
Does this code need a device link (e.g., using device_link_add()) to the
planes device?
Without a device link, unbinding the planes driver via sysfs could free
its devres-managed memory.
Later, sun50i_planes_setup() extracts the planes driver's regmap
(planes->regs) and stores it directly in the DRM layer structures.
If the planes driver is unbound, wouldn't subsequent atomic commits
dereference the dangling layer->regs pointer and cause a use-after-free
regression?
> + }
> +
> list_add_tail(&mixer->engine.list, &drv->engine_list);
>
> /* Reset registers and disable unused sub-engines */
[ ... ]
> @@ -867,16 +886,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,
With ui_num and vi_num removed, they will default to 0.
In sun8i_mixer_init(), we compute the total planes:
plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
And then initialize the blending modes:
for (i = 0; i < plane_cnt; i++)
regmap_write(mixer->engine.regs,
SUN8I_MIXER_BLEND_MODE(base, i),
SUN8I_MIXER_BLEND_MODE_DEF);
Because plane_cnt will be 0, wouldn't this skip the blender initialization
loop entirely for DE33 hardware?
Could this regression break display composition and alpha blending by leaving
the blender pipes without their default modes?
> - .map = {0, 6, 7, 8},
> };
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260509190015.79086-1-jernej.skrabec@siol.net?part=8
^ permalink raw reply [flat|nested] 16+ messages in thread