[PATCH RESEND] drm: panel: nv3052c: correct spi_device_id for RG35XX panel

2024-10-20 Thread Ryan Walklin
The Anbernic RG35XX devices use an SPI LCD panel from an unknown OEM,
with an NV3052C driver chip.

As discussed previously, the integrating vendor and device name are
preferred instead of the OEM serial. A previous patch corrected the
device tree binding and of_device_id in the NV3052C driver, however the
spi_device_id also needs correction.

Correct the spi_device_id for the RG35XX panel.

Signed-off-by: Ryan Walklin 
Fixes: 76dce2a9 ("drm: panel: nv3052c: Correct WL-355608-A8 panel compatible")
Reviewed-by: Neil Armstrong 
---
 drivers/gpu/drm/panel/panel-newvision-nv3052c.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c 
b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
index d3baccfe6286b..06e16a7c14a75 100644
--- a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
+++ b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
@@ -917,7 +917,7 @@ static const struct nv3052c_panel_info 
wl_355608_a8_panel_info = {
 static const struct spi_device_id nv3052c_ids[] = {
{ "ltk035c5444t", },
{ "fs035vg158", },
-   { "wl-355608-a8", },
+   { "rg35xx-plus-panel", },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(spi, nv3052c_ids);
-- 
2.47.0



[PATCH v5 26/26] drm: sun4i: de33: csc: add Display Engine 3.3 (DE33) support

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Like earlier DE versions, the DE33 has a CSC (Color Space Correction)
module. which provides color space conversion between BT2020/BT709, and
dynamic range conversion between SDR/ST2084/HLG.

Add support for the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c | 96 +++
 drivers/gpu/drm/sun4i/sun8i_csc.h |  3 +
 2 files changed, 99 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 2d5a2cf7cba24..45bd1ca06400e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -238,6 +238,14 @@ static const u32 yuv2yuv_de3[2][3][3][12] = {
},
 };
 
+static u32 sun8i_csc_base(struct sun8i_mixer *mixer, int layer)
+{
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return sun8i_channel_base(mixer, layer) - 0x800;
+   else
+   return ccsc_base[mixer->cfg->ccsc][layer];
+}
+
 static void sun8i_csc_setup(struct regmap *map, u32 base,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -358,6 +366,90 @@ static void sun8i_de3_ccsc_setup(struct sunxi_engine 
*engine, 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] &= 0x;
+   dst[10] &= 0x;
+   dst[14] &= 0x;
+}
+
+static void sun8i_de33_ccsc_setup(struct sun8i_mixer *mixer, int layer,
+ enum format_type fmt_type,
+ enum drm_color_encoding encoding,
+ enum drm_color_range range)
+{
+   u32 addr, val = 0, base, csc[15];
+   struct sunxi_engine *engine;
+   struct regmap *map;
+   const u32 *table;
+   int i;
+
+   table = yuv2rgb_de3[range][encoding];
+   base = sun8i_csc_base(mixer, layer);
+   engine = &mixer->engine;
+   map = engine->regs;
+
+   switch (fmt_type) {
+   case FORMAT_TYPE_RGB:
+   if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
+   break;
+   val = SUN8I_CSC_CTRL_EN;
+   sun8i_de33_convert_table(rgb2yuv_de3[engine->encoding], csc);
+   regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+   break;
+   case FORMAT_TYPE_YUV:
+   table = sun8i_csc_get_de3_yuv_table(encoding, range,
+   engine->format,
+   engine->encoding);
+   if (!table)
+   break;
+   val = SUN8I_CSC_CTRL_EN;
+   sun8i_de33_convert_table(table, csc);
+   regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+   break;
+   case FORMAT_TYPE_YVU:
+   table = sun8i_csc_get_de3_yuv_table(encoding, range,
+   engine->format,
+   engine->encoding);
+   if (!table)
+   table = yuv2yuv_de3[range][encoding][encoding];
+   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);
+}
+
 void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -369,6 +461,10 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
sun8i_de3_ccsc_setup(&mixer->engine, layer,
  

[PATCH v5 25/26] drm: sun4i: de33: fmt: add Display Engine 3.3 (DE33) support

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Like the DE3, the DE33 has a FMT (formatter) module, which
provides YUV444 to YUV422/YUV420 conversion, format re-mapping and color
depth conversion, although the DE33 module appears significantly more
capable, including up to 4K video support.

Add support for the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun50i_fmt.c | 21 +++--
 drivers/gpu/drm/sun4i/sun50i_fmt.h |  1 +
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.c 
b/drivers/gpu/drm/sun4i/sun50i_fmt.c
index 050a8716ae862..39682d4e6d208 100644
--- a/drivers/gpu/drm/sun4i/sun50i_fmt.c
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.c
@@ -51,6 +51,19 @@ static void sun50i_fmt_de3_limits(u32 *limits, u32 
colorspace, bool bit10)
}
 }
 
+static void sun50i_fmt_de33_limits(u32 *limits, u32 colorspace)
+{
+   if (colorspace == SUN50I_FMT_CS_YUV444RGB) {
+   limits[0] = SUN50I_FMT_LIMIT(0, 4095);
+   limits[1] = SUN50I_FMT_LIMIT(0, 4095);
+   limits[2] = SUN50I_FMT_LIMIT(0, 4095);
+   } else {
+   limits[0] = SUN50I_FMT_LIMIT(256, 3840);
+   limits[1] = SUN50I_FMT_LIMIT(256, 3840);
+   limits[2] = SUN50I_FMT_LIMIT(256, 3840);
+   }
+}
+
 void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
  u16 height, u32 format)
 {
@@ -60,10 +73,14 @@ void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
 
colorspace = sun50i_fmt_get_colorspace(format);
bit10 = sun50i_fmt_is_10bit(format);
-   base = SUN50I_FMT_DE3;
+   base = mixer->cfg->de_type == sun8i_mixer_de3 ?
+   SUN50I_FMT_DE3 : SUN50I_FMT_DE33;
regs = sun8i_blender_regmap(mixer);
 
-   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+   else
+   sun50i_fmt_de33_limits(limit, colorspace);
 
regmap_write(regs, SUN50I_FMT_CTRL(base), 0);
 
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.h 
b/drivers/gpu/drm/sun4i/sun50i_fmt.h
index 4127f7206aade..3e60d5c788b39 100644
--- a/drivers/gpu/drm/sun4i/sun50i_fmt.h
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.h
@@ -9,6 +9,7 @@
 #include "sun8i_mixer.h"
 
 #define SUN50I_FMT_DE3 0xa8000
+#define SUN50I_FMT_DE33 0x5000
 
 #define SUN50I_FMT_CTRL(base)   ((base) + 0x00)
 #define SUN50I_FMT_SIZE(base)   ((base) + 0x04)
-- 
2.46.1



[PATCH v5 24/26] drm: sun4i: de33: vi_scaler: add Display Engine 3.3 (DE33) support

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

The vi_scaler appears to be used in preference to the ui_scaler module
for hardware video scaling in the DE33.

Enable support for this scaler.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c  | 19 +++
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c |  7 ++-
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 7f1231cf0f012..180be9d67d9c3 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -95,12 +95,23 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
hscale = state->src_w / state->crtc_w;
vscale = state->src_h / state->crtc_h;
 
-   sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w,
- dst_h, hscale, vscale, hphase, vphase);
-   sun8i_ui_scaler_enable(mixer, channel, true);
+   if (mixer->cfg->de_type == sun8i_mixer_de33) {
+   sun8i_vi_scaler_setup(mixer, channel, src_w, src_h,
+ dst_w, dst_h, hscale, vscale,
+ hphase, vphase,
+ state->fb->format);
+   } else {
+   sun8i_ui_scaler_setup(mixer, channel, src_w, src_h,
+ dst_w, dst_h, hscale, vscale,
+ hphase, vphase);
+   sun8i_ui_scaler_enable(mixer, channel, true);
+   }
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
-   sun8i_ui_scaler_enable(mixer, channel, false);
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   sun8i_vi_scaler_disable(mixer, channel);
+   else
+   sun8i_ui_scaler_enable(mixer, channel, false);
}
 
/* Set base coordinates */
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index e7242301b312c..9c7f6e7d71d50 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -835,7 +835,9 @@ static const u32 bicubic4coefftab32[480] = {
 
 static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
 {
-   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return sun8i_channel_base(mixer, channel) + 0x3000;
+   else if (mixer->cfg->de_type == sun8i_mixer_de3)
return DE3_VI_SCALER_UNIT_BASE +
   DE3_VI_SCALER_UNIT_SIZE * channel;
else
@@ -845,6 +847,9 @@ static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, 
int channel)
 
 static bool sun8i_vi_scaler_is_vi_plane(struct sun8i_mixer *mixer, int channel)
 {
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return mixer->cfg->map[channel] < mixer->cfg->vi_num;
+
return true;
 }
 
-- 
2.46.1



[PATCH v5 23/26] drm: sun4i: de33: mixer: add Display Engine 3.3 (DE33) support

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

The DE33 is a newer version of the Allwinner Display Engine IP block,
found in the H616, H618, H700 and T507 SoCs. DE2 and DE3 are already
supported by the mainline driver.

Notable features (from the H616 datasheet and implemented):
- 4096 x 2048 (4K) output support
- AFBC ARM Frame Buffer Compression support
- YUV420 input support

The DE2 and DE3 engines have a blender register range within the
mixer engine register map, whereas the DE33 separates this out into
a separate display group, and adds a top register map.

Extend the mixer to support the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 

---
Changelog v4..v5:
- Whitespace fixes
- Correct strict mode warnings from checkpatch.pl
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 109 
 drivers/gpu/drm/sun4i/sun8i_mixer.h |  16 +++-
 2 files changed, 108 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 600084286b39d..204fc8055b32a 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -321,8 +321,12 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
 pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
 
-   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
-SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_DBUFF,
+SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+   else
+   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
+SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
 }
 
 static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
@@ -371,25 +375,33 @@ 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, *disp_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);
 
DRM_DEBUG_DRIVER("Updating global size W: %u H: %u\n",
 mode->hdisplay, mode->vdisplay);
 
-   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_SIZE, size);
-   regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
+   if (mixer->cfg->de_type == sun8i_mixer_de33) {
+   disp_regs = mixer->disp_regs;
+   regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_SIZE, size);
+   } else {
+   disp_regs = mixer->engine.regs;
+   regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE, size);
+   }
+   regmap_write(bld_regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
 
if (interlaced)
val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
else
val = 0;
 
-   regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
+   regmap_update_bits(bld_regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
 
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
@@ -400,10 +412,8 @@ static void sun8i_mixer_mode_set(struct sunxi_engine 
*engine,
else
val = 0xff108080;
 
-   regmap_write(mixer->engine.regs,
-SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
-   regmap_write(mixer->engine.regs,
-SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
+   regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
+   regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), 
val);
 
if (mixer->cfg->has_formatter)
sun50i_fmt_setup(mixer, mode->hdisplay,
@@ -443,12 +453,29 @@ static const struct sunxi_engine_ops sun8i_engine_ops = {
 };
 
 static const struct regmap_config sun8i_mixer_regmap_config = {
+   .name   = "layers",
.reg_bits   = 32,
.val_bits   = 32,
.reg_stride = 4,
.max_register   = 0xc, /* guessed */
 };
 
+static const struct regmap_config sun8i_top_regmap_config = {
+   .name   = "top",
+   .reg_bits   = 32,
+   .val_bits   = 32,
+   .reg_stride = 4,
+   .max_register   = 0x3c,
+};
+
+static const struct regmap_config sun8i_disp_regmap_config = {
+   .name   = "display",
+   .reg_bits   = 32,
+   .val_bits   = 32,
+   .reg_stride  

[PATCH v5 22/26] clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support

2024-09-29 Thread Ryan Walklin
The DE33 is a newer version of the Allwinner Display Engine IP block,
found in the H616, H618, H700 and T507 SoCs. DE2 and DE3 are already
supported by the mainline driver.

The DE33 in the H616 has mixer0 and writeback units. The clocks
and resets required are identical to the H3 and H5 respectively, so use
those existing structs for the H616 description.

There are two additional 32-bit registers (at offsets 0x24 and 0x28)
which require clearing and setting respectively to bring up the
hardware. The function of these registers is currently unknown, and the
values are taken from the out-of-tree driver.

Add the required clock description struct and compatible string to the
DE2 driver.

Signed-off-by: Ryan Walklin 

---
Changelog v2..v3:
- Lowercase hex value

Changelog v2..v3:
- Correct #include for writel()

Changelog v4..v5:
- Whitespace fix
---
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 25 +
 1 file changed, 25 insertions(+)

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c 
b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
index 7683ea08d8e30..83eab6f132aad 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -5,6 +5,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -239,6 +240,16 @@ static const struct sunxi_ccu_desc sun50i_h5_de2_clk_desc 
= {
.num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
 };
 
+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,
+
+   .resets = sun50i_h5_de2_resets,
+   .num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
+};
+
 static int sunxi_de2_clk_probe(struct platform_device *pdev)
 {
struct clk *bus_clk, *mod_clk;
@@ -291,6 +302,16 @@ static int sunxi_de2_clk_probe(struct platform_device 
*pdev)
goto err_disable_mod_clk;
}
 
+   /*
+* The DE33 requires these additional (unknown) registers set
+* during initialisation.
+*/
+   if (of_device_is_compatible(pdev->dev.of_node,
+   "allwinner,sun50i-h616-de33-clk")) {
+   writel(0, reg + 0x24);
+   writel(0xa980, reg + 0x28);
+   }
+
ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
if (ret)
goto err_assert_reset;
@@ -335,6 +356,10 @@ static const struct of_device_id sunxi_de2_clk_ids[] = {
.compatible = "allwinner,sun50i-h6-de3-clk",
.data = &sun50i_h5_de2_clk_desc,
},
+   {
+   .compatible = "allwinner,sun50i-h616-de33-clk",
+   .data = &sun50i_h616_de33_clk_desc,
+   },
{ }
 };
 MODULE_DEVICE_TABLE(of, sunxi_de2_clk_ids);
-- 
2.46.1



[PATCH v5 21/26] dt-bindings: allwinner: add H616 DE33 mixer binding

2024-09-29 Thread Ryan Walklin
The Allwinner H616 and variants have a new display engine revision
(DE33).

The mixer configuration registers are significantly different to the DE3
and DE2 revisions, being split into separate top and display blocks,
therefore a fallback for the mixer compatible is not provided.

Add a display engine mixer binding for the DE33.

Signed-off-by: Ryan Walklin 
Acked-by: Conor Dooley 
Reviewed-by: Chen-Yu Tsai 

---
Changelog v2..v3:
- Separate content into three patches for three separate subsystems
---
 .../bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml | 1 +
 1 file changed, 1 insertion(+)

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 b75c1ec686ad2..c37eb8ae1b8ee 100644
--- 
a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
+++ 
b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
@@ -24,6 +24,7 @@ properties:
   - allwinner,sun50i-a64-de2-mixer-0
   - allwinner,sun50i-a64-de2-mixer-1
   - allwinner,sun50i-h6-de3-mixer-0
+  - allwinner,sun50i-h616-de33-mixer-0
 
   reg:
 maxItems: 1
-- 
2.46.1



[PATCH v5 20/26] dt-bindings: allwinner: add H616 DE33 clock binding

2024-09-29 Thread Ryan Walklin
The Allwinner H616 and variants have a new display engine revision
(DE33).

Add a clock binding for the DE33.

Signed-off-by: Ryan Walklin 
Acked-by: Conor Dooley 
Reviewed-by: Chen-Yu Tsai 

---
Changelog v2..v3:
- Separate content into three patches for three separate subsystems
---
 .../devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml  | 1 +
 1 file changed, 1 insertion(+)

diff --git 
a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml 
b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
index 70369bd633e40..7fcd55d468d49 100644
--- a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
+++ b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
@@ -25,6 +25,7 @@ properties:
   - const: allwinner,sun50i-a64-de2-clk
   - const: allwinner,sun50i-h5-de2-clk
   - const: allwinner,sun50i-h6-de3-clk
+  - const: allwinner,sun50i-h616-de33-clk
   - items:
   - const: allwinner,sun8i-r40-de2-clk
   - const: allwinner,sun8i-h3-de2-clk
-- 
2.46.1



[PATCH v5 19/26] dt-bindings: allwinner: add H616 DE33 bus binding

2024-09-29 Thread Ryan Walklin
The Allwinner H616 and variants have a new display engine revision
(DE33).

Add a display engine bus binding for the DE33.

Signed-off-by: Ryan Walklin 
Acked-by: Conor Dooley 
Reviewed-by: Chen-Yu Tsai 

---
Changelog v1..v2:
- Correct DE2 bus enum to reflect fallback devices accurately.

Changelog v2..v3:
- Separate content into three patches for three separate subsystems
---
 .../devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git 
a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml 
b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
index 9845a187bdf65..ea7ee89158c61 100644
--- a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
+++ b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
@@ -24,7 +24,9 @@ properties:
 oneOf:
   - const: allwinner,sun50i-a64-de2
   - items:
-  - const: allwinner,sun50i-h6-de3
+  - enum:
+  - allwinner,sun50i-h6-de3
+  - allwinner,sun50i-h616-de33
   - const: allwinner,sun50i-a64-de2
 
   reg:
-- 
2.46.1



[PATCH v5 18/26] drm: sun4i: de3: Implement AFBC support

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Buffers, compressed with AFBC, are supported by the DE3 and above, and
are generally more efficient for memory transfers. Add support for them.

Currently it's implemented only for VI layers, but vendor code and
documentation suggest UI layers can have them too. However, I haven't
observed any SoC with such feature.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 

---
Changelog v4..v5:
- Correct strict mode warnings from checkpatch.pl
---
 drivers/gpu/drm/sun4i/Makefile |   2 +-
 drivers/gpu/drm/sun4i/sun50i_afbc.c| 250 +
 drivers/gpu/drm/sun4i/sun50i_afbc.h|  87 +
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c |  84 +++--
 4 files changed, 409 insertions(+), 14 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 3f516329f51ee..78290f1660fbd 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -17,7 +17,7 @@ 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 \
-  sun50i_fmt.o
+  sun50i_fmt.o sun50i_afbc.o
 
 sun4i-tcon-y   += sun4i_crtc.o
 sun4i-tcon-y   += sun4i_tcon_dclk.o
diff --git a/drivers/gpu/drm/sun4i/sun50i_afbc.c 
b/drivers/gpu/drm/sun4i/sun50i_afbc.c
new file mode 100644
index 0..b55e1c5533714
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_afbc.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Jernej Skrabec 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "sun50i_afbc.h"
+#include "sun8i_mixer.h"
+
+static u32 sun50i_afbc_get_base(struct sun8i_mixer *mixer, unsigned int 
channel)
+{
+   u32 base = sun8i_channel_base(mixer, channel);
+
+   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   return base + SUN50I_AFBC_CH_OFFSET;
+
+   return base + 0x4000;
+}
+
+bool sun50i_afbc_format_mod_supported(struct sun8i_mixer *mixer,
+ u32 format, u64 modifier)
+{
+   u64 mode;
+
+   if (modifier == DRM_FORMAT_MOD_INVALID)
+   return false;
+
+   if (modifier == DRM_FORMAT_MOD_LINEAR) {
+   if (format == DRM_FORMAT_YUV420_8BIT ||
+   format == DRM_FORMAT_YUV420_10BIT ||
+   format == DRM_FORMAT_Y210)
+   return false;
+   return true;
+   }
+
+   if (mixer->cfg->de_type == sun8i_mixer_de2)
+   return false;
+
+   mode = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+  AFBC_FORMAT_MOD_SPARSE |
+  AFBC_FORMAT_MOD_SPLIT;
+
+   switch (format) {
+   case DRM_FORMAT_RGBA:
+   case DRM_FORMAT_RGB888:
+   case DRM_FORMAT_RGB565:
+   case DRM_FORMAT_RGBA:
+   case DRM_FORMAT_RGBA5551:
+   case DRM_FORMAT_RGBA1010102:
+   mode |= AFBC_FORMAT_MOD_YTR;
+   break;
+   case DRM_FORMAT_YUYV:
+   case DRM_FORMAT_Y210:
+   case DRM_FORMAT_YUV420_8BIT:
+   case DRM_FORMAT_YUV420_10BIT:
+   break;
+   default:
+   return false;
+   }
+
+   return modifier == DRM_FORMAT_MOD_ARM_AFBC(mode);
+}
+
+void sun50i_afbc_atomic_update(struct sun8i_mixer *mixer, unsigned int channel,
+  struct drm_plane *plane)
+{
+   struct drm_plane_state *state = plane->state;
+   struct drm_framebuffer *fb = state->fb;
+   const struct drm_format_info *format = fb->format;
+   struct drm_gem_dma_object *gem;
+   u32 base, val, src_w, src_h;
+   u32 def_color0, def_color1;
+   struct regmap *regs;
+   dma_addr_t dma_addr;
+
+   base = sun50i_afbc_get_base(mixer, channel);
+   regs = mixer->engine.regs;
+
+   src_w = drm_rect_width(&state->src) >> 16;
+   src_h = drm_rect_height(&state->src) >> 16;
+
+   val = SUN50I_FBD_SIZE_HEIGHT(src_h);
+   val |= SUN50I_FBD_SIZE_WIDTH(src_w);
+   regmap_write(regs, SUN50I_FBD_SIZE(base), val);
+
+   val = SUN50I_FBD_BLK_SIZE_HEIGHT(DIV_ROUND_UP(src_h, 16));
+   val = SUN50I_FBD_BLK_SIZE_WIDTH(DIV_ROUND_UP(src_w, 16));
+   regmap_write(regs, SUN50I_FBD_BLK_SIZE(base), val);
+
+   val = SUN50I_FBD_SRC_CROP_TOP(0);
+   val |= SUN50I_FBD_SRC_CROP_LEFT(0);
+   regmap_write(regs, SUN50I_FBD_SRC_CROP(base), val);
+
+   val = SUN50I_FBD_LAY_CROP_TOP(state->src.y1 >> 16);
+   val |= SUN50I_FBD_LAY_CROP_LEFT(state->src.x1 >> 16);
+   regmap_write(regs,

[PATCH v5 17/26] drm: sun4i: de2/de3: use generic register reference function for layer configuration

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Use the new blender register lookup function where required in the layer
commit and update code.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 

---
Changelog v2..v3:
- Refactor for 6.11 layer init/modesetting changes
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c| 5 +++--
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 7 +--
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 6 --
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 18745af089545..600084286b39d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -277,6 +277,7 @@ 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;
@@ -316,8 +317,8 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
}
 
-   regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), 
route);
-   regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
+   regmap_write(bld_regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
+   regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
 pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
 
regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index cb9b694fef101..7f1231cf0f012 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -24,6 +24,7 @@
 #include "sun8i_mixer.h"
 #include "sun8i_ui_layer.h"
 #include "sun8i_ui_scaler.h"
+#include "sun8i_vi_scaler.h"
 
 static void sun8i_ui_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
int overlay, struct drm_plane *plane)
@@ -52,6 +53,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
 {
struct drm_plane_state *state = plane->state;
u32 src_w, src_h, dst_w, dst_h;
+   struct regmap *bld_regs;
u32 bld_base, ch_base;
u32 outsize, insize;
u32 hphase, vphase;
@@ -60,6 +62,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
 channel, overlay);
 
bld_base = sun8i_blender_base(mixer);
+   bld_regs = sun8i_blender_regmap(mixer);
ch_base = sun8i_channel_base(mixer, channel);
 
src_w = drm_rect_width(&state->src) >> 16;
@@ -104,10 +107,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
 state->dst.x1, state->dst.y1);
DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
-   regmap_write(mixer->engine.regs,
+   regmap_write(bld_regs,
 SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
 SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
-   regmap_write(mixer->engine.regs,
+   regmap_write(bld_regs,
 SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
 outsize);
 
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index e348fd0a3d81c..d19349eecc9de 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -55,6 +55,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
struct drm_plane_state *state = plane->state;
const struct drm_format_info *format = state->fb->format;
u32 src_w, src_h, dst_w, dst_h;
+   struct regmap *bld_regs;
u32 bld_base, ch_base;
u32 outsize, insize;
u32 hphase, vphase;
@@ -66,6 +67,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
 channel, overlay);
 
bld_base = sun8i_blender_base(mixer);
+   bld_regs = sun8i_blender_regmap(mixer);
ch_base = sun8i_channel_base(mixer, channel);
 
src_w = drm_rect_width(&state->src) >> 16;
@@ -182,10 +184,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
 state->dst.x1, state->dst.y1);
DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
-   regmap_write(mixer->engine.regs,
+   reg

[PATCH v5 16/26] drm: sun4i: de2/de3: add generic blender register reference function

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

The DE2 and DE3 engines have a blender register range within the
mixer engine register map, whereas the DE33 separates this out into
a separate display group.

Prepare for this by adding a function to look the blender reference up,
with a subsequent patch to add a conditional based on the DE type.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.h | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h 
b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index 82956cb97cfd9..75facc7d1fa66 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -224,6 +224,12 @@ 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->engine.regs;
+}
+
 static inline u32
 sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
 {
-- 
2.46.1



[PATCH v5 15/26] drm: sun4i: vi_scaler refactor vi_scaler enablement

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

If the video scaler is required, then it is obligatory to set the
relevant register to enable it, so move this to the
sun8i_vi_scaler_setup() function.

This simplifies the alternate case (scaler not required) so replace the
vi_scaler_enable() function with a vi_scaler_disable() function.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c  |  3 +--
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 21 +++--
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.h |  2 +-
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 4647e9bcccaa7..e348fd0a3d81c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -156,10 +156,9 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
  dst_h, hscale, vscale, hphase, vphase,
  format);
-   sun8i_vi_scaler_enable(mixer, channel, true);
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
-   sun8i_vi_scaler_enable(mixer, channel, false);
+   sun8i_vi_scaler_disable(mixer, channel);
}
 
regmap_write(mixer->engine.regs,
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index aa346c3beb303..e7242301b312c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -933,20 +933,13 @@ static void sun8i_vi_scaler_set_coeff_ui(struct regmap 
*map, u32 base,
  &table[offset], SUN8I_VI_SCALER_COEFF_COUNT);
 }
 
-void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
+void sun8i_vi_scaler_disable(struct sun8i_mixer *mixer, int layer)
 {
-   u32 val, base;
+   u32 base;
 
base = sun8i_vi_scaler_base(mixer, layer);
 
-   if (enable)
-   val = SUN8I_SCALER_VSU_CTRL_EN |
- SUN8I_SCALER_VSU_CTRL_COEFF_RDY;
-   else
-   val = 0;
-
-   regmap_write(mixer->engine.regs,
-SUN8I_SCALER_VSU_CTRL(base), val);
+   regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base), 0);
 }
 
 void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
@@ -982,6 +975,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int 
layer,
cvphase = vphase;
}
 
+   regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base),
+SUN8I_SCALER_VSU_CTRL_EN);
+
if (mixer->cfg->de_type >= sun8i_mixer_de3) {
u32 val;
 
@@ -1027,4 +1023,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int 
layer,
else
sun8i_vi_scaler_set_coeff_ui(mixer->engine.regs, base,
 hscale, vscale, format);
+
+   if (mixer->cfg->de_type <= sun8i_mixer_de3)
+   regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base),
+SUN8I_SCALER_VSU_CTRL_EN |
+SUN8I_SCALER_VSU_CTRL_COEFF_RDY);
 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
index 68f6593b369ab..e801bc7a4189e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
@@ -69,7 +69,7 @@
 #define SUN50I_SCALER_VSU_ANGLE_SHIFT(x)   (((x) << 16) & 0xF)
 #define SUN50I_SCALER_VSU_ANGLE_OFFSET(x)  ((x) & 0xFF)
 
-void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
+void sun8i_vi_scaler_disable(struct sun8i_mixer *mixer, int layer);
 void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
   u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
   u32 hscale, u32 vscale, u32 hphase, u32 vphase,
-- 
2.46.1



[PATCH v5 14/26] drm: sun4i: de2/de3: refactor mixer initialisation

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Now that the DE variant can be selected by enum, take the oppportunity
to factor out some common initialisation code to a separate function.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 

---
Changelog v1..v2:
- Combine base register allocation and initialisation in sun8i_mixer_init
- Whitespace fix

Changelog v4..v5:
- Remove trailing whitespace
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 64 +++--
 1 file changed, 34 insertions(+), 30 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 16e018aa4aae9..18745af089545 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -468,6 +468,38 @@ static int sun8i_mixer_of_get_id(struct device_node *node)
return of_ep.id;
 }
 
+static void sun8i_mixer_init(struct sun8i_mixer *mixer)
+{
+   unsigned int base = sun8i_blender_base(mixer);
+   int plane_cnt, i;
+
+   /* Enable the mixer */
+   regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
+SUN8I_MIXER_GLOBAL_CTL_RT_EN);
+
+   /* Set background color to black */
+   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(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(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(mixer->engine.regs,
+SUN8I_MIXER_BLEND_MODE(base, i),
+SUN8I_MIXER_BLEND_MODE_DEF);
+
+   regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+  SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
+}
+
 static int sun8i_mixer_bind(struct device *dev, struct device *master,
  void *data)
 {
@@ -476,8 +508,6 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
struct sun4i_drv *drv = drm->dev_private;
struct sun8i_mixer *mixer;
void __iomem *regs;
-   unsigned int base;
-   int plane_cnt;
int i, ret;
 
/*
@@ -581,8 +611,6 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
 
list_add_tail(&mixer->engine.list, &drv->engine_list);
 
-   base = sun8i_blender_base(mixer);
-
/* Reset registers and disable unused sub-engines */
if (mixer->cfg->de_type == sun8i_mixer_de3) {
for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
@@ -598,7 +626,7 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
-   } else {
+   } else if (mixer->cfg->de_type == sun8i_mixer_de2) {
for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
regmap_write(mixer->engine.regs, i, 0);
 
@@ -611,31 +639,7 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
}
 
-   /* Enable the mixer */
-   regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
-SUN8I_MIXER_GLOBAL_CTL_RT_EN);
-
-   /* Set background color to black */
-   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(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
-SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(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(mixer->engine.regs,
-SUN8I_MIXER_BLEND_MODE(base, i),
-SUN8I_MIXER_BLEND_MODE_DEF);
-
-   regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
-  SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
+   sun8i_mixer_init(mixer);
 
return 0;
 
-- 
2.46.1



[PATCH v5 13/26] drm: sun4i: de2/de3: add mixer version enum

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

The Allwinner DE2 and DE3 display engine mixers are currently identified
by a simple boolean flag. This will not scale to support additional DE
variants.

Convert the boolean flag to an enum.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c   |  2 +-
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 14 --
 drivers/gpu/drm/sun4i/sun8i_mixer.h | 11 ---
 drivers/gpu/drm/sun4i/sun8i_ui_scaler.c |  2 +-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c  |  8 
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c |  4 ++--
 6 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index e12a81fa91083..2d5a2cf7cba24 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -365,7 +365,7 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
 {
u32 base;
 
-   if (mixer->cfg->is_de3) {
+   if (mixer->cfg->de_type == sun8i_mixer_de3) {
sun8i_de3_ccsc_setup(&mixer->engine, layer,
 fmt_type, encoding, range);
return;
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index a50c583852edf..16e018aa4aae9 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -584,7 +584,7 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
base = sun8i_blender_base(mixer);
 
/* Reset registers and disable unused sub-engines */
-   if (mixer->cfg->is_de3) {
+   if (mixer->cfg->de_type == sun8i_mixer_de3) {
for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
regmap_write(mixer->engine.regs, i, 0);
 
@@ -675,6 +675,7 @@ static void sun8i_mixer_remove(struct platform_device *pdev)
 
 static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.scaler_mask= 0xf,
.scanline_yuv   = 2048,
.ui_num = 3,
@@ -683,6 +684,7 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = 
{
 
 static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
.ccsc   = CCSC_MIXER1_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.scaler_mask= 0x3,
.scanline_yuv   = 2048,
.ui_num = 1,
@@ -691,6 +693,7 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = 
{
 
 static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 43200,
.scaler_mask= 0xf,
.scanline_yuv   = 2048,
@@ -700,6 +703,7 @@ static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
 
 static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0xf,
.scanline_yuv   = 2048,
@@ -709,6 +713,7 @@ static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
 
 static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
.ccsc   = CCSC_MIXER1_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0x3,
.scanline_yuv   = 2048,
@@ -717,6 +722,7 @@ static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
 };
 
 static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
+   .de_type = sun8i_mixer_de2,
.vi_num = 2,
.ui_num = 1,
.scaler_mask = 0x3,
@@ -727,6 +733,7 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
 
 static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
.ccsc   = CCSC_D1_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0x3,
.scanline_yuv   = 2048,
@@ -736,6 +743,7 @@ static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
 
 static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
.ccsc   = CCSC_MIXER1_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0x1,
.scanline_yuv   = 1024,
@@ -745,6 +753,7 @@ static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
 
 static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0xf,
.scanline_yuv   = 4096,
@@ -754,6 +763,7 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = 
{
 
 static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
.ccsc   =

[PATCH v5 12/26] drm: sun4i: support YUV formats in VI scaler

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Now that YUV formats are available, enable support in the VI scaler.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 

Changelog v4..v5:
- Add commit description
---
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 85 +
 1 file changed, 58 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index 7ba75011adf9f..2e49a6e5f1f1c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -843,6 +843,11 @@ static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, 
int channel)
   DE2_VI_SCALER_UNIT_SIZE * channel;
 }
 
+static bool sun8i_vi_scaler_is_vi_plane(struct sun8i_mixer *mixer, int channel)
+{
+   return true;
+}
+
 static int sun8i_vi_scaler_coef_index(unsigned int step)
 {
unsigned int scale, int_part, float_part;
@@ -867,44 +872,65 @@ static int sun8i_vi_scaler_coef_index(unsigned int step)
}
 }
 
-static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base,
- u32 hstep, u32 vstep,
- const struct drm_format_info *format)
+static void sun8i_vi_scaler_set_coeff_vi(struct regmap *map, u32 base,
+u32 hstep, u32 vstep,
+const struct drm_format_info *format)
 {
const u32 *ch_left, *ch_right, *cy;
-   int offset, i;
+   int offset;
 
-   if (format->hsub == 1 && format->vsub == 1) {
-   ch_left = lan3coefftab32_left;
-   ch_right = lan3coefftab32_right;
-   cy = lan2coefftab32;
-   } else {
+   if (format->is_yuv) {
ch_left = bicubic8coefftab32_left;
ch_right = bicubic8coefftab32_right;
cy = bicubic4coefftab32;
+   } else {
+   ch_left = lan3coefftab32_left;
+   ch_right = lan3coefftab32_right;
+   cy = lan2coefftab32;
}
 
offset = sun8i_vi_scaler_coef_index(hstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
-   for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
-   regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, i),
-lan3coefftab32_left[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
-lan3coefftab32_right[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),
-ch_left[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),
-ch_right[offset + i]);
-   }
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, 0),
+ &lan3coefftab32_left[offset],
+ SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, 0),
+ &lan3coefftab32_right[offset],
+ SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, 0),
+ &ch_left[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, 0),
+ &ch_right[offset], SUN8I_VI_SCALER_COEFF_COUNT);
 
offset = sun8i_vi_scaler_coef_index(hstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
-   for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
-   regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
-lan2coefftab32[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
-cy[offset + i]);
-   }
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, 0),
+ &cy[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+}
+
+static void sun8i_vi_scaler_set_coeff_ui(struct regmap *map, u32 base,
+u32 hstep, u32 vstep,
+const struct drm_format_info *format)
+{
+   const u32 *table;
+   int offset;
+
+   offset = sun8i_vi_scaler_coef_index(hstep) *
+   SUN8I_VI_SCALER_COEFF_COUNT;
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+   offset = sun8i_vi_scaler_coef_index(vstep) *
+   SUN8I_VI_SCALER_COEFF_COUNT;
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+
+   table = format->is

[PATCH v5 11/26] drm: sun4i: de3: add YUV support to the TCON

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Account for U/V channel subsampling by reducing the dot clock and
resolution with a divider in the DE3 timing controller if a YUV format
is selected.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 +++---
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c 
b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index a1a2c845ade0c..e39926e9f0b5d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -598,14 +598,26 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon 
*tcon,
 static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
 const struct drm_display_mode *mode)
 {
-   unsigned int bp, hsync, vsync, vtotal;
+   unsigned int bp, hsync, vsync, vtotal, div;
+   struct sun4i_crtc *scrtc = tcon->crtc;
+   struct sunxi_engine *engine = scrtc->engine;
u8 clk_delay;
u32 val;
 
WARN_ON(!tcon->quirks->has_channel_1);
 
+   switch (engine->format) {
+   case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+   case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+   div = 2;
+   break;
+   default:
+   div = 1;
+   break;
+   }
+
/* Configure the dot clock */
-   clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
+   clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000 / div);
 
/* Adjust clock delay */
clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
@@ -624,17 +636,17 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
 
/* Set the input resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
-SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
+SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay / div) |
 SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
 
/* Set the upscaling resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
-SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
+SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay / div) |
 SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
 
/* Set the output resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
-SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
+SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay / div) |
 SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
 
/* Set horizontal display timings */
@@ -642,8 +654,8 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
 mode->htotal, bp);
regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
-SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
-SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
+SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal / div) |
+SUN4I_TCON1_BASIC3_H_BACKPORCH(bp / div));
 
bp = mode->crtc_vtotal - mode->crtc_vsync_start;
DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
-- 
2.46.1



[PATCH v5 10/26] drm: sun4i: de3: add YUV support to the color space correction module

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Add coefficients and support for YUV formats to the display engine
colorspace and dynamic range correction submodule.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c | 164 +-
 1 file changed, 162 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 8a336ccb27d33..e12a81fa91083 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -5,6 +5,8 @@
 
 #include 
 
+#include 
+
 #include "sun8i_csc.h"
 #include "sun8i_mixer.h"
 
@@ -107,6 +109,135 @@ static const u32 yuv2rgb_de3[2][3][12] = {
},
 };
 
+/* always convert to limited mode */
+static const u32 rgb2yuv_de3[3][12] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x837A, 0x0001021D, 0x3221, 0x0040,
+   0xB41C, 0x6B03, 0xE0E1, 0x0200,
+   0xE0E1, 0x43B1, 0xDB6E, 0x0200,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x5D7C, 0x00013A7C, 0x1FBF, 0x0040,
+   0xCC78, 0x52A7, 0xE0E1, 0x0200,
+   0xE0E1, 0x33BE, 0xEB61, 0x0200,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x7384, 0x00012A21, 0x1A13, 0x0040,
+   0xC133, 0x5DEC, 0xE0E1, 0x0200,
+   0xE0E1, 0x3135, 0xEDEA, 0x0200,
+   },
+};
+
+/* always convert to limited mode */
+static const u32 yuv2yuv_de3[2][3][3][12] = {
+   [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0002, 0x, 0x, 0x,
+   0x, 0x0002, 0x, 0x,
+   0x, 0x, 0x0002, 0x,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x0002, 0xC4D7, 0x9589, 0xFFC00040,
+   0x, 0x0002098B, 0x3AAF, 0xFE000200,
+   0x, 0x266D, 0x00020CF8, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x0002, 0xBFCE, 0xC5FF, 0xFFC00040,
+   0x, 0x00020521, 0x1F89, 0xFE000200,
+   0x, 0x2C87, 0x00020F07, 0xFE000200,
+   },
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0002, 0x32D9, 0x6226, 0xFFC00040,
+   0x, 0x0001FACE, 0xC759, 0xFE000200,
+   0x, 0xDAE7, 0x0001F780, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x0002, 0x, 0x, 0x,
+   0x, 0x0002, 0x, 0x,
+   0x, 0x, 0x0002, 0x,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x0002, 0xF782, 0x3036, 0xFFC00040,
+   0x, 0x0001FD99, 0xE5CA, 0xFE000200,
+   0x, 0x05E4, 0x0002015A, 0xFE000200,
+   },
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0002, 0x3B03, 0x34D2, 0xFFC00040,
+   0x, 0x0001FD8C, 0xE183, 0xFE000200,
+   0x, 0xD4F3, 0x0001F3FA, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x0002, 0x0916, 0xD061, 0xFFC00040,
+   0x, 0x0002021C, 0x1A40, 0xFE000200,
+   0x, 0xFA19, 0x0001FE5A, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x0002, 0x, 0x, 0x,
+   0x, 0x0002, 0x, 0x,
+   0x, 0x, 0x0002, 0x,
+   },
+   },
+   },
+   [DRM_COLOR_YCBCR_FULL_RANGE] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0001B7B8, 0x, 0x, 0x0040,
+   0x

[PATCH v5 09/26] drm: sun4i: de3: pass engine reference to ccsc setup function

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Configuration of the DE3 colorspace and dynamic range correction module
requires knowledge of the current video format and encoding.

Pass the display engine by reference to the csc setup function, rather
than the register map alone, to allow access to this information.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 68d955c63b05b..8a336ccb27d33 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -148,17 +148,19 @@ static void sun8i_csc_setup(struct regmap *map, u32 base,
regmap_write(map, SUN8I_CSC_CTRL(base), val);
 }
 
-static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
+static void sun8i_de3_ccsc_setup(struct sunxi_engine *engine, int layer,
 enum format_type fmt_type,
 enum drm_color_encoding encoding,
 enum drm_color_range range)
 {
u32 addr, val, mask;
+   struct regmap *map;
const u32 *table;
int i;
 
mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
table = yuv2rgb_de3[range][encoding];
+   map = engine->regs;
 
switch (fmt_type) {
case FORMAT_TYPE_RGB:
@@ -204,7 +206,7 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
u32 base;
 
if (mixer->cfg->is_de3) {
-   sun8i_de3_ccsc_setup(mixer->engine.regs, layer,
+   sun8i_de3_ccsc_setup(&mixer->engine, layer,
 fmt_type, encoding, range);
return;
}
-- 
2.46.1



[PATCH v5 08/26] drm: sun4i: de3: add YUV support to the DE3 mixer

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

The mixer in the DE3 display engine supports YUV 8 and 10 bit
formats in addition to 8-bit RGB. Add the required register
configuration and format enumeration callback functions to the mixer,
and store the in-use output format (defaulting to RGB) and color
encoding in engine variables.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 

---
Changelog v4..v5:
- Remove trailing whitespace
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c  | 53 ++--
 drivers/gpu/drm/sun4i/sunxi_engine.h |  5 +++
 2 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 252827715de1d..a50c583852edf 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -23,7 +23,10 @@
 #include 
 #include 
 
+#include 
+
 #include "sun4i_drv.h"
+#include "sun50i_fmt.h"
 #include "sun8i_mixer.h"
 #include "sun8i_ui_layer.h"
 #include "sun8i_vi_layer.h"
@@ -390,12 +393,52 @@ static void sun8i_mixer_mode_set(struct sunxi_engine 
*engine,
 
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
 interlaced ? "on" : "off");
+
+   if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
+   val = SUN8I_MIXER_BLEND_COLOR_BLACK;
+   else
+   val = 0xff108080;
+
+   regmap_write(mixer->engine.regs,
+SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
+   regmap_write(mixer->engine.regs,
+SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
+
+   if (mixer->cfg->has_formatter)
+   sun50i_fmt_setup(mixer, mode->hdisplay,
+mode->vdisplay, mixer->engine.format);
+}
+
+static u32 *sun8i_mixer_get_supported_fmts(struct sunxi_engine *engine, u32 
*num)
+{
+   struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+   u32 *formats, count;
+
+   count = 0;
+
+   formats = kcalloc(5, sizeof(*formats), GFP_KERNEL);
+   if (!formats)
+   return NULL;
+
+   if (mixer->cfg->has_formatter) {
+   formats[count++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
+   formats[count++] = MEDIA_BUS_FMT_YUV8_1X24;
+   formats[count++] = MEDIA_BUS_FMT_UYVY8_1X16;
+   formats[count++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+   }
+
+   formats[count++] = MEDIA_BUS_FMT_RGB888_1X24;
+
+   *num = count;
+
+   return formats;
 }
 
 static const struct sunxi_engine_ops sun8i_engine_ops = {
-   .commit = sun8i_mixer_commit,
-   .layers_init= sun8i_layers_init,
-   .mode_set   = sun8i_mixer_mode_set,
+   .commit = sun8i_mixer_commit,
+   .layers_init= sun8i_layers_init,
+   .mode_set   = sun8i_mixer_mode_set,
+   .get_supported_fmts = sun8i_mixer_get_supported_fmts,
 };
 
 static const struct regmap_config sun8i_mixer_regmap_config = {
@@ -456,6 +499,10 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
dev_set_drvdata(dev, mixer);
mixer->engine.ops = &sun8i_engine_ops;
mixer->engine.node = dev->of_node;
+   /* default output format, supported by all mixers */
+   mixer->engine.format = MEDIA_BUS_FMT_RGB888_1X24;
+   /* default color encoding, ignored with RGB I/O */
+   mixer->engine.encoding = DRM_COLOR_YCBCR_BT601;
 
if (of_property_present(dev->of_node, "iommus")) {
/*
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h 
b/drivers/gpu/drm/sun4i/sunxi_engine.h
index c48cbc1aceb80..ffafc29b3a0c3 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -6,6 +6,8 @@
 #ifndef _SUNXI_ENGINE_H_
 #define _SUNXI_ENGINE_H_
 
+#include 
+
 struct drm_plane;
 struct drm_crtc;
 struct drm_device;
@@ -151,6 +153,9 @@ struct sunxi_engine {
 
int id;
 
+   u32 format;
+   enum drm_color_encoding encoding;
+
/* Engine list management */
struct list_headlist;
 };
-- 
2.46.1



[PATCH v5 07/26] drm: sun4i: de3: add formatter flag to mixer config

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Only the DE3 (and newer) display engines have a formatter module. This
could be inferred from the is_de3 flag alone, however this will not
scale with addition of future DE versions in subsequent patches.

Add a separate flag to signal this in the mixer configuration.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 1 +
 drivers/gpu/drm/sun4i/sun8i_mixer.h | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index bd0fe2c6624e6..252827715de1d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -717,6 +717,7 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = 
{
 static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
.is_de3 = true,
+   .has_formatter  = 1,
.mod_rate   = 6,
.scaler_mask= 0xf,
.scanline_yuv   = 4096,
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h 
b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index d7898c9c9cc0c..8417b8fef2e1f 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -163,6 +163,7 @@ enum {
  * @mod_rate: module clock rate that needs to be set in order to have
  * a functional block.
  * @is_de3: true, if this is next gen display engine 3.0, false otherwise.
+ * @has_formatter: true, if mixer has formatter core, for 10-bit and YUV 
handling
  * @scaline_yuv: size of a scanline for VI scaler for YUV formats.
  */
 struct sun8i_mixer_cfg {
@@ -172,6 +173,7 @@ struct sun8i_mixer_cfg {
int ccsc;
unsigned long   mod_rate;
unsigned intis_de3 : 1;
+   unsigned inthas_formatter : 1;
unsigned intscanline_yuv;
 };
 
-- 
2.46.1



[PATCH v5 06/26] drm: sun4i: de3: add format enumeration function to engine

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

The DE3 display engine supports YUV formats in addition to RGB.

Add an optional format enumeration function to the engine.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sunxi_engine.h | 29 
 1 file changed, 29 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h 
b/drivers/gpu/drm/sun4i/sunxi_engine.h
index ec0c4932f15cf..c48cbc1aceb80 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -123,6 +123,17 @@ struct sunxi_engine_ops {
 */
void (*mode_set)(struct sunxi_engine *engine,
 const struct drm_display_mode *mode);
+
+   /**
+* @get_supported_fmts
+*
+* This callback is used to enumerate all supported output
+* formats by the engine. They are used for bridge format
+* negotiation.
+*
+* This function is optional.
+*/
+   u32 *(*get_supported_fmts)(struct sunxi_engine *engine, u32 *num);
 };
 
 /**
@@ -215,4 +226,22 @@ sunxi_engine_mode_set(struct sunxi_engine *engine,
if (engine->ops && engine->ops->mode_set)
engine->ops->mode_set(engine, mode);
 }
+
+/**
+ * sunxi_engine_get_supported_formats - Provide array of supported formats
+ * @engine:pointer to the engine
+ * @num:   pointer to variable, which will hold number of formats
+ *
+ * This list can be used for format negotiation by bridge.
+ */
+static inline u32 *
+sunxi_engine_get_supported_formats(struct sunxi_engine *engine, u32 *num)
+{
+   if (engine->ops && engine->ops->get_supported_fmts)
+   return engine->ops->get_supported_fmts(engine, num);
+
+   *num = 0;
+
+   return NULL;
+}
 #endif /* _SUNXI_ENGINE_H_ */
-- 
2.46.1



[PATCH v5 05/26] drm: sun4i: de3: Add YUV formatter module

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

The display engine formatter (FMT) module is present in the DE3 engine
and provides YUV444 to YUV422/YUV420 conversion, format re-mapping and
color depth conversion.

Add support for this module.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/Makefile |  3 +-
 drivers/gpu/drm/sun4i/sun50i_fmt.c | 82 ++
 drivers/gpu/drm/sun4i/sun50i_fmt.h | 32 
 3 files changed, 116 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index bad7497a0d11e..3f516329f51ee 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_fmt.o
 
 sun4i-tcon-y   += sun4i_crtc.o
 sun4i-tcon-y   += sun4i_tcon_dclk.o
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.c 
b/drivers/gpu/drm/sun4i/sun50i_fmt.c
new file mode 100644
index 0..050a8716ae862
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Jernej Skrabec 
+ */
+
+#include 
+
+#include "sun50i_fmt.h"
+
+static bool sun50i_fmt_is_10bit(u32 format)
+{
+   switch (format) {
+   case MEDIA_BUS_FMT_RGB101010_1X30:
+   case MEDIA_BUS_FMT_YUV10_1X30:
+   case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+   case MEDIA_BUS_FMT_UYVY10_1X20:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static u32 sun50i_fmt_get_colorspace(u32 format)
+{
+   switch (format) {
+   case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+   case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+   return SUN50I_FMT_CS_YUV420;
+   case MEDIA_BUS_FMT_UYVY8_1X16:
+   case MEDIA_BUS_FMT_UYVY10_1X20:
+   return SUN50I_FMT_CS_YUV422;
+   default:
+   return SUN50I_FMT_CS_YUV444RGB;
+   }
+}
+
+static void sun50i_fmt_de3_limits(u32 *limits, u32 colorspace, bool bit10)
+{
+   if (colorspace != SUN50I_FMT_CS_YUV444RGB) {
+   limits[0] = SUN50I_FMT_LIMIT(64, 940);
+   limits[1] = SUN50I_FMT_LIMIT(64, 960);
+   limits[2] = SUN50I_FMT_LIMIT(64, 960);
+   } else if (bit10) {
+   limits[0] = SUN50I_FMT_LIMIT(0, 1023);
+   limits[1] = SUN50I_FMT_LIMIT(0, 1023);
+   limits[2] = SUN50I_FMT_LIMIT(0, 1023);
+   } else {
+   limits[0] = SUN50I_FMT_LIMIT(0, 1021);
+   limits[1] = SUN50I_FMT_LIMIT(0, 1021);
+   limits[2] = SUN50I_FMT_LIMIT(0, 1021);
+   }
+}
+
+void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
+ u16 height, u32 format)
+{
+   u32 colorspace, limit[3], base;
+   struct regmap *regs;
+   bool bit10;
+
+   colorspace = sun50i_fmt_get_colorspace(format);
+   bit10 = sun50i_fmt_is_10bit(format);
+   base = SUN50I_FMT_DE3;
+   regs = sun8i_blender_regmap(mixer);
+
+   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+
+   regmap_write(regs, SUN50I_FMT_CTRL(base), 0);
+
+   regmap_write(regs, SUN50I_FMT_SIZE(base),
+SUN8I_MIXER_SIZE(width, height));
+   regmap_write(regs, SUN50I_FMT_SWAP(base), 0);
+   regmap_write(regs, SUN50I_FMT_DEPTH(base), bit10);
+   regmap_write(regs, SUN50I_FMT_FORMAT(base), colorspace);
+   regmap_write(regs, SUN50I_FMT_COEF(base), 0);
+
+   regmap_write(regs, SUN50I_FMT_LMT_Y(base), limit[0]);
+   regmap_write(regs, SUN50I_FMT_LMT_C0(base), limit[1]);
+   regmap_write(regs, SUN50I_FMT_LMT_C1(base), limit[2]);
+
+   regmap_write(regs, SUN50I_FMT_CTRL(base), 1);
+}
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.h 
b/drivers/gpu/drm/sun4i/sun50i_fmt.h
new file mode 100644
index 0..4127f7206aade
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) Jernej Skrabec 
+ */
+
+#ifndef _SUN50I_FMT_H_
+#define _SUN50I_FMT_H_
+
+#include "sun8i_mixer.h"
+
+#define SUN50I_FMT_DE3 0xa8000
+
+#define SUN50I_FMT_CTRL(base)   ((base) + 0x00)
+#define SUN50I_FMT_SIZE(base)   ((base) + 0x04)
+#define SUN50I_FMT_SWAP(base)   ((base) + 0x08)
+#define SUN50I_FMT_DEPTH(base)  ((base) + 0x0c)
+#define SUN50I_FMT_FORMAT(base) ((base) + 0x10)
+#define SUN50I_FMT_COEF(base)   ((base) + 0x14)
+#define SUN50I_FMT_LMT_Y(base)  ((base) + 0x20)
+#define SUN50I_FMT_LMT_C0(base) ((ba

[PATCH v5 04/26] drm: sun4i: de2: Initialize layer fields earlier

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

drm_universal_plane_init() can already call some callbacks, like
format_mod_supported, during initialization. Because of that, fields
should be initialized beforehand.

Signed-off-by: Jernej Skrabec 
Co-developed-by: Ryan Walklin 
Signed-off-by: Ryan Walklin 
Reviewed-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 9 +
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 9 +
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index aa987bca1dbb9..cb9b694fef101 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -295,6 +295,11 @@ struct sun8i_layer *sun8i_ui_layer_init_one(struct 
drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
 
+   layer->mixer = mixer;
+   layer->type = SUN8I_LAYER_TYPE_UI;
+   layer->channel = channel;
+   layer->overlay = 0;
+
if (index == 0)
type = DRM_PLANE_TYPE_PRIMARY;
 
@@ -325,10 +330,6 @@ struct sun8i_layer *sun8i_ui_layer_init_one(struct 
drm_device *drm,
}
 
drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs);
-   layer->mixer = mixer;
-   layer->type = SUN8I_LAYER_TYPE_UI;
-   layer->channel = channel;
-   layer->overlay = 0;
 
return layer;
 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index f3a5329351caa..3c657b069d1f4 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -478,6 +478,11 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct 
drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
 
+   layer->mixer = mixer;
+   layer->type = SUN8I_LAYER_TYPE_VI;
+   layer->channel = index;
+   layer->overlay = 0;
+
if (mixer->cfg->is_de3) {
formats = sun8i_vi_layer_de3_formats;
format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
@@ -536,10 +541,6 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct 
drm_device *drm,
}
 
drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
-   layer->mixer = mixer;
-   layer->type = SUN8I_LAYER_TYPE_VI;
-   layer->channel = index;
-   layer->overlay = 0;
 
return layer;
 }
-- 
2.46.1



[PATCH v5 03/26] drm: sun4i: de2/de3: call csc setup also for UI layer

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Currently, only VI layer calls CSC setup function. This comes from DE2
limitation, which doesn't have CSC unit for UI layers. However, DE3 has
separate CSC units for each layer. This allows display pipeline to make
output signal in different color spaces. To support both use cases, add
a call to CSC setup function also in UI layer code. For DE2, this will
be a no-op, but it will allow DE3 to output signal in multiple formats.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c  | 8 +---
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 6 ++
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 0dcbc0866ae82..68d955c63b05b 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -209,8 +209,10 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
return;
}
 
-   base = ccsc_base[mixer->cfg->ccsc][layer];
+   if (layer < mixer->cfg->vi_num) {
+   base = ccsc_base[mixer->cfg->ccsc][layer];
 
-   sun8i_csc_setup(mixer->engine.regs, base,
-   fmt_type, encoding, range);
+   sun8i_csc_setup(mixer->engine.regs, base,
+   fmt_type, encoding, range);
+   }
 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index b90e5edef4e88..aa987bca1dbb9 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -20,6 +20,7 @@
 #include 
 #include 
 
+#include "sun8i_csc.h"
 #include "sun8i_mixer.h"
 #include "sun8i_ui_layer.h"
 #include "sun8i_ui_scaler.h"
@@ -135,6 +136,11 @@ static int sun8i_ui_layer_update_formats(struct 
sun8i_mixer *mixer, int channel,
   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
 
+   /* Note: encoding and range arguments are ignored for RGB */
+   sun8i_csc_set_ccsc(mixer, channel, FORMAT_TYPE_RGB,
+  DRM_COLOR_YCBCR_BT601,
+  DRM_COLOR_YCBCR_FULL_RANGE);
+
return 0;
 }
 
-- 
2.46.1



[PATCH v5 01/26] drm: sun4i: de2/de3: Change CSC argument

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

Currently, CSC module takes care only for converting YUV to RGB.
However, DE3 is more suited to work in YUV color space. Change CSC mode
argument to format type to be more neutral. New argument only tells
layer format type and doesn't imply output type.

This commit doesn't make any functional change.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c  | 22 +++---
 drivers/gpu/drm/sun4i/sun8i_csc.h  | 10 +-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 16 
 3 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 58480d8e4f704..6ebd1c3aa3ab5 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -108,7 +108,7 @@ static const u32 yuv2rgb_de3[2][3][12] = {
 };
 
 static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
-  enum sun8i_csc_mode mode,
+  enum format_type fmt_type,
   enum drm_color_encoding encoding,
   enum drm_color_range range)
 {
@@ -118,12 +118,12 @@ static void sun8i_csc_set_coefficients(struct regmap 
*map, u32 base,
 
table = yuv2rgb[range][encoding];
 
-   switch (mode) {
-   case SUN8I_CSC_MODE_YUV2RGB:
+   switch (fmt_type) {
+   case FORMAT_TYPE_YUV:
base_reg = SUN8I_CSC_COEFF(base, 0);
regmap_bulk_write(map, base_reg, table, 12);
break;
-   case SUN8I_CSC_MODE_YVU2RGB:
+   case FORMAT_TYPE_YVU:
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
base_reg = SUN8I_CSC_COEFF(base, i + 1);
@@ -141,7 +141,7 @@ static void sun8i_csc_set_coefficients(struct regmap *map, 
u32 base,
 }
 
 static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
-   enum sun8i_csc_mode mode,
+   enum format_type fmt_type,
enum drm_color_encoding encoding,
enum drm_color_range range)
 {
@@ -151,12 +151,12 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap 
*map, int layer,
 
table = yuv2rgb_de3[range][encoding];
 
-   switch (mode) {
-   case SUN8I_CSC_MODE_YUV2RGB:
+   switch (fmt_type) {
+   case FORMAT_TYPE_YUV:
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, addr, table, 12);
break;
-   case SUN8I_CSC_MODE_YVU2RGB:
+   case FORMAT_TYPE_YVU:
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
addr = 
SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
@@ -206,7 +206,7 @@ static void sun8i_de3_ccsc_enable(struct regmap *map, int 
layer, bool enable)
 }
 
 void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
-enum sun8i_csc_mode mode,
+enum format_type fmt_type,
 enum drm_color_encoding encoding,
 enum drm_color_range range)
 {
@@ -214,14 +214,14 @@ void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer 
*mixer, int layer,
 
if (mixer->cfg->is_de3) {
sun8i_de3_ccsc_set_coefficients(mixer->engine.regs, layer,
-   mode, encoding, range);
+   fmt_type, encoding, range);
return;
}
 
base = ccsc_base[mixer->cfg->ccsc][layer];
 
sun8i_csc_set_coefficients(mixer->engine.regs, base,
-  mode, encoding, range);
+  fmt_type, encoding, range);
 }
 
 void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h 
b/drivers/gpu/drm/sun4i/sun8i_csc.h
index 828b86fd0cabb..7322770f39f03 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
@@ -22,14 +22,14 @@ struct sun8i_mixer;
 
 #define SUN8I_CSC_CTRL_EN  BIT(0)
 
-enum sun8i_csc_mode {
-   SUN8I_CSC_MODE_OFF,
-   SUN8I_CSC_MODE_YUV2RGB,
-   SUN8I_CSC_MODE_YVU2RGB,
+enum format_type {
+   FORMAT_TYPE_RGB,
+   FORMAT_TYPE_YUV,
+   FORMAT_TYPE_YVU,
 };
 
 void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
-enum sun8i_csc_mode mode,
+enum format_type fmt_type,
   

[PATCH v5 02/26] drm: sun4i: de2/de3: Merge CSC functions into one

2024-09-29 Thread Ryan Walklin
From: Jernej Skrabec 

At the moment the colour space conversion is handled by two functions:
one to setup the conversion parameters, and another one to enable the
conversion. Merging both into one gives more flexibility for upcoming
extensions to support whole YUV pipelines, in the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c  | 89 ++
 drivers/gpu/drm/sun4i/sun8i_csc.h  |  9 ++-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 11 +---
 3 files changed, 40 insertions(+), 69 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 6ebd1c3aa3ab5..0dcbc0866ae82 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -107,23 +107,28 @@ static const u32 yuv2rgb_de3[2][3][12] = {
},
 };
 
-static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
-  enum format_type fmt_type,
-  enum drm_color_encoding encoding,
-  enum drm_color_range range)
+static void sun8i_csc_setup(struct regmap *map, u32 base,
+   enum format_type fmt_type,
+   enum drm_color_encoding encoding,
+   enum drm_color_range range)
 {
+   u32 base_reg, val;
const u32 *table;
-   u32 base_reg;
int i;
 
table = yuv2rgb[range][encoding];
 
switch (fmt_type) {
+   case FORMAT_TYPE_RGB:
+   val = 0;
+   break;
case FORMAT_TYPE_YUV:
+   val = SUN8I_CSC_CTRL_EN;
base_reg = SUN8I_CSC_COEFF(base, 0);
regmap_bulk_write(map, base_reg, table, 12);
break;
case FORMAT_TYPE_YVU:
+   val = SUN8I_CSC_CTRL_EN;
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
base_reg = SUN8I_CSC_COEFF(base, i + 1);
@@ -135,28 +140,37 @@ static void sun8i_csc_set_coefficients(struct regmap 
*map, u32 base,
}
break;
default:
+   val = 0;
DRM_WARN("Wrong CSC mode specified.\n");
return;
}
+
+   regmap_write(map, SUN8I_CSC_CTRL(base), val);
 }
 
-static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
-   enum format_type fmt_type,
-   enum drm_color_encoding encoding,
-   enum drm_color_range range)
+static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
+enum format_type fmt_type,
+enum drm_color_encoding encoding,
+enum drm_color_range range)
 {
+   u32 addr, val, mask;
const u32 *table;
-   u32 addr;
int i;
 
+   mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
table = yuv2rgb_de3[range][encoding];
 
switch (fmt_type) {
+   case FORMAT_TYPE_RGB:
+   val = 0;
+   break;
case FORMAT_TYPE_YUV:
+   val = mask;
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, addr, table, 12);
break;
case FORMAT_TYPE_YVU:
+   val = mask;
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
addr = 
SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
@@ -173,67 +187,30 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap 
*map, int layer,
}
break;
default:
+   val = 0;
DRM_WARN("Wrong CSC mode specified.\n");
return;
}
-}
-
-static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
-{
-   u32 val;
-
-   if (enable)
-   val = SUN8I_CSC_CTRL_EN;
-   else
-   val = 0;
-
-   regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
-}
-
-static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable)
-{
-   u32 val, mask;
-
-   mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
-
-   if (enable)
-   val = mask;
-   else
-   val = 0;
 
regmap_update_bits(map, SUN50I_MIXER_BLEND_CSC_CTL(DE3_BLD_BASE),
   mask, val);
 }
 
-void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
-enum format_type fmt_type,
-enum drm_color_encoding encoding,
-enum drm_color_range range)
-{
-   u32 base

[PATCH v5 00/26] drm: sun4i: add Display Engine 3.3 (DE33) support

2024-09-29 Thread Ryan Walklin
Hi,

V5 of this patch series adding support for the Allwinner DE33 display engine 
variant. V5 is rebased on torvalds/master as of today with the 6.12 drm-next 
patches included, with no code changes required. V3 and V4 were in turn rebased 
on top of the layer init and modesetting changes merged for 6.11. No functional 
changes from V4, fixes and reviews from previous V1-4 added, and relevant 
issues found by checkpatch.pl corrected.

Original blurb below:

There is existing mainline support for the DE2 and DE3 AllWinner display 
pipeline IP blocks, used in the A64 and H6 among others, however the H700 (as 
well as the H616/H618 and the T507 automotive SoC) have a newer version of the 
Display Engine (v3.3/DE33) which adds additional high-resolution support as 
well as YUV colour formats and AFBC compression support.

This patch set adds DE33 support, following up from the previous RFC [1], with 
significant rework to break down the previous relatively complex set into more 
logical steps, detailed below.

1. Refactor the existing DE2/DE3 code in readiness to support YUV colour 
formats in the DE3 engine (patches 1-4).
2. Add YUV420 colour format support in the DE3 driver (patches 5-12).
3. Replace the is_de3 mixer flag with an enum to support multiple DE versions 
(patch 13).
4. Refactor the mixer, vi_scaler and some register code to merge common init 
code and more easily support multiple DE versions (patches 14-17).
5. Add Arm Frame Buffer Compression (AFBC) compressed buffer support to the DE3 
driver. This is currently only supported for VI layers (for HW-decoded video 
output) but is well integrated into these changes and a subsequent patchset to 
enable the Video Engine is planned. (patch 18).
6. Add DT bindings for the DE33 engine. (patches 19-21).
7. Extend the DE2/3 driver for the DE33, comprising clock, mixer, vi_scaler, 
fmt and csc module support (patches 22-26).

Further patchsets are planned to support HDMI and the LCD timing controller 
present in these SoCs.

Regards,

Ryan

Jernej Skrabec (22):
  drm: sun4i: de2/de3: Change CSC argument
  drm: sun4i: de2/de3: Merge CSC functions into one
  drm: sun4i: de2/de3: call csc setup also for UI layer
  drm: sun4i: de2: Initialize layer fields earlier
  drm: sun4i: de3: Add YUV formatter module
  drm: sun4i: de3: add format enumeration function to engine
  drm: sun4i: de3: add formatter flag to mixer config
  drm: sun4i: de3: add YUV support to the DE3 mixer
  drm: sun4i: de3: pass engine reference to ccsc setup function
  drm: sun4i: de3: add YUV support to the color space correction module
  drm: sun4i: de3: add YUV support to the TCON
  drm: sun4i: support YUV formats in VI scaler
  drm: sun4i: de2/de3: add mixer version enum
  drm: sun4i: de2/de3: refactor mixer initialisation
  drm: sun4i: vi_scaler refactor vi_scaler enablement
  drm: sun4i: de2/de3: add generic blender register reference function
  drm: sun4i: de2/de3: use generic register reference function for layer
configuration
  drm: sun4i: de3: Implement AFBC support
  drm: sun4i: de33: mixer: add Display Engine 3.3 (DE33) support
  drm: sun4i: de33: vi_scaler: add Display Engine 3.3 (DE33) support
  drm: sun4i: de33: fmt: add Display Engine 3.3 (DE33) support
  drm: sun4i: de33: csc: add Display Engine 3.3 (DE33) support

Ryan Walklin (4):
  dt-bindings: allwinner: add H616 DE33 bus binding
  dt-bindings: allwinner: add H616 DE33 clock binding
  dt-bindings: allwinner: add H616 DE33 mixer binding
  clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support

 .../bus/allwinner,sun50i-a64-de2.yaml |   4 +-
 .../clock/allwinner,sun8i-a83t-de2-clk.yaml   |   1 +
 .../allwinner,sun8i-a83t-de2-mixer.yaml   |   1 +
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c  |  25 ++
 drivers/gpu/drm/sun4i/Makefile|   3 +-
 drivers/gpu/drm/sun4i/sun4i_tcon.c|  26 +-
 drivers/gpu/drm/sun4i/sun50i_afbc.c   | 250 +
 drivers/gpu/drm/sun4i/sun50i_afbc.h   |  87 +
 drivers/gpu/drm/sun4i/sun50i_fmt.c|  99 +
 drivers/gpu/drm/sun4i/sun50i_fmt.h|  33 ++
 drivers/gpu/drm/sun4i/sun8i_csc.c | 341 +++---
 drivers/gpu/drm/sun4i/sun8i_csc.h |  20 +-
 drivers/gpu/drm/sun4i/sun8i_mixer.c   | 226 +---
 drivers/gpu/drm/sun4i/sun8i_mixer.h   |  31 +-
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c|  41 ++-
 drivers/gpu/drm/sun4i/sun8i_ui_scaler.c   |   2 +-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c| 133 +--
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c   | 115 --
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.h   |   2 +-
 drivers/gpu/drm/sun4i/sunxi_engine.h  |  34 ++
 20 files changed, 1269 insertions(+), 205 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.h
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.h

Re: [PATCH v4 21/26] dt-bindings: allwinner: add H616 DE33 mixer binding

2024-09-29 Thread Ryan Walklin


On Mon, 23 Sep 2024, at 8:52 AM, Krzysztof Kozlowski wrote:
> On Sat, Sep 21, 2024 at 09:46:10PM +1200, Ryan Walklin wrote:
>> --
>
> That's not a delimiter and you would see checkpatch warning (because it
> is quite confused).
>
Thanks, will correct these for v5.

> Please run scripts/checkpatch.pl and fix reported warnings. Then please
> run  and (probably) fix more warnings.
> Some warnings can be ignored, especially from --strict run, but the code
> here looks like it needs a fix. Feel free to get in touch if the warning
> is not clear.
>
> Best regards,
> Krzysztof

Regards,

Ryan


[PATCH] drm: panel: nv3052c: correct spi_device_id for RG35XX panel

2024-09-29 Thread Ryan Walklin
The Anbernic RG35XX devices use an SPI LCD panel from an unknown OEM,
with an NV3052C driver chip.

As discussed previously, the integrating vendor and device name are
preferred instead of the OEM serial. A previous patch corrected the
device tree binding and of_device_id in the NV3052C driver, however the
spi_device_id also needs correction.

Correct the spi_device_id for the RG35XX panel.

Signed-off-by: Ryan Walklin 
Fixes: 76dce2a9 ("drm: panel: nv3052c: Correct WL-355608-A8 panel compatible")
---
 drivers/gpu/drm/panel/panel-newvision-nv3052c.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c 
b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
index d3baccfe6286b..06e16a7c14a75 100644
--- a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
+++ b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
@@ -917,7 +917,7 @@ static const struct nv3052c_panel_info 
wl_355608_a8_panel_info = {
 static const struct spi_device_id nv3052c_ids[] = {
{ "ltk035c5444t", },
{ "fs035vg158", },
-   { "wl-355608-a8", },
+   { "rg35xx-plus-panel", },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(spi, nv3052c_ids);
-- 
2.46.1



[PATCH v4 25/26] drm: sun4i: de33: fmt: add Display Engine 3.3 (DE33) support

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Like the DE3, the DE33 has a FMT (formatter) module, which
provides YUV444 to YUV422/YUV420 conversion, format re-mapping and color
depth conversion, although the DE33 module appears significantly more
capable, including up to 4K video support.

Add support for the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun50i_fmt.c | 21 +++--
 drivers/gpu/drm/sun4i/sun50i_fmt.h |  1 +
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.c 
b/drivers/gpu/drm/sun4i/sun50i_fmt.c
index 050a8716ae862..39682d4e6d208 100644
--- a/drivers/gpu/drm/sun4i/sun50i_fmt.c
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.c
@@ -51,6 +51,19 @@ static void sun50i_fmt_de3_limits(u32 *limits, u32 
colorspace, bool bit10)
}
 }
 
+static void sun50i_fmt_de33_limits(u32 *limits, u32 colorspace)
+{
+   if (colorspace == SUN50I_FMT_CS_YUV444RGB) {
+   limits[0] = SUN50I_FMT_LIMIT(0, 4095);
+   limits[1] = SUN50I_FMT_LIMIT(0, 4095);
+   limits[2] = SUN50I_FMT_LIMIT(0, 4095);
+   } else {
+   limits[0] = SUN50I_FMT_LIMIT(256, 3840);
+   limits[1] = SUN50I_FMT_LIMIT(256, 3840);
+   limits[2] = SUN50I_FMT_LIMIT(256, 3840);
+   }
+}
+
 void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
  u16 height, u32 format)
 {
@@ -60,10 +73,14 @@ void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
 
colorspace = sun50i_fmt_get_colorspace(format);
bit10 = sun50i_fmt_is_10bit(format);
-   base = SUN50I_FMT_DE3;
+   base = mixer->cfg->de_type == sun8i_mixer_de3 ?
+   SUN50I_FMT_DE3 : SUN50I_FMT_DE33;
regs = sun8i_blender_regmap(mixer);
 
-   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+   else
+   sun50i_fmt_de33_limits(limit, colorspace);
 
regmap_write(regs, SUN50I_FMT_CTRL(base), 0);
 
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.h 
b/drivers/gpu/drm/sun4i/sun50i_fmt.h
index 4127f7206aade..3e60d5c788b39 100644
--- a/drivers/gpu/drm/sun4i/sun50i_fmt.h
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.h
@@ -9,6 +9,7 @@
 #include "sun8i_mixer.h"
 
 #define SUN50I_FMT_DE3 0xa8000
+#define SUN50I_FMT_DE33 0x5000
 
 #define SUN50I_FMT_CTRL(base)   ((base) + 0x00)
 #define SUN50I_FMT_SIZE(base)   ((base) + 0x04)
-- 
2.46.1



[PATCH v4 26/26] drm: sun4i: de33: csc: add Display Engine 3.3 (DE33) support

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Like earlier DE versions, the DE33 has a CSC (Color Space Correction)
module. which provides color space conversion between BT2020/BT709, and
dynamic range conversion between SDR/ST2084/HLG.

Add support for the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c | 96 +++
 drivers/gpu/drm/sun4i/sun8i_csc.h |  3 +
 2 files changed, 99 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 2d5a2cf7cba24..45bd1ca06400e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -238,6 +238,14 @@ static const u32 yuv2yuv_de3[2][3][3][12] = {
},
 };
 
+static u32 sun8i_csc_base(struct sun8i_mixer *mixer, int layer)
+{
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return sun8i_channel_base(mixer, layer) - 0x800;
+   else
+   return ccsc_base[mixer->cfg->ccsc][layer];
+}
+
 static void sun8i_csc_setup(struct regmap *map, u32 base,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -358,6 +366,90 @@ static void sun8i_de3_ccsc_setup(struct sunxi_engine 
*engine, 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] &= 0x;
+   dst[10] &= 0x;
+   dst[14] &= 0x;
+}
+
+static void sun8i_de33_ccsc_setup(struct sun8i_mixer *mixer, int layer,
+ enum format_type fmt_type,
+ enum drm_color_encoding encoding,
+ enum drm_color_range range)
+{
+   u32 addr, val = 0, base, csc[15];
+   struct sunxi_engine *engine;
+   struct regmap *map;
+   const u32 *table;
+   int i;
+
+   table = yuv2rgb_de3[range][encoding];
+   base = sun8i_csc_base(mixer, layer);
+   engine = &mixer->engine;
+   map = engine->regs;
+
+   switch (fmt_type) {
+   case FORMAT_TYPE_RGB:
+   if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
+   break;
+   val = SUN8I_CSC_CTRL_EN;
+   sun8i_de33_convert_table(rgb2yuv_de3[engine->encoding], csc);
+   regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+   break;
+   case FORMAT_TYPE_YUV:
+   table = sun8i_csc_get_de3_yuv_table(encoding, range,
+   engine->format,
+   engine->encoding);
+   if (!table)
+   break;
+   val = SUN8I_CSC_CTRL_EN;
+   sun8i_de33_convert_table(table, csc);
+   regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+   break;
+   case FORMAT_TYPE_YVU:
+   table = sun8i_csc_get_de3_yuv_table(encoding, range,
+   engine->format,
+   engine->encoding);
+   if (!table)
+   table = yuv2yuv_de3[range][encoding][encoding];
+   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);
+}
+
 void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -369,6 +461,10 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
sun8i_de3_ccsc_setup(&mixer->engine, layer,
  

[PATCH v4 24/26] drm: sun4i: de33: vi_scaler: add Display Engine 3.3 (DE33) support

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

The vi_scaler appears to be used in preference to the ui_scaler module
for hardware video scaling in the DE33.

Enable support for this scaler.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c  | 19 +++
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c |  7 ++-
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 7f1231cf0f012..180be9d67d9c3 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -95,12 +95,23 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
hscale = state->src_w / state->crtc_w;
vscale = state->src_h / state->crtc_h;
 
-   sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w,
- dst_h, hscale, vscale, hphase, vphase);
-   sun8i_ui_scaler_enable(mixer, channel, true);
+   if (mixer->cfg->de_type == sun8i_mixer_de33) {
+   sun8i_vi_scaler_setup(mixer, channel, src_w, src_h,
+ dst_w, dst_h, hscale, vscale,
+ hphase, vphase,
+ state->fb->format);
+   } else {
+   sun8i_ui_scaler_setup(mixer, channel, src_w, src_h,
+ dst_w, dst_h, hscale, vscale,
+ hphase, vphase);
+   sun8i_ui_scaler_enable(mixer, channel, true);
+   }
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
-   sun8i_ui_scaler_enable(mixer, channel, false);
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   sun8i_vi_scaler_disable(mixer, channel);
+   else
+   sun8i_ui_scaler_enable(mixer, channel, false);
}
 
/* Set base coordinates */
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index e7242301b312c..9c7f6e7d71d50 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -835,7 +835,9 @@ static const u32 bicubic4coefftab32[480] = {
 
 static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
 {
-   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return sun8i_channel_base(mixer, channel) + 0x3000;
+   else if (mixer->cfg->de_type == sun8i_mixer_de3)
return DE3_VI_SCALER_UNIT_BASE +
   DE3_VI_SCALER_UNIT_SIZE * channel;
else
@@ -845,6 +847,9 @@ static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, 
int channel)
 
 static bool sun8i_vi_scaler_is_vi_plane(struct sun8i_mixer *mixer, int channel)
 {
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return mixer->cfg->map[channel] < mixer->cfg->vi_num;
+
return true;
 }
 
-- 
2.46.1



[PATCH v4 23/26] drm: sun4i: de33: mixer: add Display Engine 3.3 (DE33) support

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

The DE33 is a newer version of the Allwinner Display Engine IP block,
found in the H616, H618, H700 and T507 SoCs. DE2 and DE3 are already
supported by the mainline driver.

Notable features (from the H616 datasheet and implemented):
- 4096 x 2048 (4K) output support
- AFBC ARM Frame Buffer Compression support
- YUV420 input support

The DE2 and DE3 engines have a blender register range within the
mixer engine register map, whereas the DE33 separates this out into
a separate display group, and adds a top register map.

Extend the mixer to support the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 108 
 drivers/gpu/drm/sun4i/sun8i_mixer.h |  16 -
 2 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 23561f122a2b6..5a70d60e9a0eb 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -321,8 +321,12 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
 pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
 
-   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
-SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_DBUFF,
+SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+   else
+   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
+SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
 }
 
 static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
@@ -371,25 +375,33 @@ 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, *disp_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);
 
DRM_DEBUG_DRIVER("Updating global size W: %u H: %u\n",
 mode->hdisplay, mode->vdisplay);
 
-   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_SIZE, size);
-   regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
+   if (mixer->cfg->de_type == sun8i_mixer_de33) {
+   disp_regs = mixer->disp_regs;
+   regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_SIZE, size);
+   } else {
+   disp_regs = mixer->engine.regs;
+   regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE, size);
+   }
+   regmap_write(bld_regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
 
if (interlaced)
val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
else
val = 0;
 
-   regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
+   regmap_update_bits(bld_regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
 
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
@@ -400,10 +412,8 @@ static void sun8i_mixer_mode_set(struct sunxi_engine 
*engine,
else
val = 0xff108080;
 
-   regmap_write(mixer->engine.regs,
-SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
-   regmap_write(mixer->engine.regs,
-SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
+   regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
+   regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), 
val);
 
if (mixer->cfg->has_formatter)
sun50i_fmt_setup(mixer, mode->hdisplay,
@@ -443,12 +453,29 @@ static const struct sunxi_engine_ops sun8i_engine_ops = {
 };
 
 static const struct regmap_config sun8i_mixer_regmap_config = {
+   .name   = "layers",
.reg_bits   = 32,
.val_bits   = 32,
.reg_stride = 4,
.max_register   = 0xc, /* guessed */
 };
 
+static const struct regmap_config sun8i_top_regmap_config = {
+   .name   = "top",
+   .reg_bits   = 32,
+   .val_bits   = 32,
+   .reg_stride = 4,
+   .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   = 0x2,
+};
+
 static int sun8i_mixer_of_get_id(struc

[PATCH v4 22/26] clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support

2024-09-21 Thread Ryan Walklin
The DE33 is a newer version of the Allwinner Display Engine IP block,
found in the H616, H618, H700 and T507 SoCs. DE2 and DE3 are already
supported by the mainline driver.

The DE33 in the H616 has mixer0 and writeback units. The clocks
and resets required are identical to the H3 and H5 respectively, so use
those existing structs for the H616 description.

There are two additional 32-bit registers (at offsets 0x24 and 0x28)
which require clearing and setting respectively to bring up the
hardware. The function of these registers is currently unknown, and the
values are taken from the out-of-tree driver.

Add the required clock description struct and compatible string to the
DE2 driver.

Signed-off-by: Ryan Walklin 

--
Changelog v2..v3:
- Lowercase hex value

Changelog v2..v3:
- Correct #include for writel()
---
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 25 +
 1 file changed, 25 insertions(+)

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c 
b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
index 7683ea08d8e30..2eb5bb2547e92 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -5,6 +5,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -239,6 +240,16 @@ static const struct sunxi_ccu_desc sun50i_h5_de2_clk_desc 
= {
.num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
 };
 
+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,
+
+   .resets = sun50i_h5_de2_resets,
+   .num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
+};
+
 static int sunxi_de2_clk_probe(struct platform_device *pdev)
 {
struct clk *bus_clk, *mod_clk;
@@ -290,6 +301,16 @@ static int sunxi_de2_clk_probe(struct platform_device 
*pdev)
"Couldn't deassert reset control: %d\n", ret);
goto err_disable_mod_clk;
}
+ 
+   /*
+* The DE33 requires these additional (unknown) registers set
+* during initialisation.
+*/
+   if (of_device_is_compatible(pdev->dev.of_node,
+   "allwinner,sun50i-h616-de33-clk")) {
+   writel(0, reg + 0x24);
+   writel(0xa980, reg + 0x28);
+   }
 
ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
if (ret)
@@ -335,6 +356,10 @@ static const struct of_device_id sunxi_de2_clk_ids[] = {
.compatible = "allwinner,sun50i-h6-de3-clk",
.data = &sun50i_h5_de2_clk_desc,
},
+   {
+   .compatible = "allwinner,sun50i-h616-de33-clk",
+   .data = &sun50i_h616_de33_clk_desc,
+   },
{ }
 };
 MODULE_DEVICE_TABLE(of, sunxi_de2_clk_ids);
-- 
2.46.1



[PATCH v4 21/26] dt-bindings: allwinner: add H616 DE33 mixer binding

2024-09-21 Thread Ryan Walklin
The Allwinner H616 and variants have a new display engine revision
(DE33).

The mixer configuration registers are significantly different to the DE3
and DE2 revisions, being split into separate top and display blocks,
therefore a fallback for the mixer compatible is not provided.

Add a display engine mixer binding for the DE33.

Signed-off-by: Ryan Walklin 
Acked-by: Conor Dooley 
Reviewed-by: Chen-Yu Tsai 

--

Changelog v2..v3:
- Separate content into three patches for three separate subsystems
---
 .../bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml | 1 +
 1 file changed, 1 insertion(+)

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 b75c1ec686ad2..c37eb8ae1b8ee 100644
--- 
a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
+++ 
b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
@@ -24,6 +24,7 @@ properties:
   - allwinner,sun50i-a64-de2-mixer-0
   - allwinner,sun50i-a64-de2-mixer-1
   - allwinner,sun50i-h6-de3-mixer-0
+  - allwinner,sun50i-h616-de33-mixer-0
 
   reg:
 maxItems: 1
-- 
2.46.1



[PATCH v4 20/26] dt-bindings: allwinner: add H616 DE33 clock binding

2024-09-21 Thread Ryan Walklin
The Allwinner H616 and variants have a new display engine revision
(DE33).

Add a clock binding for the DE33.

Signed-off-by: Ryan Walklin 
Acked-by: Conor Dooley 
Reviewed-by: Chen-Yu Tsai 

--
Changelog v2..v3:
- Separate content into three patches for three separate subsystems
---
 .../devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml  | 1 +
 1 file changed, 1 insertion(+)

diff --git 
a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml 
b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
index 70369bd633e40..7fcd55d468d49 100644
--- a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
+++ b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
@@ -25,6 +25,7 @@ properties:
   - const: allwinner,sun50i-a64-de2-clk
   - const: allwinner,sun50i-h5-de2-clk
   - const: allwinner,sun50i-h6-de3-clk
+  - const: allwinner,sun50i-h616-de33-clk
   - items:
   - const: allwinner,sun8i-r40-de2-clk
   - const: allwinner,sun8i-h3-de2-clk
-- 
2.46.1



[PATCH v4 19/26] dt-bindings: allwinner: add H616 DE33 bus binding

2024-09-21 Thread Ryan Walklin
The Allwinner H616 and variants have a new display engine revision
(DE33).

Add a display engine bus binding for the DE33.

Signed-off-by: Ryan Walklin 
Acked-by: Conor Dooley 
Reviewed-by: Chen-Yu Tsai 

--
Changelog v1..v2:
- Correct DE2 bus enum to reflect fallback devices accurately.

Changelog v2..v3:
- Separate content into three patches for three separate subsystems
---
 .../devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git 
a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml 
b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
index 9845a187bdf65..ea7ee89158c61 100644
--- a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
+++ b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
@@ -24,7 +24,9 @@ properties:
 oneOf:
   - const: allwinner,sun50i-a64-de2
   - items:
-  - const: allwinner,sun50i-h6-de3
+  - enum:
+  - allwinner,sun50i-h6-de3
+  - allwinner,sun50i-h616-de33
   - const: allwinner,sun50i-a64-de2
 
   reg:
-- 
2.46.1



[PATCH v4 18/26] drm: sun4i: de3: Implement AFBC support

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Buffers, compressed with AFBC, are supported by the DE3 and above, and
are generally more efficient for memory transfers. Add support for them.

Currently it's implemented only for VI layers, but vendor code and
documentation suggest UI layers can have them too. However, I haven't
observed any SoC with such feature.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/Makefile |   2 +-
 drivers/gpu/drm/sun4i/sun50i_afbc.c| 250 +
 drivers/gpu/drm/sun4i/sun50i_afbc.h|  87 +
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c |  85 +++--
 4 files changed, 410 insertions(+), 14 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 3f516329f51ee..78290f1660fbd 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -17,7 +17,7 @@ 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 \
-  sun50i_fmt.o
+  sun50i_fmt.o sun50i_afbc.o
 
 sun4i-tcon-y   += sun4i_crtc.o
 sun4i-tcon-y   += sun4i_tcon_dclk.o
diff --git a/drivers/gpu/drm/sun4i/sun50i_afbc.c 
b/drivers/gpu/drm/sun4i/sun50i_afbc.c
new file mode 100644
index 0..b55e1c5533714
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_afbc.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Jernej Skrabec 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "sun50i_afbc.h"
+#include "sun8i_mixer.h"
+
+static u32 sun50i_afbc_get_base(struct sun8i_mixer *mixer, unsigned int 
channel)
+{
+   u32 base = sun8i_channel_base(mixer, channel);
+
+   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   return base + SUN50I_AFBC_CH_OFFSET;
+
+   return base + 0x4000;
+}
+
+bool sun50i_afbc_format_mod_supported(struct sun8i_mixer *mixer,
+ u32 format, u64 modifier)
+{
+   u64 mode;
+
+   if (modifier == DRM_FORMAT_MOD_INVALID)
+   return false;
+
+   if (modifier == DRM_FORMAT_MOD_LINEAR) {
+   if (format == DRM_FORMAT_YUV420_8BIT ||
+   format == DRM_FORMAT_YUV420_10BIT ||
+   format == DRM_FORMAT_Y210)
+   return false;
+   return true;
+   }
+
+   if (mixer->cfg->de_type == sun8i_mixer_de2)
+   return false;
+
+   mode = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+  AFBC_FORMAT_MOD_SPARSE |
+  AFBC_FORMAT_MOD_SPLIT;
+
+   switch (format) {
+   case DRM_FORMAT_RGBA:
+   case DRM_FORMAT_RGB888:
+   case DRM_FORMAT_RGB565:
+   case DRM_FORMAT_RGBA:
+   case DRM_FORMAT_RGBA5551:
+   case DRM_FORMAT_RGBA1010102:
+   mode |= AFBC_FORMAT_MOD_YTR;
+   break;
+   case DRM_FORMAT_YUYV:
+   case DRM_FORMAT_Y210:
+   case DRM_FORMAT_YUV420_8BIT:
+   case DRM_FORMAT_YUV420_10BIT:
+   break;
+   default:
+   return false;
+   }
+
+   return modifier == DRM_FORMAT_MOD_ARM_AFBC(mode);
+}
+
+void sun50i_afbc_atomic_update(struct sun8i_mixer *mixer, unsigned int channel,
+  struct drm_plane *plane)
+{
+   struct drm_plane_state *state = plane->state;
+   struct drm_framebuffer *fb = state->fb;
+   const struct drm_format_info *format = fb->format;
+   struct drm_gem_dma_object *gem;
+   u32 base, val, src_w, src_h;
+   u32 def_color0, def_color1;
+   struct regmap *regs;
+   dma_addr_t dma_addr;
+
+   base = sun50i_afbc_get_base(mixer, channel);
+   regs = mixer->engine.regs;
+
+   src_w = drm_rect_width(&state->src) >> 16;
+   src_h = drm_rect_height(&state->src) >> 16;
+
+   val = SUN50I_FBD_SIZE_HEIGHT(src_h);
+   val |= SUN50I_FBD_SIZE_WIDTH(src_w);
+   regmap_write(regs, SUN50I_FBD_SIZE(base), val);
+
+   val = SUN50I_FBD_BLK_SIZE_HEIGHT(DIV_ROUND_UP(src_h, 16));
+   val = SUN50I_FBD_BLK_SIZE_WIDTH(DIV_ROUND_UP(src_w, 16));
+   regmap_write(regs, SUN50I_FBD_BLK_SIZE(base), val);
+
+   val = SUN50I_FBD_SRC_CROP_TOP(0);
+   val |= SUN50I_FBD_SRC_CROP_LEFT(0);
+   regmap_write(regs, SUN50I_FBD_SRC_CROP(base), val);
+
+   val = SUN50I_FBD_LAY_CROP_TOP(state->src.y1 >> 16);
+   val |= SUN50I_FBD_LAY_CROP_LEFT(state->src.x1 >> 16);
+   regmap_write(regs, SUN50I_FBD_LAY_CROP(base), val);
+
+   /*
+* Default color 

[PATCH v4 17/26] drm: sun4i: de2/de3: use generic register reference function for layer configuration

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Use the new blender register lookup function where required in the layer
commit and update code.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 

--

Changelog v2..v3:
- Refactor for 6.11 layer init/modesetting changes
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c| 5 +++--
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 7 +--
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 6 --
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 8871ca2858c80..23561f122a2b6 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -277,6 +277,7 @@ 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;
@@ -316,8 +317,8 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
}
 
-   regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), 
route);
-   regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
+   regmap_write(bld_regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
+   regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
 pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
 
regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index cb9b694fef101..7f1231cf0f012 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -24,6 +24,7 @@
 #include "sun8i_mixer.h"
 #include "sun8i_ui_layer.h"
 #include "sun8i_ui_scaler.h"
+#include "sun8i_vi_scaler.h"
 
 static void sun8i_ui_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
int overlay, struct drm_plane *plane)
@@ -52,6 +53,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
 {
struct drm_plane_state *state = plane->state;
u32 src_w, src_h, dst_w, dst_h;
+   struct regmap *bld_regs;
u32 bld_base, ch_base;
u32 outsize, insize;
u32 hphase, vphase;
@@ -60,6 +62,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
 channel, overlay);
 
bld_base = sun8i_blender_base(mixer);
+   bld_regs = sun8i_blender_regmap(mixer);
ch_base = sun8i_channel_base(mixer, channel);
 
src_w = drm_rect_width(&state->src) >> 16;
@@ -104,10 +107,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
 state->dst.x1, state->dst.y1);
DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
-   regmap_write(mixer->engine.regs,
+   regmap_write(bld_regs,
 SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
 SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
-   regmap_write(mixer->engine.regs,
+   regmap_write(bld_regs,
 SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
 outsize);
 
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index e348fd0a3d81c..d19349eecc9de 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -55,6 +55,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
struct drm_plane_state *state = plane->state;
const struct drm_format_info *format = state->fb->format;
u32 src_w, src_h, dst_w, dst_h;
+   struct regmap *bld_regs;
u32 bld_base, ch_base;
u32 outsize, insize;
u32 hphase, vphase;
@@ -66,6 +67,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
 channel, overlay);
 
bld_base = sun8i_blender_base(mixer);
+   bld_regs = sun8i_blender_regmap(mixer);
ch_base = sun8i_channel_base(mixer, channel);
 
src_w = drm_rect_width(&state->src) >> 16;
@@ -182,10 +184,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
 state->dst.x1, state->dst.y1);
DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
-   regmap_write(mixer->engine.regs,
+   reg

[PATCH v4 16/26] drm: sun4i: de2/de3: add generic blender register reference function

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

The DE2 and DE3 engines have a blender register range within the
mixer engine register map, whereas the DE33 separates this out into
a separate display group.

Prepare for this by adding a function to look the blender reference up,
with a subsequent patch to add a conditional based on the DE type.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.h | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h 
b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index 82956cb97cfd9..75facc7d1fa66 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -224,6 +224,12 @@ 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->engine.regs;
+}
+
 static inline u32
 sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
 {
-- 
2.46.1



[PATCH v4 15/26] drm: sun4i: vi_scaler refactor vi_scaler enablement

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

If the video scaler is required, then it is obligatory to set the
relevant register to enable it, so move this to the
sun8i_vi_scaler_setup() function.

This simplifies the alternate case (scaler not required) so replace the
vi_scaler_enable() function with a vi_scaler_disable() function.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c  |  3 +--
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 21 +++--
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.h |  2 +-
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 4647e9bcccaa7..e348fd0a3d81c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -156,10 +156,9 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
  dst_h, hscale, vscale, hphase, vphase,
  format);
-   sun8i_vi_scaler_enable(mixer, channel, true);
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
-   sun8i_vi_scaler_enable(mixer, channel, false);
+   sun8i_vi_scaler_disable(mixer, channel);
}
 
regmap_write(mixer->engine.regs,
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index aa346c3beb303..e7242301b312c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -933,20 +933,13 @@ static void sun8i_vi_scaler_set_coeff_ui(struct regmap 
*map, u32 base,
  &table[offset], SUN8I_VI_SCALER_COEFF_COUNT);
 }
 
-void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
+void sun8i_vi_scaler_disable(struct sun8i_mixer *mixer, int layer)
 {
-   u32 val, base;
+   u32 base;
 
base = sun8i_vi_scaler_base(mixer, layer);
 
-   if (enable)
-   val = SUN8I_SCALER_VSU_CTRL_EN |
- SUN8I_SCALER_VSU_CTRL_COEFF_RDY;
-   else
-   val = 0;
-
-   regmap_write(mixer->engine.regs,
-SUN8I_SCALER_VSU_CTRL(base), val);
+   regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base), 0);
 }
 
 void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
@@ -982,6 +975,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int 
layer,
cvphase = vphase;
}
 
+   regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base),
+SUN8I_SCALER_VSU_CTRL_EN);
+
if (mixer->cfg->de_type >= sun8i_mixer_de3) {
u32 val;
 
@@ -1027,4 +1023,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int 
layer,
else
sun8i_vi_scaler_set_coeff_ui(mixer->engine.regs, base,
 hscale, vscale, format);
+
+   if (mixer->cfg->de_type <= sun8i_mixer_de3)
+   regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base),
+SUN8I_SCALER_VSU_CTRL_EN |
+SUN8I_SCALER_VSU_CTRL_COEFF_RDY);
 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
index 68f6593b369ab..e801bc7a4189e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
@@ -69,7 +69,7 @@
 #define SUN50I_SCALER_VSU_ANGLE_SHIFT(x)   (((x) << 16) & 0xF)
 #define SUN50I_SCALER_VSU_ANGLE_OFFSET(x)  ((x) & 0xFF)
 
-void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
+void sun8i_vi_scaler_disable(struct sun8i_mixer *mixer, int layer);
 void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
   u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
   u32 hscale, u32 vscale, u32 hphase, u32 vphase,
-- 
2.46.1



[PATCH v4 14/26] drm: sun4i: de2/de3: refactor mixer initialisation

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Now that the DE variant can be selected by enum, take the oppportunity
to factor out some common initialisation code to a separate function.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 

--
Changelog v1..v2:
- Combine base register allocation and initialisation in sun8i_mixer_init
- Whitespace fix
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 66 +++--
 1 file changed, 35 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 34f03ad18a26e..8871ca2858c80 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -468,6 +468,38 @@ static int sun8i_mixer_of_get_id(struct device_node *node)
return of_ep.id;
 }
 
+static void sun8i_mixer_init(struct sun8i_mixer *mixer)
+{
+   unsigned int base = sun8i_blender_base(mixer);
+   int plane_cnt, i;
+
+   /* Enable the mixer */
+   regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
+SUN8I_MIXER_GLOBAL_CTL_RT_EN);
+
+   /* Set background color to black */
+   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(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(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(mixer->engine.regs,
+SUN8I_MIXER_BLEND_MODE(base, i),
+SUN8I_MIXER_BLEND_MODE_DEF);
+
+   regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+  SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
+}
+
 static int sun8i_mixer_bind(struct device *dev, struct device *master,
  void *data)
 {
@@ -476,8 +508,6 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
struct sun4i_drv *drv = drm->dev_private;
struct sun8i_mixer *mixer;
void __iomem *regs;
-   unsigned int base;
-   int plane_cnt;
int i, ret;
 
/*
@@ -581,8 +611,6 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
 
list_add_tail(&mixer->engine.list, &drv->engine_list);
 
-   base = sun8i_blender_base(mixer);
-
/* Reset registers and disable unused sub-engines */
if (mixer->cfg->de_type == sun8i_mixer_de3) {
for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
@@ -598,7 +626,7 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
-   } else {
+   } else if (mixer->cfg->de_type == sun8i_mixer_de2) {
for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
regmap_write(mixer->engine.regs, i, 0);
 
@@ -611,32 +639,8 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
}
 
-   /* Enable the mixer */
-   regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
-SUN8I_MIXER_GLOBAL_CTL_RT_EN);
-
-   /* Set background color to black */
-   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(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
-SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(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(mixer->engine.regs,
-SUN8I_MIXER_BLEND_MODE(base, i),
-SUN8I_MIXER_BLEND_MODE_DEF);
-
-   regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
-  SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
-
+   sun8i_mixer_init(mixer);
+   
return 0;
 
 err_disable_bus_clk:
-- 
2.46.1



[PATCH v4 13/26] drm: sun4i: de2/de3: add mixer version enum

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

The Allwinner DE2 and DE3 display engine mixers are currently identified
by a simple boolean flag. This will not scale to support additional DE
variants.

Convert the boolean flag to an enum.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c   |  2 +-
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 14 --
 drivers/gpu/drm/sun4i/sun8i_mixer.h | 11 ---
 drivers/gpu/drm/sun4i/sun8i_ui_scaler.c |  2 +-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c  |  8 
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c |  4 ++--
 6 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index e12a81fa91083..2d5a2cf7cba24 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -365,7 +365,7 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
 {
u32 base;
 
-   if (mixer->cfg->is_de3) {
+   if (mixer->cfg->de_type == sun8i_mixer_de3) {
sun8i_de3_ccsc_setup(&mixer->engine, layer,
 fmt_type, encoding, range);
return;
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index af7c8f786eb83..34f03ad18a26e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -584,7 +584,7 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
base = sun8i_blender_base(mixer);
 
/* Reset registers and disable unused sub-engines */
-   if (mixer->cfg->is_de3) {
+   if (mixer->cfg->de_type == sun8i_mixer_de3) {
for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
regmap_write(mixer->engine.regs, i, 0);
 
@@ -675,6 +675,7 @@ static void sun8i_mixer_remove(struct platform_device *pdev)
 
 static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.scaler_mask= 0xf,
.scanline_yuv   = 2048,
.ui_num = 3,
@@ -683,6 +684,7 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = 
{
 
 static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
.ccsc   = CCSC_MIXER1_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.scaler_mask= 0x3,
.scanline_yuv   = 2048,
.ui_num = 1,
@@ -691,6 +693,7 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = 
{
 
 static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 43200,
.scaler_mask= 0xf,
.scanline_yuv   = 2048,
@@ -700,6 +703,7 @@ static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
 
 static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0xf,
.scanline_yuv   = 2048,
@@ -709,6 +713,7 @@ static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
 
 static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
.ccsc   = CCSC_MIXER1_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0x3,
.scanline_yuv   = 2048,
@@ -717,6 +722,7 @@ static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
 };
 
 static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
+   .de_type = sun8i_mixer_de2,
.vi_num = 2,
.ui_num = 1,
.scaler_mask = 0x3,
@@ -727,6 +733,7 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
 
 static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
.ccsc   = CCSC_D1_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0x3,
.scanline_yuv   = 2048,
@@ -736,6 +743,7 @@ static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
 
 static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
.ccsc   = CCSC_MIXER1_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0x1,
.scanline_yuv   = 1024,
@@ -745,6 +753,7 @@ static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
 
 static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0xf,
.scanline_yuv   = 4096,
@@ -754,6 +763,7 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = 
{
 
 static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
.ccsc   =

[PATCH v4 12/26] drm: sun4i: support YUV formats in VI scaler

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 85 +
 1 file changed, 58 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index 7ba75011adf9f..2e49a6e5f1f1c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -843,6 +843,11 @@ static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, 
int channel)
   DE2_VI_SCALER_UNIT_SIZE * channel;
 }
 
+static bool sun8i_vi_scaler_is_vi_plane(struct sun8i_mixer *mixer, int channel)
+{
+   return true;
+}
+
 static int sun8i_vi_scaler_coef_index(unsigned int step)
 {
unsigned int scale, int_part, float_part;
@@ -867,44 +872,65 @@ static int sun8i_vi_scaler_coef_index(unsigned int step)
}
 }
 
-static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base,
- u32 hstep, u32 vstep,
- const struct drm_format_info *format)
+static void sun8i_vi_scaler_set_coeff_vi(struct regmap *map, u32 base,
+u32 hstep, u32 vstep,
+const struct drm_format_info *format)
 {
const u32 *ch_left, *ch_right, *cy;
-   int offset, i;
+   int offset;
 
-   if (format->hsub == 1 && format->vsub == 1) {
-   ch_left = lan3coefftab32_left;
-   ch_right = lan3coefftab32_right;
-   cy = lan2coefftab32;
-   } else {
+   if (format->is_yuv) {
ch_left = bicubic8coefftab32_left;
ch_right = bicubic8coefftab32_right;
cy = bicubic4coefftab32;
+   } else {
+   ch_left = lan3coefftab32_left;
+   ch_right = lan3coefftab32_right;
+   cy = lan2coefftab32;
}
 
offset = sun8i_vi_scaler_coef_index(hstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
-   for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
-   regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, i),
-lan3coefftab32_left[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
-lan3coefftab32_right[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),
-ch_left[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),
-ch_right[offset + i]);
-   }
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, 0),
+ &lan3coefftab32_left[offset],
+ SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, 0),
+ &lan3coefftab32_right[offset],
+ SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, 0),
+ &ch_left[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, 0),
+ &ch_right[offset], SUN8I_VI_SCALER_COEFF_COUNT);
 
offset = sun8i_vi_scaler_coef_index(hstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
-   for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
-   regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
-lan2coefftab32[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
-cy[offset + i]);
-   }
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, 0),
+ &cy[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+}
+
+static void sun8i_vi_scaler_set_coeff_ui(struct regmap *map, u32 base,
+u32 hstep, u32 vstep,
+const struct drm_format_info *format)
+{
+   const u32 *table;
+   int offset;
+
+   offset = sun8i_vi_scaler_coef_index(hstep) *
+   SUN8I_VI_SCALER_COEFF_COUNT;
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+   offset = sun8i_vi_scaler_coef_index(vstep) *
+   SUN8I_VI_SCALER_COEFF_COUNT;
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+
+   table = format->is_yuv ? bicubic4coefftab32 : lan2coefftab32;
+   offset = sun8i_vi_scaler_coef_index(hstep) *
+   

[PATCH v4 11/26] drm: sun4i: de3: add YUV support to the TCON

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Account for U/V channel subsampling by reducing the dot clock and
resolution with a divider in the DE3 timing controller if a YUV format
is selected.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 +++---
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c 
b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index a1a2c845ade0c..e39926e9f0b5d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -598,14 +598,26 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon 
*tcon,
 static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
 const struct drm_display_mode *mode)
 {
-   unsigned int bp, hsync, vsync, vtotal;
+   unsigned int bp, hsync, vsync, vtotal, div;
+   struct sun4i_crtc *scrtc = tcon->crtc;
+   struct sunxi_engine *engine = scrtc->engine;
u8 clk_delay;
u32 val;
 
WARN_ON(!tcon->quirks->has_channel_1);
 
+   switch (engine->format) {
+   case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+   case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+   div = 2;
+   break;
+   default:
+   div = 1;
+   break;
+   }
+
/* Configure the dot clock */
-   clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
+   clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000 / div);
 
/* Adjust clock delay */
clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
@@ -624,17 +636,17 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
 
/* Set the input resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
-SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
+SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay / div) |
 SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
 
/* Set the upscaling resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
-SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
+SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay / div) |
 SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
 
/* Set the output resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
-SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
+SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay / div) |
 SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
 
/* Set horizontal display timings */
@@ -642,8 +654,8 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
 mode->htotal, bp);
regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
-SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
-SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
+SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal / div) |
+SUN4I_TCON1_BASIC3_H_BACKPORCH(bp / div));
 
bp = mode->crtc_vtotal - mode->crtc_vsync_start;
DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
-- 
2.46.1



[PATCH v4 10/26] drm: sun4i: de3: add YUV support to the color space correction module

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Add coefficients and support for YUV formats to the display engine
colorspace and dynamic range correction submodule.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c | 164 +-
 1 file changed, 162 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 8a336ccb27d33..e12a81fa91083 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -5,6 +5,8 @@
 
 #include 
 
+#include 
+
 #include "sun8i_csc.h"
 #include "sun8i_mixer.h"
 
@@ -107,6 +109,135 @@ static const u32 yuv2rgb_de3[2][3][12] = {
},
 };
 
+/* always convert to limited mode */
+static const u32 rgb2yuv_de3[3][12] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x837A, 0x0001021D, 0x3221, 0x0040,
+   0xB41C, 0x6B03, 0xE0E1, 0x0200,
+   0xE0E1, 0x43B1, 0xDB6E, 0x0200,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x5D7C, 0x00013A7C, 0x1FBF, 0x0040,
+   0xCC78, 0x52A7, 0xE0E1, 0x0200,
+   0xE0E1, 0x33BE, 0xEB61, 0x0200,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x7384, 0x00012A21, 0x1A13, 0x0040,
+   0xC133, 0x5DEC, 0xE0E1, 0x0200,
+   0xE0E1, 0x3135, 0xEDEA, 0x0200,
+   },
+};
+
+/* always convert to limited mode */
+static const u32 yuv2yuv_de3[2][3][3][12] = {
+   [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0002, 0x, 0x, 0x,
+   0x, 0x0002, 0x, 0x,
+   0x, 0x, 0x0002, 0x,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x0002, 0xC4D7, 0x9589, 0xFFC00040,
+   0x, 0x0002098B, 0x3AAF, 0xFE000200,
+   0x, 0x266D, 0x00020CF8, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x0002, 0xBFCE, 0xC5FF, 0xFFC00040,
+   0x, 0x00020521, 0x1F89, 0xFE000200,
+   0x, 0x2C87, 0x00020F07, 0xFE000200,
+   },
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0002, 0x32D9, 0x6226, 0xFFC00040,
+   0x, 0x0001FACE, 0xC759, 0xFE000200,
+   0x, 0xDAE7, 0x0001F780, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x0002, 0x, 0x, 0x,
+   0x, 0x0002, 0x, 0x,
+   0x, 0x, 0x0002, 0x,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x0002, 0xF782, 0x3036, 0xFFC00040,
+   0x, 0x0001FD99, 0xE5CA, 0xFE000200,
+   0x, 0x05E4, 0x0002015A, 0xFE000200,
+   },
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0002, 0x3B03, 0x34D2, 0xFFC00040,
+   0x, 0x0001FD8C, 0xE183, 0xFE000200,
+   0x, 0xD4F3, 0x0001F3FA, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x0002, 0x0916, 0xD061, 0xFFC00040,
+   0x, 0x0002021C, 0x1A40, 0xFE000200,
+   0x, 0xFA19, 0x0001FE5A, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x0002, 0x, 0x, 0x,
+   0x, 0x0002, 0x, 0x,
+   0x, 0x, 0x0002, 0x,
+   },
+   },
+   },
+   [DRM_COLOR_YCBCR_FULL_RANGE] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0001B7B8, 0x, 0x, 0x0040,
+   0x

[PATCH v4 09/26] drm: sun4i: de3: pass engine reference to ccsc setup function

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Configuration of the DE3 colorspace and dynamic range correction module
requires knowledge of the current video format and encoding.

Pass the display engine by reference to the csc setup function, rather
than the register map alone, to allow access to this information.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 68d955c63b05b..8a336ccb27d33 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -148,17 +148,19 @@ static void sun8i_csc_setup(struct regmap *map, u32 base,
regmap_write(map, SUN8I_CSC_CTRL(base), val);
 }
 
-static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
+static void sun8i_de3_ccsc_setup(struct sunxi_engine *engine, int layer,
 enum format_type fmt_type,
 enum drm_color_encoding encoding,
 enum drm_color_range range)
 {
u32 addr, val, mask;
+   struct regmap *map;
const u32 *table;
int i;
 
mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
table = yuv2rgb_de3[range][encoding];
+   map = engine->regs;
 
switch (fmt_type) {
case FORMAT_TYPE_RGB:
@@ -204,7 +206,7 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
u32 base;
 
if (mixer->cfg->is_de3) {
-   sun8i_de3_ccsc_setup(mixer->engine.regs, layer,
+   sun8i_de3_ccsc_setup(&mixer->engine, layer,
 fmt_type, encoding, range);
return;
}
-- 
2.46.1



[PATCH v4 08/26] drm: sun4i: de3: add YUV support to the DE3 mixer

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

The mixer in the DE3 display engine supports YUV 8 and 10 bit
formats in addition to 8-bit RGB. Add the required register
configuration and format enumeration callback functions to the mixer,
and store the in-use output format (defaulting to RGB) and color
encoding in engine variables.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c  | 55 ++--
 drivers/gpu/drm/sun4i/sunxi_engine.h |  5 +++
 2 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 252827715de1d..af7c8f786eb83 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -23,7 +23,10 @@
 #include 
 #include 
 
+#include 
+
 #include "sun4i_drv.h"
+#include "sun50i_fmt.h"
 #include "sun8i_mixer.h"
 #include "sun8i_ui_layer.h"
 #include "sun8i_vi_layer.h"
@@ -390,12 +393,52 @@ static void sun8i_mixer_mode_set(struct sunxi_engine 
*engine,
 
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
 interlaced ? "on" : "off");
+
+   if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
+   val = SUN8I_MIXER_BLEND_COLOR_BLACK;
+   else
+   val = 0xff108080;
+
+   regmap_write(mixer->engine.regs,
+SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
+   regmap_write(mixer->engine.regs,
+SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
+
+   if (mixer->cfg->has_formatter)
+   sun50i_fmt_setup(mixer, mode->hdisplay,
+mode->vdisplay, mixer->engine.format);
+}
+
+static u32 *sun8i_mixer_get_supported_fmts(struct sunxi_engine *engine, u32 
*num)
+{
+   struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+   u32 *formats, count;
+
+   count = 0;
+
+   formats = kcalloc(5, sizeof(*formats), GFP_KERNEL);
+   if (!formats)
+   return NULL;
+
+   if (mixer->cfg->has_formatter) {
+   formats[count++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
+   formats[count++] = MEDIA_BUS_FMT_YUV8_1X24;
+   formats[count++] = MEDIA_BUS_FMT_UYVY8_1X16;
+   formats[count++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+   }
+
+   formats[count++] = MEDIA_BUS_FMT_RGB888_1X24;
+
+   *num = count;
+
+   return formats;
 }
 
 static const struct sunxi_engine_ops sun8i_engine_ops = {
-   .commit = sun8i_mixer_commit,
-   .layers_init= sun8i_layers_init,
-   .mode_set   = sun8i_mixer_mode_set,
+   .commit = sun8i_mixer_commit,
+   .layers_init= sun8i_layers_init,
+   .mode_set   = sun8i_mixer_mode_set,
+   .get_supported_fmts = sun8i_mixer_get_supported_fmts,
 };
 
 static const struct regmap_config sun8i_mixer_regmap_config = {
@@ -456,7 +499,11 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
dev_set_drvdata(dev, mixer);
mixer->engine.ops = &sun8i_engine_ops;
mixer->engine.node = dev->of_node;
-
+   /* default output format, supported by all mixers */
+   mixer->engine.format = MEDIA_BUS_FMT_RGB888_1X24;
+   /* default color encoding, ignored with RGB I/O */
+   mixer->engine.encoding = DRM_COLOR_YCBCR_BT601;
+   
if (of_property_present(dev->of_node, "iommus")) {
/*
 * This assume we have the same DMA constraints for
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h 
b/drivers/gpu/drm/sun4i/sunxi_engine.h
index c48cbc1aceb80..ffafc29b3a0c3 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -6,6 +6,8 @@
 #ifndef _SUNXI_ENGINE_H_
 #define _SUNXI_ENGINE_H_
 
+#include 
+
 struct drm_plane;
 struct drm_crtc;
 struct drm_device;
@@ -151,6 +153,9 @@ struct sunxi_engine {
 
int id;
 
+   u32 format;
+   enum drm_color_encoding encoding;
+
/* Engine list management */
struct list_headlist;
 };
-- 
2.46.1



[PATCH v4 07/26] drm: sun4i: de3: add formatter flag to mixer config

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Only the DE3 (and newer) display engines have a formatter module. This
could be inferred from the is_de3 flag alone, however this will not
scale with addition of future DE versions in subsequent patches.

Add a separate flag to signal this in the mixer configuration.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 1 +
 drivers/gpu/drm/sun4i/sun8i_mixer.h | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index bd0fe2c6624e6..252827715de1d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -717,6 +717,7 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = 
{
 static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
.is_de3 = true,
+   .has_formatter  = 1,
.mod_rate   = 6,
.scaler_mask= 0xf,
.scanline_yuv   = 4096,
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h 
b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index d7898c9c9cc0c..8417b8fef2e1f 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -163,6 +163,7 @@ enum {
  * @mod_rate: module clock rate that needs to be set in order to have
  * a functional block.
  * @is_de3: true, if this is next gen display engine 3.0, false otherwise.
+ * @has_formatter: true, if mixer has formatter core, for 10-bit and YUV 
handling
  * @scaline_yuv: size of a scanline for VI scaler for YUV formats.
  */
 struct sun8i_mixer_cfg {
@@ -172,6 +173,7 @@ struct sun8i_mixer_cfg {
int ccsc;
unsigned long   mod_rate;
unsigned intis_de3 : 1;
+   unsigned inthas_formatter : 1;
unsigned intscanline_yuv;
 };
 
-- 
2.46.1



[PATCH v4 06/26] drm: sun4i: de3: add format enumeration function to engine

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

The DE3 display engine supports YUV formats in addition to RGB.

Add an optional format enumeration function to the engine.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sunxi_engine.h | 29 
 1 file changed, 29 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h 
b/drivers/gpu/drm/sun4i/sunxi_engine.h
index ec0c4932f15cf..c48cbc1aceb80 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -123,6 +123,17 @@ struct sunxi_engine_ops {
 */
void (*mode_set)(struct sunxi_engine *engine,
 const struct drm_display_mode *mode);
+
+   /**
+* @get_supported_fmts
+*
+* This callback is used to enumerate all supported output
+* formats by the engine. They are used for bridge format
+* negotiation.
+*
+* This function is optional.
+*/
+   u32 *(*get_supported_fmts)(struct sunxi_engine *engine, u32 *num);
 };
 
 /**
@@ -215,4 +226,22 @@ sunxi_engine_mode_set(struct sunxi_engine *engine,
if (engine->ops && engine->ops->mode_set)
engine->ops->mode_set(engine, mode);
 }
+
+/**
+ * sunxi_engine_get_supported_formats - Provide array of supported formats
+ * @engine:pointer to the engine
+ * @num:   pointer to variable, which will hold number of formats
+ *
+ * This list can be used for format negotiation by bridge.
+ */
+static inline u32 *
+sunxi_engine_get_supported_formats(struct sunxi_engine *engine, u32 *num)
+{
+   if (engine->ops && engine->ops->get_supported_fmts)
+   return engine->ops->get_supported_fmts(engine, num);
+
+   *num = 0;
+
+   return NULL;
+}
 #endif /* _SUNXI_ENGINE_H_ */
-- 
2.46.1



[PATCH v4 05/26] drm: sun4i: de3: Add YUV formatter module

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

The display engine formatter (FMT) module is present in the DE3 engine
and provides YUV444 to YUV422/YUV420 conversion, format re-mapping and
color depth conversion.

Add support for this module.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/Makefile |  3 +-
 drivers/gpu/drm/sun4i/sun50i_fmt.c | 82 ++
 drivers/gpu/drm/sun4i/sun50i_fmt.h | 32 
 3 files changed, 116 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index bad7497a0d11e..3f516329f51ee 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_fmt.o
 
 sun4i-tcon-y   += sun4i_crtc.o
 sun4i-tcon-y   += sun4i_tcon_dclk.o
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.c 
b/drivers/gpu/drm/sun4i/sun50i_fmt.c
new file mode 100644
index 0..050a8716ae862
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Jernej Skrabec 
+ */
+
+#include 
+
+#include "sun50i_fmt.h"
+
+static bool sun50i_fmt_is_10bit(u32 format)
+{
+   switch (format) {
+   case MEDIA_BUS_FMT_RGB101010_1X30:
+   case MEDIA_BUS_FMT_YUV10_1X30:
+   case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+   case MEDIA_BUS_FMT_UYVY10_1X20:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static u32 sun50i_fmt_get_colorspace(u32 format)
+{
+   switch (format) {
+   case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+   case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+   return SUN50I_FMT_CS_YUV420;
+   case MEDIA_BUS_FMT_UYVY8_1X16:
+   case MEDIA_BUS_FMT_UYVY10_1X20:
+   return SUN50I_FMT_CS_YUV422;
+   default:
+   return SUN50I_FMT_CS_YUV444RGB;
+   }
+}
+
+static void sun50i_fmt_de3_limits(u32 *limits, u32 colorspace, bool bit10)
+{
+   if (colorspace != SUN50I_FMT_CS_YUV444RGB) {
+   limits[0] = SUN50I_FMT_LIMIT(64, 940);
+   limits[1] = SUN50I_FMT_LIMIT(64, 960);
+   limits[2] = SUN50I_FMT_LIMIT(64, 960);
+   } else if (bit10) {
+   limits[0] = SUN50I_FMT_LIMIT(0, 1023);
+   limits[1] = SUN50I_FMT_LIMIT(0, 1023);
+   limits[2] = SUN50I_FMT_LIMIT(0, 1023);
+   } else {
+   limits[0] = SUN50I_FMT_LIMIT(0, 1021);
+   limits[1] = SUN50I_FMT_LIMIT(0, 1021);
+   limits[2] = SUN50I_FMT_LIMIT(0, 1021);
+   }
+}
+
+void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
+ u16 height, u32 format)
+{
+   u32 colorspace, limit[3], base;
+   struct regmap *regs;
+   bool bit10;
+
+   colorspace = sun50i_fmt_get_colorspace(format);
+   bit10 = sun50i_fmt_is_10bit(format);
+   base = SUN50I_FMT_DE3;
+   regs = sun8i_blender_regmap(mixer);
+
+   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+
+   regmap_write(regs, SUN50I_FMT_CTRL(base), 0);
+
+   regmap_write(regs, SUN50I_FMT_SIZE(base),
+SUN8I_MIXER_SIZE(width, height));
+   regmap_write(regs, SUN50I_FMT_SWAP(base), 0);
+   regmap_write(regs, SUN50I_FMT_DEPTH(base), bit10);
+   regmap_write(regs, SUN50I_FMT_FORMAT(base), colorspace);
+   regmap_write(regs, SUN50I_FMT_COEF(base), 0);
+
+   regmap_write(regs, SUN50I_FMT_LMT_Y(base), limit[0]);
+   regmap_write(regs, SUN50I_FMT_LMT_C0(base), limit[1]);
+   regmap_write(regs, SUN50I_FMT_LMT_C1(base), limit[2]);
+
+   regmap_write(regs, SUN50I_FMT_CTRL(base), 1);
+}
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.h 
b/drivers/gpu/drm/sun4i/sun50i_fmt.h
new file mode 100644
index 0..4127f7206aade
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) Jernej Skrabec 
+ */
+
+#ifndef _SUN50I_FMT_H_
+#define _SUN50I_FMT_H_
+
+#include "sun8i_mixer.h"
+
+#define SUN50I_FMT_DE3 0xa8000
+
+#define SUN50I_FMT_CTRL(base)   ((base) + 0x00)
+#define SUN50I_FMT_SIZE(base)   ((base) + 0x04)
+#define SUN50I_FMT_SWAP(base)   ((base) + 0x08)
+#define SUN50I_FMT_DEPTH(base)  ((base) + 0x0c)
+#define SUN50I_FMT_FORMAT(base) ((base) + 0x10)
+#define SUN50I_FMT_COEF(base)   ((base) + 0x14)
+#define SUN50I_FMT_LMT_Y(base)  ((base) + 0x20)
+#define SUN50I_FMT_LMT_C0(base) ((ba

[PATCH v4 04/26] drm: sun4i: de2: Initialize layer fields earlier

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

drm_universal_plane_init() can already call some callbacks, like
format_mod_supported, during initialization. Because of that, fields
should be initialized beforehand.

Signed-off-by: Jernej Skrabec 
Co-developed-by: Ryan Walklin 
Signed-off-by: Ryan Walklin 
Reviewed-by: Chen-Yu Tsai 
---
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 9 +
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 9 +
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index aa987bca1dbb9..cb9b694fef101 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -295,6 +295,11 @@ struct sun8i_layer *sun8i_ui_layer_init_one(struct 
drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
 
+   layer->mixer = mixer;
+   layer->type = SUN8I_LAYER_TYPE_UI;
+   layer->channel = channel;
+   layer->overlay = 0;
+
if (index == 0)
type = DRM_PLANE_TYPE_PRIMARY;
 
@@ -325,10 +330,6 @@ struct sun8i_layer *sun8i_ui_layer_init_one(struct 
drm_device *drm,
}
 
drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs);
-   layer->mixer = mixer;
-   layer->type = SUN8I_LAYER_TYPE_UI;
-   layer->channel = channel;
-   layer->overlay = 0;
 
return layer;
 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index f3a5329351caa..3c657b069d1f4 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -478,6 +478,11 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct 
drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
 
+   layer->mixer = mixer;
+   layer->type = SUN8I_LAYER_TYPE_VI;
+   layer->channel = index;
+   layer->overlay = 0;
+
if (mixer->cfg->is_de3) {
formats = sun8i_vi_layer_de3_formats;
format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
@@ -536,10 +541,6 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct 
drm_device *drm,
}
 
drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
-   layer->mixer = mixer;
-   layer->type = SUN8I_LAYER_TYPE_VI;
-   layer->channel = index;
-   layer->overlay = 0;
 
return layer;
 }
-- 
2.46.1



[PATCH v4 03/26] drm: sun4i: de2/de3: call csc setup also for UI layer

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Currently, only VI layer calls CSC setup function. This comes from DE2
limitation, which doesn't have CSC unit for UI layers. However, DE3 has
separate CSC units for each layer. This allows display pipeline to make
output signal in different color spaces. To support both use cases, add
a call to CSC setup function also in UI layer code. For DE2, this will
be a no-op, but it will allow DE3 to output signal in multiple formats.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c  | 8 +---
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 6 ++
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 0dcbc0866ae82..68d955c63b05b 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -209,8 +209,10 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
return;
}
 
-   base = ccsc_base[mixer->cfg->ccsc][layer];
+   if (layer < mixer->cfg->vi_num) {
+   base = ccsc_base[mixer->cfg->ccsc][layer];
 
-   sun8i_csc_setup(mixer->engine.regs, base,
-   fmt_type, encoding, range);
+   sun8i_csc_setup(mixer->engine.regs, base,
+   fmt_type, encoding, range);
+   }
 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index b90e5edef4e88..aa987bca1dbb9 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -20,6 +20,7 @@
 #include 
 #include 
 
+#include "sun8i_csc.h"
 #include "sun8i_mixer.h"
 #include "sun8i_ui_layer.h"
 #include "sun8i_ui_scaler.h"
@@ -135,6 +136,11 @@ static int sun8i_ui_layer_update_formats(struct 
sun8i_mixer *mixer, int channel,
   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
 
+   /* Note: encoding and range arguments are ignored for RGB */
+   sun8i_csc_set_ccsc(mixer, channel, FORMAT_TYPE_RGB,
+  DRM_COLOR_YCBCR_BT601,
+  DRM_COLOR_YCBCR_FULL_RANGE);
+
return 0;
 }
 
-- 
2.46.1



[PATCH v4 02/26] drm: sun4i: de2/de3: Merge CSC functions into one

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

At the moment the colour space conversion is handled by two functions:
one to setup the conversion parameters, and another one to enable the
conversion. Merging both into one gives more flexibility for upcoming
extensions to support whole YUV pipelines, in the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c  | 89 ++
 drivers/gpu/drm/sun4i/sun8i_csc.h  |  9 ++-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 11 +---
 3 files changed, 40 insertions(+), 69 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 6ebd1c3aa3ab5..0dcbc0866ae82 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -107,23 +107,28 @@ static const u32 yuv2rgb_de3[2][3][12] = {
},
 };
 
-static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
-  enum format_type fmt_type,
-  enum drm_color_encoding encoding,
-  enum drm_color_range range)
+static void sun8i_csc_setup(struct regmap *map, u32 base,
+   enum format_type fmt_type,
+   enum drm_color_encoding encoding,
+   enum drm_color_range range)
 {
+   u32 base_reg, val;
const u32 *table;
-   u32 base_reg;
int i;
 
table = yuv2rgb[range][encoding];
 
switch (fmt_type) {
+   case FORMAT_TYPE_RGB:
+   val = 0;
+   break;
case FORMAT_TYPE_YUV:
+   val = SUN8I_CSC_CTRL_EN;
base_reg = SUN8I_CSC_COEFF(base, 0);
regmap_bulk_write(map, base_reg, table, 12);
break;
case FORMAT_TYPE_YVU:
+   val = SUN8I_CSC_CTRL_EN;
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
base_reg = SUN8I_CSC_COEFF(base, i + 1);
@@ -135,28 +140,37 @@ static void sun8i_csc_set_coefficients(struct regmap 
*map, u32 base,
}
break;
default:
+   val = 0;
DRM_WARN("Wrong CSC mode specified.\n");
return;
}
+
+   regmap_write(map, SUN8I_CSC_CTRL(base), val);
 }
 
-static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
-   enum format_type fmt_type,
-   enum drm_color_encoding encoding,
-   enum drm_color_range range)
+static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
+enum format_type fmt_type,
+enum drm_color_encoding encoding,
+enum drm_color_range range)
 {
+   u32 addr, val, mask;
const u32 *table;
-   u32 addr;
int i;
 
+   mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
table = yuv2rgb_de3[range][encoding];
 
switch (fmt_type) {
+   case FORMAT_TYPE_RGB:
+   val = 0;
+   break;
case FORMAT_TYPE_YUV:
+   val = mask;
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, addr, table, 12);
break;
case FORMAT_TYPE_YVU:
+   val = mask;
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
addr = 
SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
@@ -173,67 +187,30 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap 
*map, int layer,
}
break;
default:
+   val = 0;
DRM_WARN("Wrong CSC mode specified.\n");
return;
}
-}
-
-static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
-{
-   u32 val;
-
-   if (enable)
-   val = SUN8I_CSC_CTRL_EN;
-   else
-   val = 0;
-
-   regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
-}
-
-static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable)
-{
-   u32 val, mask;
-
-   mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
-
-   if (enable)
-   val = mask;
-   else
-   val = 0;
 
regmap_update_bits(map, SUN50I_MIXER_BLEND_CSC_CTL(DE3_BLD_BASE),
   mask, val);
 }
 
-void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
-enum format_type fmt_type,
-enum drm_color_encoding encoding,
-enum drm_color_range range)
-{
-   u32 base

[PATCH v4 01/26] drm: sun4i: de2/de3: Change CSC argument

2024-09-21 Thread Ryan Walklin
From: Jernej Skrabec 

Currently, CSC module takes care only for converting YUV to RGB.
However, DE3 is more suited to work in YUV color space. Change CSC mode
argument to format type to be more neutral. New argument only tells
layer format type and doesn't imply output type.

This commit doesn't make any functional change.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c  | 22 +++---
 drivers/gpu/drm/sun4i/sun8i_csc.h  | 10 +-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 16 
 3 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 58480d8e4f704..6ebd1c3aa3ab5 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -108,7 +108,7 @@ static const u32 yuv2rgb_de3[2][3][12] = {
 };
 
 static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
-  enum sun8i_csc_mode mode,
+  enum format_type fmt_type,
   enum drm_color_encoding encoding,
   enum drm_color_range range)
 {
@@ -118,12 +118,12 @@ static void sun8i_csc_set_coefficients(struct regmap 
*map, u32 base,
 
table = yuv2rgb[range][encoding];
 
-   switch (mode) {
-   case SUN8I_CSC_MODE_YUV2RGB:
+   switch (fmt_type) {
+   case FORMAT_TYPE_YUV:
base_reg = SUN8I_CSC_COEFF(base, 0);
regmap_bulk_write(map, base_reg, table, 12);
break;
-   case SUN8I_CSC_MODE_YVU2RGB:
+   case FORMAT_TYPE_YVU:
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
base_reg = SUN8I_CSC_COEFF(base, i + 1);
@@ -141,7 +141,7 @@ static void sun8i_csc_set_coefficients(struct regmap *map, 
u32 base,
 }
 
 static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
-   enum sun8i_csc_mode mode,
+   enum format_type fmt_type,
enum drm_color_encoding encoding,
enum drm_color_range range)
 {
@@ -151,12 +151,12 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap 
*map, int layer,
 
table = yuv2rgb_de3[range][encoding];
 
-   switch (mode) {
-   case SUN8I_CSC_MODE_YUV2RGB:
+   switch (fmt_type) {
+   case FORMAT_TYPE_YUV:
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, addr, table, 12);
break;
-   case SUN8I_CSC_MODE_YVU2RGB:
+   case FORMAT_TYPE_YVU:
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
addr = 
SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
@@ -206,7 +206,7 @@ static void sun8i_de3_ccsc_enable(struct regmap *map, int 
layer, bool enable)
 }
 
 void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
-enum sun8i_csc_mode mode,
+enum format_type fmt_type,
 enum drm_color_encoding encoding,
 enum drm_color_range range)
 {
@@ -214,14 +214,14 @@ void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer 
*mixer, int layer,
 
if (mixer->cfg->is_de3) {
sun8i_de3_ccsc_set_coefficients(mixer->engine.regs, layer,
-   mode, encoding, range);
+   fmt_type, encoding, range);
return;
}
 
base = ccsc_base[mixer->cfg->ccsc][layer];
 
sun8i_csc_set_coefficients(mixer->engine.regs, base,
-  mode, encoding, range);
+  fmt_type, encoding, range);
 }
 
 void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h 
b/drivers/gpu/drm/sun4i/sun8i_csc.h
index 828b86fd0cabb..7322770f39f03 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
@@ -22,14 +22,14 @@ struct sun8i_mixer;
 
 #define SUN8I_CSC_CTRL_EN  BIT(0)
 
-enum sun8i_csc_mode {
-   SUN8I_CSC_MODE_OFF,
-   SUN8I_CSC_MODE_YUV2RGB,
-   SUN8I_CSC_MODE_YVU2RGB,
+enum format_type {
+   FORMAT_TYPE_RGB,
+   FORMAT_TYPE_YUV,
+   FORMAT_TYPE_YVU,
 };
 
 void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
-enum sun8i_csc_mode mode,
+enum format_type fmt_type,
   

[PATCH v4 00/26] drm: sun4i: add Display Engine 3.3 (DE33) support

2024-09-21 Thread Ryan Walklin
Hi,

V4 of this patch series adding support for the Allwinner DE33 display engine 
variant. V4 is rebased on torvalds/master with the 'drm-next-2024-09-19' branch 
merged, with no code changes required. V3 was in turn rebased on top of the 
layer init and modesetting changes merged for 6.11. No functional changes from 
V3, fixes and reviews from previous V1-3 added, and a single #include 
correction.

Original blurb below:

There is existing mainline support for the DE2 and DE3 AllWinner display 
pipeline IP blocks, used in the A64 and H6 among others, however the H700 (as 
well as the H616/H618 and the T507 automotive SoC) have a newer version of the 
Display Engine (v3.3/DE33) which adds additional high-resolution support as 
well as YUV colour formats and AFBC compression support.

This patch set adds DE33 support, following up from the previous RFC [1], with 
significant rework to break down the previous relatively complex set into more 
logical steps, detailed below.

1. Refactor the existing DE2/DE3 code in readiness to support YUV colour 
formats in the DE3 engine (patches 1-4).
2. Add YUV420 colour format support in the DE3 driver (patches 5-12).
3. Replace the is_de3 mixer flag with an enum to support multiple DE versions 
(patch 13).
4. Refactor the mixer, vi_scaler and some register code to merge common init 
code and more easily support multiple DE versions (patches 14-17).
5. Add Arm Frame Buffer Compression (AFBC) compressed buffer support to the DE3 
driver. This is currently only supported for VI layers (for HW-decoded video 
output) but is well integrated into these changes and a subsequent patchset to 
enable the Video Engine is planned. (patch 18).
6. Add DT bindings for the DE33 engine. (patches 19-21).
7. Extend the DE2/3 driver for the DE33, comprising clock, mixer, vi_scaler, 
fmt and csc module support (patches 22-26).

Further patchsets are planned to support HDMI and the LCD timing controller 
present in these SoCs.

Regards,

Ryan

Jernej Skrabec (22):
  drm: sun4i: de2/de3: Change CSC argument
  drm: sun4i: de2/de3: Merge CSC functions into one
  drm: sun4i: de2/de3: call csc setup also for UI layer
  drm: sun4i: de2: Initialize layer fields earlier
  drm: sun4i: de3: Add YUV formatter module
  drm: sun4i: de3: add format enumeration function to engine
  drm: sun4i: de3: add formatter flag to mixer config
  drm: sun4i: de3: add YUV support to the DE3 mixer
  drm: sun4i: de3: pass engine reference to ccsc setup function
  drm: sun4i: de3: add YUV support to the color space correction module
  drm: sun4i: de3: add YUV support to the TCON
  drm: sun4i: support YUV formats in VI scaler
  drm: sun4i: de2/de3: add mixer version enum
  drm: sun4i: de2/de3: refactor mixer initialisation
  drm: sun4i: vi_scaler refactor vi_scaler enablement
  drm: sun4i: de2/de3: add generic blender register reference function
  drm: sun4i: de2/de3: use generic register reference function for layer
configuration
  drm: sun4i: de3: Implement AFBC support
  drm: sun4i: de33: mixer: add Display Engine 3.3 (DE33) support
  drm: sun4i: de33: vi_scaler: add Display Engine 3.3 (DE33) support
  drm: sun4i: de33: fmt: add Display Engine 3.3 (DE33) support
  drm: sun4i: de33: csc: add Display Engine 3.3 (DE33) support

Ryan Walklin (4):
  dt-bindings: allwinner: add H616 DE33 bus binding
  dt-bindings: allwinner: add H616 DE33 clock binding
  dt-bindings: allwinner: add H616 DE33 mixer binding
  clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support

 .../bus/allwinner,sun50i-a64-de2.yaml |   4 +-
 .../clock/allwinner,sun8i-a83t-de2-clk.yaml   |   1 +
 .../allwinner,sun8i-a83t-de2-mixer.yaml   |   1 +
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c  |  25 ++
 drivers/gpu/drm/sun4i/Makefile|   3 +-
 drivers/gpu/drm/sun4i/sun4i_tcon.c|  26 +-
 drivers/gpu/drm/sun4i/sun50i_afbc.c   | 250 +
 drivers/gpu/drm/sun4i/sun50i_afbc.h   |  87 +
 drivers/gpu/drm/sun4i/sun50i_fmt.c|  99 +
 drivers/gpu/drm/sun4i/sun50i_fmt.h|  33 ++
 drivers/gpu/drm/sun4i/sun8i_csc.c | 341 +++---
 drivers/gpu/drm/sun4i/sun8i_csc.h |  20 +-
 drivers/gpu/drm/sun4i/sun8i_mixer.c   | 229 +---
 drivers/gpu/drm/sun4i/sun8i_mixer.h   |  31 +-
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c|  41 ++-
 drivers/gpu/drm/sun4i/sun8i_ui_scaler.c   |   2 +-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c| 134 +--
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c   | 115 --
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.h   |   2 +-
 drivers/gpu/drm/sun4i/sunxi_engine.h  |  34 ++
 20 files changed, 1271 insertions(+), 207 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.h
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.h

-- 
2.46.1



[PATCH v3 2/2] drm: panel: nv3052c: Correct WL-355608-A8 panel compatible

2024-09-03 Thread Ryan Walklin
As per the previous dt-binding commit, update the WL-355608-A8 panel
compatible to reflect the the integrating device vendor and name as the
panel OEM is unknown.

Signed-off-by: Ryan Walklin 

--
Changelog v2..v3:
- Use integrating device name with vendor prefix instead of OEM serial.

---
 drivers/gpu/drm/panel/panel-newvision-nv3052c.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c 
b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
index c5d3ead385550..d3baccfe6286b 100644
--- a/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
+++ b/drivers/gpu/drm/panel/panel-newvision-nv3052c.c
@@ -925,7 +925,7 @@ MODULE_DEVICE_TABLE(spi, nv3052c_ids);
 static const struct of_device_id nv3052c_of_match[] = {
{ .compatible = "leadtek,ltk035c5444t", .data = 
<k035c5444t_panel_info },
{ .compatible = "fascontek,fs035vg158", .data = &fs035vg158_panel_info 
},
-   { .compatible = "wl-355608-a8", .data = &wl_355608_a8_panel_info },
+   { .compatible = "anbernic,rg35xx-plus-panel", .data = 
&wl_355608_a8_panel_info },
{ /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, nv3052c_of_match);
-- 
2.46.0



[PATCH v3 1/2] dt-bindings: display: panel: Rename WL-355608-A8 panel to rg35xx-*-panel

2024-09-03 Thread Ryan Walklin
The WL-355608-A8 is a 3.5" 640x480@60Hz RGB LCD display from an unknown
OEM used in a number of handheld gaming devices made by Anbernic.
Previously committed using the OEM serial without a vendor prefix,
however following subsequent discussion the preference is to use the
integrating device vendor and name where the OEM is unknown.

There are 4 RG35XX series devices from Anbernic based on an Allwinner
H700 SoC using this panel, with the -Plus variant introduced first.
Therefore the -Plus is used as the fallback for the subsequent -H,
-2024, and -SP devices.

Alter the filename and compatible string to reflect the convention.

Fixes: f08aac40639c ("drm: panel: nv3052c: Add WL-355608-A8 panel")
Signed-off-by: Ryan Walklin 

--
Changelog v1..v2:
- Use known panel serial for compatible name rather than referencing
  integrating devices as per feedback [1] from DT maintainers.

 Changelog v2..v3:
 - Use integrating device names rather than panel serial number for
   compatible string as per further maintainer feedback [2].

 [1] 
https://lore.kernel.org/linux-devicetree/8b4519fc-0fba-48fe-bfb4-318818b47...@app.fastmail.com/#t

 [2] 
https://lore.kernel.org/dri-devel/6ab54fb5-8723-457d-b5e6-483f82faf...@app.fastmail.com/
---
 ...08-a8.yaml => anbernic,rg35xx-plus-panel.yaml} | 15 +++
 1 file changed, 11 insertions(+), 4 deletions(-)
 rename Documentation/devicetree/bindings/display/panel/{wl-355608-a8.yaml => 
anbernic,rg35xx-plus-panel.yaml} (67%)

diff --git a/Documentation/devicetree/bindings/display/panel/wl-355608-a8.yaml 
b/Documentation/devicetree/bindings/display/panel/anbernic,rg35xx-plus-panel.yaml
similarity index 67%
rename from Documentation/devicetree/bindings/display/panel/wl-355608-a8.yaml
rename to 
Documentation/devicetree/bindings/display/panel/anbernic,rg35xx-plus-panel.yaml
index e552d01b52b97..1d67492ebd3b4 100644
--- a/Documentation/devicetree/bindings/display/panel/wl-355608-a8.yaml
+++ 
b/Documentation/devicetree/bindings/display/panel/anbernic,rg35xx-plus-panel.yaml
@@ -1,10 +1,10 @@
 # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 %YAML 1.2
 ---
-$id: http://devicetree.org/schemas/display/panel/wl-355608-a8.yaml#
+$id: 
http://devicetree.org/schemas/display/panel/anbernic,rg35xx-plus-panel.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: WL-355608-A8 3.5" (640x480 pixels) 24-bit IPS LCD panel
+title: Anbernic RG35XX series (WL-355608-A8) 3.5" 640x480 24-bit IPS LCD panel
 
 maintainers:
   - Ryan Walklin 
@@ -15,7 +15,14 @@ allOf:
 
 properties:
   compatible:
-const: wl-355608-a8
+oneOf:
+  - const: anbernic,rg35xx-plus-panel
+  - items:
+  - enum:
+  - anbernic,rg35xx-2024-panel
+  - anbernic,rg35xx-h-panel
+  - anbernic,rg35xx-sp-panel
+  - const: anbernic,rg35xx-plus-panel
 
   reg:
 maxItems: 1
@@ -40,7 +47,7 @@ examples:
 #size-cells = <0>;
 
 panel@0 {
-compatible = "wl-355608-a8";
+compatible = "anbernic,rg35xx-plus-panel";
 reg = <0>;
 
 spi-3wire;
-- 
2.46.0



[PATCH v3 0/2] Correct WL-355608-A8 panel compatible

2024-09-03 Thread Ryan Walklin
Hi,

V3 of this patch updated to reflect discussion and agreement to use the 
integrating vendor prefix and device names for this display panel.

The previous patch adding support for this panel [1] referred to previously by 
its serial number only. As discussed after the patch was committed, the 
preference is to use the integrating device vendor and name in this 
circumstance.

This series corrects the panel compatible to reflect the integrating vendor 
(Anbernic, already in the vendor prefix table) and device names (adding 
fallbacks for the variants using the same panel), and updates the NV3052C panel 
driver with the new compatible.

Ryan Walklin (2):
  dt-bindings: display: panel: Rename WL-355608-A8 panel to
rg35xx-*-panel
  drm: panel: nv3052c: Correct WL-355608-A8 panel compatible

 ...08-a8.yaml => anbernic,rg35xx-plus-panel.yaml} | 15 +++
 drivers/gpu/drm/panel/panel-newvision-nv3052c.c   |  2 +-
 2 files changed, 12 insertions(+), 5 deletions(-)
 rename Documentation/devicetree/bindings/display/panel/{wl-355608-a8.yaml => 
anbernic,rg35xx-plus-panel.yaml} (67%)

-- 
2.46.0



Re: [PATCH 1/3] dt-bindings: display: panel: Rename WL-355608-A8 panel

2024-09-02 Thread Ryan Walklin
On Fri, 30 Aug 2024, at 7:56 PM, Neil Armstrong wrote:

Thanks Neil,

>
> The only valid compatible with anbernic would be to use the exact 
> device in use and not a wildcard,

> so you said the 3 devices using this panel are:
>   anbernic,rg35xx-2024
>   anbernic,rg35xx-plus
>   anbernic,rg35xx-h
> you should introduce 3 compatibles:
>   anbernic,rg35xx-2024-panel
>   anbernic,rg35xx-plus-panel
>   anbernic,rg35xx-h-panel
>
> but it's duplicating for nothing, to you should use fallbacks for 2 of 
> them to have in DT :
>
>   anbernic,rg35xx-2024-panel
>   anbernic,rg35xx-plus-panel, anbernic,rg35xx-2024-panel
>   anbernic,rg35xx-h-panel, anbernic,rg35xx-2024-panel
>
> and only use anbernic,rg35xx-2024-panel in the driver.
>
> In this case bindings should be like:
>properties:
>  compatible:
>oneOf:
>  - const: anbernic,rg35xx-2024-panel
>  - items:
>  - enum:
>  - anbernic,rg35xx-plus-panel
>  - anbernic,rg35xx-h-panel
>  - const: anbernic,rg35xx-2024-panel
>
> (of course I selected rg35xx-2024 as the primary one, it could be 
> another, usually the older one)
>

If all are happy with this approach I will resubmit a V2 with that change this 
evening.

Regards,

Ryan


Re: [PATCH 1/3] dt-bindings: display: panel: Rename WL-355608-A8 panel

2024-08-29 Thread Ryan Walklin



> On 28 Aug 2024, at 7:07 PM, Maxime Ripard  wrote:
> 
> On Tue, Aug 27, 2024 at 06:28:21PM GMT, Neil Armstrong wrote:
>>> Thanks both for the further feedback, agreed logical to use the
>>> device vendor and panel serial number, ie "anbernic,wl-355608-a8".
>>> Will post a V2 with a comment to that effect.
>> 
>> Well in this case we can keep "wl-355608-a8", because the panel vendor
>> _is not_ anbernic.
> 
> And it's not a generic or ubiquitous device either. We've been over
> this already, anbernic is the best we have.

I don’t have a strong preference either way but agree the anbernic vendor 
string is the best compromise.

Regards,

Ryan


Re: [PATCH v3 22/26] clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support

2024-08-18 Thread Ryan Walklin



On Mon, 19 Aug 2024, at 1:40 AM, Chen-Yu Tsai wrote:

Hi Chen-Yu, thanks for the reviews!

>> +#include 

> Still incorrect.

Whoops, only fixed the changelog it seems. Will correct.

Ryan


[PATCH v3 10/26] drm: sun4i: de3: add YUV support to the color space correction module

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Add coefficients and support for YUV formats to the display engine
colorspace and dynamic range correction submodule.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c | 164 +-
 1 file changed, 162 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 8a336ccb27d33..e12a81fa91083 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -5,6 +5,8 @@
 
 #include 
 
+#include 
+
 #include "sun8i_csc.h"
 #include "sun8i_mixer.h"
 
@@ -107,6 +109,135 @@ static const u32 yuv2rgb_de3[2][3][12] = {
},
 };
 
+/* always convert to limited mode */
+static const u32 rgb2yuv_de3[3][12] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x837A, 0x0001021D, 0x3221, 0x0040,
+   0xB41C, 0x6B03, 0xE0E1, 0x0200,
+   0xE0E1, 0x43B1, 0xDB6E, 0x0200,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x5D7C, 0x00013A7C, 0x1FBF, 0x0040,
+   0xCC78, 0x52A7, 0xE0E1, 0x0200,
+   0xE0E1, 0x33BE, 0xEB61, 0x0200,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x7384, 0x00012A21, 0x1A13, 0x0040,
+   0xC133, 0x5DEC, 0xE0E1, 0x0200,
+   0xE0E1, 0x3135, 0xEDEA, 0x0200,
+   },
+};
+
+/* always convert to limited mode */
+static const u32 yuv2yuv_de3[2][3][3][12] = {
+   [DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0002, 0x, 0x, 0x,
+   0x, 0x0002, 0x, 0x,
+   0x, 0x, 0x0002, 0x,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x0002, 0xC4D7, 0x9589, 0xFFC00040,
+   0x, 0x0002098B, 0x3AAF, 0xFE000200,
+   0x, 0x266D, 0x00020CF8, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x0002, 0xBFCE, 0xC5FF, 0xFFC00040,
+   0x, 0x00020521, 0x1F89, 0xFE000200,
+   0x, 0x2C87, 0x00020F07, 0xFE000200,
+   },
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0002, 0x32D9, 0x6226, 0xFFC00040,
+   0x, 0x0001FACE, 0xC759, 0xFE000200,
+   0x, 0xDAE7, 0x0001F780, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x0002, 0x, 0x, 0x,
+   0x, 0x0002, 0x, 0x,
+   0x, 0x, 0x0002, 0x,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x0002, 0xF782, 0x3036, 0xFFC00040,
+   0x, 0x0001FD99, 0xE5CA, 0xFE000200,
+   0x, 0x05E4, 0x0002015A, 0xFE000200,
+   },
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0002, 0x3B03, 0x34D2, 0xFFC00040,
+   0x, 0x0001FD8C, 0xE183, 0xFE000200,
+   0x, 0xD4F3, 0x0001F3FA, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT709] = {
+   0x0002, 0x0916, 0xD061, 0xFFC00040,
+   0x, 0x0002021C, 0x1A40, 0xFE000200,
+   0x, 0xFA19, 0x0001FE5A, 0xFE000200,
+   },
+   [DRM_COLOR_YCBCR_BT2020] = {
+   0x0002, 0x, 0x, 0x,
+   0x, 0x0002, 0x, 0x,
+   0x, 0x, 0x0002, 0x,
+   },
+   },
+   },
+   [DRM_COLOR_YCBCR_FULL_RANGE] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   [DRM_COLOR_YCBCR_BT601] = {
+   0x0001B7B8, 0x, 0x, 0x0040,
+   0x

[PATCH v3 15/26] drm: sun4i: vi_scaler refactor vi_scaler enablement

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

If the video scaler is required, then it is obligatory to set the
relevant register to enable it, so move this to the
sun8i_vi_scaler_setup() function.

This simplifies the alternate case (scaler not required) so replace the
vi_scaler_enable() function with a vi_scaler_disable() function.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c  |  3 +--
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 21 +++--
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.h |  2 +-
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index 4647e9bcccaa7..e348fd0a3d81c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -156,10 +156,9 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
sun8i_vi_scaler_setup(mixer, channel, src_w, src_h, dst_w,
  dst_h, hscale, vscale, hphase, vphase,
  format);
-   sun8i_vi_scaler_enable(mixer, channel, true);
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
-   sun8i_vi_scaler_enable(mixer, channel, false);
+   sun8i_vi_scaler_disable(mixer, channel);
}
 
regmap_write(mixer->engine.regs,
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index aa346c3beb303..e7242301b312c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -933,20 +933,13 @@ static void sun8i_vi_scaler_set_coeff_ui(struct regmap 
*map, u32 base,
  &table[offset], SUN8I_VI_SCALER_COEFF_COUNT);
 }
 
-void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
+void sun8i_vi_scaler_disable(struct sun8i_mixer *mixer, int layer)
 {
-   u32 val, base;
+   u32 base;
 
base = sun8i_vi_scaler_base(mixer, layer);
 
-   if (enable)
-   val = SUN8I_SCALER_VSU_CTRL_EN |
- SUN8I_SCALER_VSU_CTRL_COEFF_RDY;
-   else
-   val = 0;
-
-   regmap_write(mixer->engine.regs,
-SUN8I_SCALER_VSU_CTRL(base), val);
+   regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base), 0);
 }
 
 void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
@@ -982,6 +975,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int 
layer,
cvphase = vphase;
}
 
+   regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base),
+SUN8I_SCALER_VSU_CTRL_EN);
+
if (mixer->cfg->de_type >= sun8i_mixer_de3) {
u32 val;
 
@@ -1027,4 +1023,9 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int 
layer,
else
sun8i_vi_scaler_set_coeff_ui(mixer->engine.regs, base,
 hscale, vscale, format);
+
+   if (mixer->cfg->de_type <= sun8i_mixer_de3)
+   regmap_write(mixer->engine.regs, SUN8I_SCALER_VSU_CTRL(base),
+SUN8I_SCALER_VSU_CTRL_EN |
+SUN8I_SCALER_VSU_CTRL_COEFF_RDY);
 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
index 68f6593b369ab..e801bc7a4189e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
@@ -69,7 +69,7 @@
 #define SUN50I_SCALER_VSU_ANGLE_SHIFT(x)   (((x) << 16) & 0xF)
 #define SUN50I_SCALER_VSU_ANGLE_OFFSET(x)  ((x) & 0xFF)
 
-void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
+void sun8i_vi_scaler_disable(struct sun8i_mixer *mixer, int layer);
 void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
   u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
   u32 hscale, u32 vscale, u32 hphase, u32 vphase,
-- 
2.46.0



[PATCH v3 08/26] drm: sun4i: de3: add YUV support to the DE3 mixer

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

The mixer in the DE3 display engine supports YUV 8 and 10 bit
formats in addition to 8-bit RGB. Add the required register
configuration and format enumeration callback functions to the mixer,
and store the in-use output format (defaulting to RGB) and color
encoding in engine variables.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c  | 55 ++--
 drivers/gpu/drm/sun4i/sunxi_engine.h |  5 +++
 2 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 252827715de1d..af7c8f786eb83 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -23,7 +23,10 @@
 #include 
 #include 
 
+#include 
+
 #include "sun4i_drv.h"
+#include "sun50i_fmt.h"
 #include "sun8i_mixer.h"
 #include "sun8i_ui_layer.h"
 #include "sun8i_vi_layer.h"
@@ -390,12 +393,52 @@ static void sun8i_mixer_mode_set(struct sunxi_engine 
*engine,
 
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
 interlaced ? "on" : "off");
+
+   if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
+   val = SUN8I_MIXER_BLEND_COLOR_BLACK;
+   else
+   val = 0xff108080;
+
+   regmap_write(mixer->engine.regs,
+SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
+   regmap_write(mixer->engine.regs,
+SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
+
+   if (mixer->cfg->has_formatter)
+   sun50i_fmt_setup(mixer, mode->hdisplay,
+mode->vdisplay, mixer->engine.format);
+}
+
+static u32 *sun8i_mixer_get_supported_fmts(struct sunxi_engine *engine, u32 
*num)
+{
+   struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+   u32 *formats, count;
+
+   count = 0;
+
+   formats = kcalloc(5, sizeof(*formats), GFP_KERNEL);
+   if (!formats)
+   return NULL;
+
+   if (mixer->cfg->has_formatter) {
+   formats[count++] = MEDIA_BUS_FMT_UYYVYY10_0_5X30;
+   formats[count++] = MEDIA_BUS_FMT_YUV8_1X24;
+   formats[count++] = MEDIA_BUS_FMT_UYVY8_1X16;
+   formats[count++] = MEDIA_BUS_FMT_UYYVYY8_0_5X24;
+   }
+
+   formats[count++] = MEDIA_BUS_FMT_RGB888_1X24;
+
+   *num = count;
+
+   return formats;
 }
 
 static const struct sunxi_engine_ops sun8i_engine_ops = {
-   .commit = sun8i_mixer_commit,
-   .layers_init= sun8i_layers_init,
-   .mode_set   = sun8i_mixer_mode_set,
+   .commit = sun8i_mixer_commit,
+   .layers_init= sun8i_layers_init,
+   .mode_set   = sun8i_mixer_mode_set,
+   .get_supported_fmts = sun8i_mixer_get_supported_fmts,
 };
 
 static const struct regmap_config sun8i_mixer_regmap_config = {
@@ -456,7 +499,11 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
dev_set_drvdata(dev, mixer);
mixer->engine.ops = &sun8i_engine_ops;
mixer->engine.node = dev->of_node;
-
+   /* default output format, supported by all mixers */
+   mixer->engine.format = MEDIA_BUS_FMT_RGB888_1X24;
+   /* default color encoding, ignored with RGB I/O */
+   mixer->engine.encoding = DRM_COLOR_YCBCR_BT601;
+   
if (of_property_present(dev->of_node, "iommus")) {
/*
 * This assume we have the same DMA constraints for
diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h 
b/drivers/gpu/drm/sun4i/sunxi_engine.h
index c48cbc1aceb80..ffafc29b3a0c3 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -6,6 +6,8 @@
 #ifndef _SUNXI_ENGINE_H_
 #define _SUNXI_ENGINE_H_
 
+#include 
+
 struct drm_plane;
 struct drm_crtc;
 struct drm_device;
@@ -151,6 +153,9 @@ struct sunxi_engine {
 
int id;
 
+   u32 format;
+   enum drm_color_encoding encoding;
+
/* Engine list management */
struct list_headlist;
 };
-- 
2.46.0



[PATCH v3 17/26] drm: sun4i: de2/de3: use generic register reference function for layer configuration

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Use the new blender register lookup function where required in the layer
commit and update code.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 

--

Changelog v2..v3:
- Refactor for 6.11 layer init/modesetting changes
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c| 5 +++--
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 7 +--
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 6 --
 3 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 8871ca2858c80..23561f122a2b6 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -277,6 +277,7 @@ 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;
@@ -316,8 +317,8 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
}
 
-   regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), 
route);
-   regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
+   regmap_write(bld_regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
+   regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
 pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
 
regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index cb9b694fef101..7f1231cf0f012 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -24,6 +24,7 @@
 #include "sun8i_mixer.h"
 #include "sun8i_ui_layer.h"
 #include "sun8i_ui_scaler.h"
+#include "sun8i_vi_scaler.h"
 
 static void sun8i_ui_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
int overlay, struct drm_plane *plane)
@@ -52,6 +53,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
 {
struct drm_plane_state *state = plane->state;
u32 src_w, src_h, dst_w, dst_h;
+   struct regmap *bld_regs;
u32 bld_base, ch_base;
u32 outsize, insize;
u32 hphase, vphase;
@@ -60,6 +62,7 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
 channel, overlay);
 
bld_base = sun8i_blender_base(mixer);
+   bld_regs = sun8i_blender_regmap(mixer);
ch_base = sun8i_channel_base(mixer, channel);
 
src_w = drm_rect_width(&state->src) >> 16;
@@ -104,10 +107,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
 state->dst.x1, state->dst.y1);
DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
-   regmap_write(mixer->engine.regs,
+   regmap_write(bld_regs,
 SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
 SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
-   regmap_write(mixer->engine.regs,
+   regmap_write(bld_regs,
 SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
 outsize);
 
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index e348fd0a3d81c..d19349eecc9de 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -55,6 +55,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
struct drm_plane_state *state = plane->state;
const struct drm_format_info *format = state->fb->format;
u32 src_w, src_h, dst_w, dst_h;
+   struct regmap *bld_regs;
u32 bld_base, ch_base;
u32 outsize, insize;
u32 hphase, vphase;
@@ -66,6 +67,7 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
 channel, overlay);
 
bld_base = sun8i_blender_base(mixer);
+   bld_regs = sun8i_blender_regmap(mixer);
ch_base = sun8i_channel_base(mixer, channel);
 
src_w = drm_rect_width(&state->src) >> 16;
@@ -182,10 +184,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
DRM_DEBUG_DRIVER("Layer destination coordinates X: %d Y: %d\n",
 state->dst.x1, state->dst.y1);
DRM_DEBUG_DRIVER("Layer destination size W: %d H: %d\n", dst_w, dst_h);
-   regmap_write(mixer->engine.regs,
+   reg

[PATCH v3 13/26] drm: sun4i: de2/de3: add mixer version enum

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

The Allwinner DE2 and DE3 display engine mixers are currently identified
by a simple boolean flag. This will not scale to support additional DE
variants.

Convert the boolean flag to an enum.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c   |  2 +-
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 14 --
 drivers/gpu/drm/sun4i/sun8i_mixer.h | 11 ---
 drivers/gpu/drm/sun4i/sun8i_ui_scaler.c |  2 +-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c  |  8 
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c |  4 ++--
 6 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index e12a81fa91083..2d5a2cf7cba24 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -365,7 +365,7 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
 {
u32 base;
 
-   if (mixer->cfg->is_de3) {
+   if (mixer->cfg->de_type == sun8i_mixer_de3) {
sun8i_de3_ccsc_setup(&mixer->engine, layer,
 fmt_type, encoding, range);
return;
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index af7c8f786eb83..34f03ad18a26e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -584,7 +584,7 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
base = sun8i_blender_base(mixer);
 
/* Reset registers and disable unused sub-engines */
-   if (mixer->cfg->is_de3) {
+   if (mixer->cfg->de_type == sun8i_mixer_de3) {
for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
regmap_write(mixer->engine.regs, i, 0);
 
@@ -675,6 +675,7 @@ static void sun8i_mixer_remove(struct platform_device *pdev)
 
 static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.scaler_mask= 0xf,
.scanline_yuv   = 2048,
.ui_num = 3,
@@ -683,6 +684,7 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = 
{
 
 static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
.ccsc   = CCSC_MIXER1_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.scaler_mask= 0x3,
.scanline_yuv   = 2048,
.ui_num = 1,
@@ -691,6 +693,7 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = 
{
 
 static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 43200,
.scaler_mask= 0xf,
.scanline_yuv   = 2048,
@@ -700,6 +703,7 @@ static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
 
 static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0xf,
.scanline_yuv   = 2048,
@@ -709,6 +713,7 @@ static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
 
 static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
.ccsc   = CCSC_MIXER1_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0x3,
.scanline_yuv   = 2048,
@@ -717,6 +722,7 @@ static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
 };
 
 static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
+   .de_type = sun8i_mixer_de2,
.vi_num = 2,
.ui_num = 1,
.scaler_mask = 0x3,
@@ -727,6 +733,7 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
 
 static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
.ccsc   = CCSC_D1_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0x3,
.scanline_yuv   = 2048,
@@ -736,6 +743,7 @@ static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
 
 static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
.ccsc   = CCSC_MIXER1_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0x1,
.scanline_yuv   = 1024,
@@ -745,6 +753,7 @@ static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
 
 static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
+   .de_type= sun8i_mixer_de2,
.mod_rate   = 29700,
.scaler_mask= 0xf,
.scanline_yuv   = 4096,
@@ -754,6 +763,7 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = 
{
 
 static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
.ccsc   =

[PATCH v3 12/26] drm: sun4i: support YUV formats in VI scaler

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c | 85 +
 1 file changed, 58 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index 7ba75011adf9f..2e49a6e5f1f1c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -843,6 +843,11 @@ static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, 
int channel)
   DE2_VI_SCALER_UNIT_SIZE * channel;
 }
 
+static bool sun8i_vi_scaler_is_vi_plane(struct sun8i_mixer *mixer, int channel)
+{
+   return true;
+}
+
 static int sun8i_vi_scaler_coef_index(unsigned int step)
 {
unsigned int scale, int_part, float_part;
@@ -867,44 +872,65 @@ static int sun8i_vi_scaler_coef_index(unsigned int step)
}
 }
 
-static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base,
- u32 hstep, u32 vstep,
- const struct drm_format_info *format)
+static void sun8i_vi_scaler_set_coeff_vi(struct regmap *map, u32 base,
+u32 hstep, u32 vstep,
+const struct drm_format_info *format)
 {
const u32 *ch_left, *ch_right, *cy;
-   int offset, i;
+   int offset;
 
-   if (format->hsub == 1 && format->vsub == 1) {
-   ch_left = lan3coefftab32_left;
-   ch_right = lan3coefftab32_right;
-   cy = lan2coefftab32;
-   } else {
+   if (format->is_yuv) {
ch_left = bicubic8coefftab32_left;
ch_right = bicubic8coefftab32_right;
cy = bicubic4coefftab32;
+   } else {
+   ch_left = lan3coefftab32_left;
+   ch_right = lan3coefftab32_right;
+   cy = lan2coefftab32;
}
 
offset = sun8i_vi_scaler_coef_index(hstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
-   for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
-   regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, i),
-lan3coefftab32_left[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
-lan3coefftab32_right[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, i),
-ch_left[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, i),
-ch_right[offset + i]);
-   }
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, 0),
+ &lan3coefftab32_left[offset],
+ SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, 0),
+ &lan3coefftab32_right[offset],
+ SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_CHCOEFF0(base, 0),
+ &ch_left[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_CHCOEFF1(base, 0),
+ &ch_right[offset], SUN8I_VI_SCALER_COEFF_COUNT);
 
offset = sun8i_vi_scaler_coef_index(hstep) *
SUN8I_VI_SCALER_COEFF_COUNT;
-   for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++) {
-   regmap_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, i),
-lan2coefftab32[offset + i]);
-   regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
-cy[offset + i]);
-   }
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, 0),
+ &cy[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+}
+
+static void sun8i_vi_scaler_set_coeff_ui(struct regmap *map, u32 base,
+u32 hstep, u32 vstep,
+const struct drm_format_info *format)
+{
+   const u32 *table;
+   int offset;
+
+   offset = sun8i_vi_scaler_coef_index(hstep) *
+   SUN8I_VI_SCALER_COEFF_COUNT;
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YHCOEFF0(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+   offset = sun8i_vi_scaler_coef_index(vstep) *
+   SUN8I_VI_SCALER_COEFF_COUNT;
+   regmap_bulk_write(map, SUN8I_SCALER_VSU_YVCOEFF(base, 0),
+ &lan2coefftab32[offset], SUN8I_VI_SCALER_COEFF_COUNT);
+
+   table = format->is_yuv ? bicubic4coefftab32 : lan2coefftab32;
+   offset = sun8i_vi_scaler_coef_index(hstep) *
+   

[PATCH v3 09/26] drm: sun4i: de3: pass engine reference to ccsc setup function

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Configuration of the DE3 colorspace and dynamic range correction module
requires knowledge of the current video format and encoding.

Pass the display engine by reference to the csc setup function, rather
than the register map alone, to allow access to this information.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 68d955c63b05b..8a336ccb27d33 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -148,17 +148,19 @@ static void sun8i_csc_setup(struct regmap *map, u32 base,
regmap_write(map, SUN8I_CSC_CTRL(base), val);
 }
 
-static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
+static void sun8i_de3_ccsc_setup(struct sunxi_engine *engine, int layer,
 enum format_type fmt_type,
 enum drm_color_encoding encoding,
 enum drm_color_range range)
 {
u32 addr, val, mask;
+   struct regmap *map;
const u32 *table;
int i;
 
mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
table = yuv2rgb_de3[range][encoding];
+   map = engine->regs;
 
switch (fmt_type) {
case FORMAT_TYPE_RGB:
@@ -204,7 +206,7 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
u32 base;
 
if (mixer->cfg->is_de3) {
-   sun8i_de3_ccsc_setup(mixer->engine.regs, layer,
+   sun8i_de3_ccsc_setup(&mixer->engine, layer,
 fmt_type, encoding, range);
return;
}
-- 
2.46.0



[PATCH v3 23/26] drm: sun4i: de33: mixer: add Display Engine 3.3 (DE33) support

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

The DE33 is a newer version of the Allwinner Display Engine IP block,
found in the H616, H618, H700 and T507 SoCs. DE2 and DE3 are already
supported by the mainline driver.

Notable features (from the H616 datasheet and implemented):
- 4096 x 2048 (4K) output support
- AFBC ARM Frame Buffer Compression support
- YUV420 input support

The DE2 and DE3 engines have a blender register range within the
mixer engine register map, whereas the DE33 separates this out into
a separate display group, and adds a top register map.

Extend the mixer to support the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 108 
 drivers/gpu/drm/sun4i/sun8i_mixer.h |  16 -
 2 files changed, 107 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 23561f122a2b6..5a70d60e9a0eb 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -321,8 +321,12 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
 pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
 
-   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
-SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_DBUFF,
+SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+   else
+   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
+SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
 }
 
 static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
@@ -371,25 +375,33 @@ 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, *disp_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);
 
DRM_DEBUG_DRIVER("Updating global size W: %u H: %u\n",
 mode->hdisplay, mode->vdisplay);
 
-   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_SIZE, size);
-   regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
+   if (mixer->cfg->de_type == sun8i_mixer_de33) {
+   disp_regs = mixer->disp_regs;
+   regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_SIZE, size);
+   } else {
+   disp_regs = mixer->engine.regs;
+   regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE, size);
+   }
+   regmap_write(bld_regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
 
if (interlaced)
val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
else
val = 0;
 
-   regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
+   regmap_update_bits(bld_regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
 
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
@@ -400,10 +412,8 @@ static void sun8i_mixer_mode_set(struct sunxi_engine 
*engine,
else
val = 0xff108080;
 
-   regmap_write(mixer->engine.regs,
-SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
-   regmap_write(mixer->engine.regs,
-SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
+   regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
+   regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), 
val);
 
if (mixer->cfg->has_formatter)
sun50i_fmt_setup(mixer, mode->hdisplay,
@@ -443,12 +453,29 @@ static const struct sunxi_engine_ops sun8i_engine_ops = {
 };
 
 static const struct regmap_config sun8i_mixer_regmap_config = {
+   .name   = "layers",
.reg_bits   = 32,
.val_bits   = 32,
.reg_stride = 4,
.max_register   = 0xc, /* guessed */
 };
 
+static const struct regmap_config sun8i_top_regmap_config = {
+   .name   = "top",
+   .reg_bits   = 32,
+   .val_bits   = 32,
+   .reg_stride = 4,
+   .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   = 0x2,
+};
+
 static int sun8i_mixer_of_get_id(struc

[PATCH v3 20/26] dt-bindings: allwinner: add H616 DE33 clock binding

2024-08-17 Thread Ryan Walklin
The Allwinner H616 and variants have a new display engine revision
(DE33).

Add a clock binding for the DE33.

Signed-off-by: Ryan Walklin 
Acked-by: Conor Dooley 

--
Changelog v2..v3:
- Separate content into three patches for three separate subsystems
---
 .../devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml  | 1 +
 1 file changed, 1 insertion(+)

diff --git 
a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml 
b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
index 70369bd633e40..7fcd55d468d49 100644
--- a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
+++ b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
@@ -25,6 +25,7 @@ properties:
   - const: allwinner,sun50i-a64-de2-clk
   - const: allwinner,sun50i-h5-de2-clk
   - const: allwinner,sun50i-h6-de3-clk
+  - const: allwinner,sun50i-h616-de33-clk
   - items:
   - const: allwinner,sun8i-r40-de2-clk
   - const: allwinner,sun8i-h3-de2-clk
-- 
2.46.0



[PATCH v3 18/26] drm: sun4i: de3: Implement AFBC support

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Buffers, compressed with AFBC, are supported by the DE3 and above, and
are generally more efficient for memory transfers. Add support for them.

Currently it's implemented only for VI layers, but vendor code and
documentation suggest UI layers can have them too. However, I haven't
observed any SoC with such feature.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/Makefile |   2 +-
 drivers/gpu/drm/sun4i/sun50i_afbc.c| 250 +
 drivers/gpu/drm/sun4i/sun50i_afbc.h|  87 +
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c |  85 +++--
 4 files changed, 410 insertions(+), 14 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 3f516329f51ee..78290f1660fbd 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -17,7 +17,7 @@ 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 \
-  sun50i_fmt.o
+  sun50i_fmt.o sun50i_afbc.o
 
 sun4i-tcon-y   += sun4i_crtc.o
 sun4i-tcon-y   += sun4i_tcon_dclk.o
diff --git a/drivers/gpu/drm/sun4i/sun50i_afbc.c 
b/drivers/gpu/drm/sun4i/sun50i_afbc.c
new file mode 100644
index 0..b55e1c5533714
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_afbc.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Jernej Skrabec 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "sun50i_afbc.h"
+#include "sun8i_mixer.h"
+
+static u32 sun50i_afbc_get_base(struct sun8i_mixer *mixer, unsigned int 
channel)
+{
+   u32 base = sun8i_channel_base(mixer, channel);
+
+   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   return base + SUN50I_AFBC_CH_OFFSET;
+
+   return base + 0x4000;
+}
+
+bool sun50i_afbc_format_mod_supported(struct sun8i_mixer *mixer,
+ u32 format, u64 modifier)
+{
+   u64 mode;
+
+   if (modifier == DRM_FORMAT_MOD_INVALID)
+   return false;
+
+   if (modifier == DRM_FORMAT_MOD_LINEAR) {
+   if (format == DRM_FORMAT_YUV420_8BIT ||
+   format == DRM_FORMAT_YUV420_10BIT ||
+   format == DRM_FORMAT_Y210)
+   return false;
+   return true;
+   }
+
+   if (mixer->cfg->de_type == sun8i_mixer_de2)
+   return false;
+
+   mode = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+  AFBC_FORMAT_MOD_SPARSE |
+  AFBC_FORMAT_MOD_SPLIT;
+
+   switch (format) {
+   case DRM_FORMAT_RGBA:
+   case DRM_FORMAT_RGB888:
+   case DRM_FORMAT_RGB565:
+   case DRM_FORMAT_RGBA:
+   case DRM_FORMAT_RGBA5551:
+   case DRM_FORMAT_RGBA1010102:
+   mode |= AFBC_FORMAT_MOD_YTR;
+   break;
+   case DRM_FORMAT_YUYV:
+   case DRM_FORMAT_Y210:
+   case DRM_FORMAT_YUV420_8BIT:
+   case DRM_FORMAT_YUV420_10BIT:
+   break;
+   default:
+   return false;
+   }
+
+   return modifier == DRM_FORMAT_MOD_ARM_AFBC(mode);
+}
+
+void sun50i_afbc_atomic_update(struct sun8i_mixer *mixer, unsigned int channel,
+  struct drm_plane *plane)
+{
+   struct drm_plane_state *state = plane->state;
+   struct drm_framebuffer *fb = state->fb;
+   const struct drm_format_info *format = fb->format;
+   struct drm_gem_dma_object *gem;
+   u32 base, val, src_w, src_h;
+   u32 def_color0, def_color1;
+   struct regmap *regs;
+   dma_addr_t dma_addr;
+
+   base = sun50i_afbc_get_base(mixer, channel);
+   regs = mixer->engine.regs;
+
+   src_w = drm_rect_width(&state->src) >> 16;
+   src_h = drm_rect_height(&state->src) >> 16;
+
+   val = SUN50I_FBD_SIZE_HEIGHT(src_h);
+   val |= SUN50I_FBD_SIZE_WIDTH(src_w);
+   regmap_write(regs, SUN50I_FBD_SIZE(base), val);
+
+   val = SUN50I_FBD_BLK_SIZE_HEIGHT(DIV_ROUND_UP(src_h, 16));
+   val = SUN50I_FBD_BLK_SIZE_WIDTH(DIV_ROUND_UP(src_w, 16));
+   regmap_write(regs, SUN50I_FBD_BLK_SIZE(base), val);
+
+   val = SUN50I_FBD_SRC_CROP_TOP(0);
+   val |= SUN50I_FBD_SRC_CROP_LEFT(0);
+   regmap_write(regs, SUN50I_FBD_SRC_CROP(base), val);
+
+   val = SUN50I_FBD_LAY_CROP_TOP(state->src.y1 >> 16);
+   val |= SUN50I_FBD_LAY_CROP_LEFT(state->src.x1 >> 16);
+   regmap_write(regs, SUN50I_FBD_LAY_CROP(base), val);
+
+   /*
+* Default color 

[PATCH v3 24/26] drm: sun4i: de33: vi_scaler: add Display Engine 3.3 (DE33) support

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

The vi_scaler appears to be used in preference to the ui_scaler module
for hardware video scaling in the DE33.

Enable support for this scaler.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c  | 19 +++
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c |  7 ++-
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 7f1231cf0f012..180be9d67d9c3 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -95,12 +95,23 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
hscale = state->src_w / state->crtc_w;
vscale = state->src_h / state->crtc_h;
 
-   sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w,
- dst_h, hscale, vscale, hphase, vphase);
-   sun8i_ui_scaler_enable(mixer, channel, true);
+   if (mixer->cfg->de_type == sun8i_mixer_de33) {
+   sun8i_vi_scaler_setup(mixer, channel, src_w, src_h,
+ dst_w, dst_h, hscale, vscale,
+ hphase, vphase,
+ state->fb->format);
+   } else {
+   sun8i_ui_scaler_setup(mixer, channel, src_w, src_h,
+ dst_w, dst_h, hscale, vscale,
+ hphase, vphase);
+   sun8i_ui_scaler_enable(mixer, channel, true);
+   }
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
-   sun8i_ui_scaler_enable(mixer, channel, false);
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   sun8i_vi_scaler_disable(mixer, channel);
+   else
+   sun8i_ui_scaler_enable(mixer, channel, false);
}
 
/* Set base coordinates */
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index e7242301b312c..9c7f6e7d71d50 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -835,7 +835,9 @@ static const u32 bicubic4coefftab32[480] = {
 
 static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
 {
-   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return sun8i_channel_base(mixer, channel) + 0x3000;
+   else if (mixer->cfg->de_type == sun8i_mixer_de3)
return DE3_VI_SCALER_UNIT_BASE +
   DE3_VI_SCALER_UNIT_SIZE * channel;
else
@@ -845,6 +847,9 @@ static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, 
int channel)
 
 static bool sun8i_vi_scaler_is_vi_plane(struct sun8i_mixer *mixer, int channel)
 {
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return mixer->cfg->map[channel] < mixer->cfg->vi_num;
+
return true;
 }
 
-- 
2.46.0



[PATCH v3 26/26] drm: sun4i: de33: csc: add Display Engine 3.3 (DE33) support

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Like earlier DE versions, the DE33 has a CSC (Color Space Correction)
module. which provides color space conversion between BT2020/BT709, and
dynamic range conversion between SDR/ST2084/HLG.

Add support for the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c | 96 +++
 drivers/gpu/drm/sun4i/sun8i_csc.h |  3 +
 2 files changed, 99 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 2d5a2cf7cba24..45bd1ca06400e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -238,6 +238,14 @@ static const u32 yuv2yuv_de3[2][3][3][12] = {
},
 };
 
+static u32 sun8i_csc_base(struct sun8i_mixer *mixer, int layer)
+{
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return sun8i_channel_base(mixer, layer) - 0x800;
+   else
+   return ccsc_base[mixer->cfg->ccsc][layer];
+}
+
 static void sun8i_csc_setup(struct regmap *map, u32 base,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -358,6 +366,90 @@ static void sun8i_de3_ccsc_setup(struct sunxi_engine 
*engine, 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] &= 0x;
+   dst[10] &= 0x;
+   dst[14] &= 0x;
+}
+
+static void sun8i_de33_ccsc_setup(struct sun8i_mixer *mixer, int layer,
+ enum format_type fmt_type,
+ enum drm_color_encoding encoding,
+ enum drm_color_range range)
+{
+   u32 addr, val = 0, base, csc[15];
+   struct sunxi_engine *engine;
+   struct regmap *map;
+   const u32 *table;
+   int i;
+
+   table = yuv2rgb_de3[range][encoding];
+   base = sun8i_csc_base(mixer, layer);
+   engine = &mixer->engine;
+   map = engine->regs;
+
+   switch (fmt_type) {
+   case FORMAT_TYPE_RGB:
+   if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
+   break;
+   val = SUN8I_CSC_CTRL_EN;
+   sun8i_de33_convert_table(rgb2yuv_de3[engine->encoding], csc);
+   regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+   break;
+   case FORMAT_TYPE_YUV:
+   table = sun8i_csc_get_de3_yuv_table(encoding, range,
+   engine->format,
+   engine->encoding);
+   if (!table)
+   break;
+   val = SUN8I_CSC_CTRL_EN;
+   sun8i_de33_convert_table(table, csc);
+   regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+   break;
+   case FORMAT_TYPE_YVU:
+   table = sun8i_csc_get_de3_yuv_table(encoding, range,
+   engine->format,
+   engine->encoding);
+   if (!table)
+   table = yuv2yuv_de3[range][encoding][encoding];
+   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);
+}
+
 void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -369,6 +461,10 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
sun8i_de3_ccsc_setup(&mixer->engine, layer,
  

[PATCH v3 07/26] drm: sun4i: de3: add formatter flag to mixer config

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Only the DE3 (and newer) display engines have a formatter module. This
could be inferred from the is_de3 flag alone, however this will not
scale with addition of future DE versions in subsequent patches.

Add a separate flag to signal this in the mixer configuration.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 1 +
 drivers/gpu/drm/sun4i/sun8i_mixer.h | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index bd0fe2c6624e6..252827715de1d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -717,6 +717,7 @@ static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = 
{
 static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
.ccsc   = CCSC_MIXER0_LAYOUT,
.is_de3 = true,
+   .has_formatter  = 1,
.mod_rate   = 6,
.scaler_mask= 0xf,
.scanline_yuv   = 4096,
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h 
b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index d7898c9c9cc0c..8417b8fef2e1f 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -163,6 +163,7 @@ enum {
  * @mod_rate: module clock rate that needs to be set in order to have
  * a functional block.
  * @is_de3: true, if this is next gen display engine 3.0, false otherwise.
+ * @has_formatter: true, if mixer has formatter core, for 10-bit and YUV 
handling
  * @scaline_yuv: size of a scanline for VI scaler for YUV formats.
  */
 struct sun8i_mixer_cfg {
@@ -172,6 +173,7 @@ struct sun8i_mixer_cfg {
int ccsc;
unsigned long   mod_rate;
unsigned intis_de3 : 1;
+   unsigned inthas_formatter : 1;
unsigned intscanline_yuv;
 };
 
-- 
2.46.0



[PATCH v3 14/26] drm: sun4i: de2/de3: refactor mixer initialisation

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Now that the DE variant can be selected by enum, take the oppportunity
to factor out some common initialisation code to a separate function.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 

--
Changelog v1..v2:
- Combine base register allocation and initialisation in sun8i_mixer_init
- Whitespace fix
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 66 +++--
 1 file changed, 35 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 34f03ad18a26e..8871ca2858c80 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -468,6 +468,38 @@ static int sun8i_mixer_of_get_id(struct device_node *node)
return of_ep.id;
 }
 
+static void sun8i_mixer_init(struct sun8i_mixer *mixer)
+{
+   unsigned int base = sun8i_blender_base(mixer);
+   int plane_cnt, i;
+
+   /* Enable the mixer */
+   regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
+SUN8I_MIXER_GLOBAL_CTL_RT_EN);
+
+   /* Set background color to black */
+   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(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(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(mixer->engine.regs,
+SUN8I_MIXER_BLEND_MODE(base, i),
+SUN8I_MIXER_BLEND_MODE_DEF);
+
+   regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
+  SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
+}
+
 static int sun8i_mixer_bind(struct device *dev, struct device *master,
  void *data)
 {
@@ -476,8 +508,6 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
struct sun4i_drv *drv = drm->dev_private;
struct sun8i_mixer *mixer;
void __iomem *regs;
-   unsigned int base;
-   int plane_cnt;
int i, ret;
 
/*
@@ -581,8 +611,6 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
 
list_add_tail(&mixer->engine.list, &drv->engine_list);
 
-   base = sun8i_blender_base(mixer);
-
/* Reset registers and disable unused sub-engines */
if (mixer->cfg->de_type == sun8i_mixer_de3) {
for (i = 0; i < DE3_MIXER_UNIT_SIZE; i += 4)
@@ -598,7 +626,7 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
regmap_write(mixer->engine.regs, SUN50I_MIXER_FMT_EN, 0);
regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC0_EN, 0);
regmap_write(mixer->engine.regs, SUN50I_MIXER_CDC1_EN, 0);
-   } else {
+   } else if (mixer->cfg->de_type == sun8i_mixer_de2) {
for (i = 0; i < DE2_MIXER_UNIT_SIZE; i += 4)
regmap_write(mixer->engine.regs, i, 0);
 
@@ -611,32 +639,8 @@ static int sun8i_mixer_bind(struct device *dev, struct 
device *master,
regmap_write(mixer->engine.regs, SUN8I_MIXER_DCSC_EN, 0);
}
 
-   /* Enable the mixer */
-   regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
-SUN8I_MIXER_GLOBAL_CTL_RT_EN);
-
-   /* Set background color to black */
-   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(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
-SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(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(mixer->engine.regs,
-SUN8I_MIXER_BLEND_MODE(base, i),
-SUN8I_MIXER_BLEND_MODE_DEF);
-
-   regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
-  SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
-
+   sun8i_mixer_init(mixer);
+   
return 0;
 
 err_disable_bus_clk:
-- 
2.46.0



[PATCH v3 06/26] drm: sun4i: de3: add format enumeration function to engine

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

The DE3 display engine supports YUV formats in addition to RGB.

Add an optional format enumeration function to the engine.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sunxi_engine.h | 29 
 1 file changed, 29 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sunxi_engine.h 
b/drivers/gpu/drm/sun4i/sunxi_engine.h
index ec0c4932f15cf..c48cbc1aceb80 100644
--- a/drivers/gpu/drm/sun4i/sunxi_engine.h
+++ b/drivers/gpu/drm/sun4i/sunxi_engine.h
@@ -123,6 +123,17 @@ struct sunxi_engine_ops {
 */
void (*mode_set)(struct sunxi_engine *engine,
 const struct drm_display_mode *mode);
+
+   /**
+* @get_supported_fmts
+*
+* This callback is used to enumerate all supported output
+* formats by the engine. They are used for bridge format
+* negotiation.
+*
+* This function is optional.
+*/
+   u32 *(*get_supported_fmts)(struct sunxi_engine *engine, u32 *num);
 };
 
 /**
@@ -215,4 +226,22 @@ sunxi_engine_mode_set(struct sunxi_engine *engine,
if (engine->ops && engine->ops->mode_set)
engine->ops->mode_set(engine, mode);
 }
+
+/**
+ * sunxi_engine_get_supported_formats - Provide array of supported formats
+ * @engine:pointer to the engine
+ * @num:   pointer to variable, which will hold number of formats
+ *
+ * This list can be used for format negotiation by bridge.
+ */
+static inline u32 *
+sunxi_engine_get_supported_formats(struct sunxi_engine *engine, u32 *num)
+{
+   if (engine->ops && engine->ops->get_supported_fmts)
+   return engine->ops->get_supported_fmts(engine, num);
+
+   *num = 0;
+
+   return NULL;
+}
 #endif /* _SUNXI_ENGINE_H_ */
-- 
2.46.0



[PATCH v3 25/26] drm: sun4i: de33: fmt: add Display Engine 3.3 (DE33) support

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Like the DE3, the DE33 has a FMT (formatter) module, which
provides YUV444 to YUV422/YUV420 conversion, format re-mapping and color
depth conversion, although the DE33 module appears significantly more
capable, including up to 4K video support.

Add support for the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun50i_fmt.c | 21 +++--
 drivers/gpu/drm/sun4i/sun50i_fmt.h |  1 +
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.c 
b/drivers/gpu/drm/sun4i/sun50i_fmt.c
index 050a8716ae862..39682d4e6d208 100644
--- a/drivers/gpu/drm/sun4i/sun50i_fmt.c
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.c
@@ -51,6 +51,19 @@ static void sun50i_fmt_de3_limits(u32 *limits, u32 
colorspace, bool bit10)
}
 }
 
+static void sun50i_fmt_de33_limits(u32 *limits, u32 colorspace)
+{
+   if (colorspace == SUN50I_FMT_CS_YUV444RGB) {
+   limits[0] = SUN50I_FMT_LIMIT(0, 4095);
+   limits[1] = SUN50I_FMT_LIMIT(0, 4095);
+   limits[2] = SUN50I_FMT_LIMIT(0, 4095);
+   } else {
+   limits[0] = SUN50I_FMT_LIMIT(256, 3840);
+   limits[1] = SUN50I_FMT_LIMIT(256, 3840);
+   limits[2] = SUN50I_FMT_LIMIT(256, 3840);
+   }
+}
+
 void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
  u16 height, u32 format)
 {
@@ -60,10 +73,14 @@ void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
 
colorspace = sun50i_fmt_get_colorspace(format);
bit10 = sun50i_fmt_is_10bit(format);
-   base = SUN50I_FMT_DE3;
+   base = mixer->cfg->de_type == sun8i_mixer_de3 ?
+   SUN50I_FMT_DE3 : SUN50I_FMT_DE33;
regs = sun8i_blender_regmap(mixer);
 
-   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+   else
+   sun50i_fmt_de33_limits(limit, colorspace);
 
regmap_write(regs, SUN50I_FMT_CTRL(base), 0);
 
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.h 
b/drivers/gpu/drm/sun4i/sun50i_fmt.h
index 4127f7206aade..3e60d5c788b39 100644
--- a/drivers/gpu/drm/sun4i/sun50i_fmt.h
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.h
@@ -9,6 +9,7 @@
 #include "sun8i_mixer.h"
 
 #define SUN50I_FMT_DE3 0xa8000
+#define SUN50I_FMT_DE33 0x5000
 
 #define SUN50I_FMT_CTRL(base)   ((base) + 0x00)
 #define SUN50I_FMT_SIZE(base)   ((base) + 0x04)
-- 
2.46.0



[PATCH v3 22/26] clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

The DE33 is a newer version of the Allwinner Display Engine IP block,
found in the H616, H618, H700 and T507 SoCs. DE2 and DE3 are already
supported by the mainline driver.

The DE33 in the H616 has mixer0 and writeback units. The clocks
and resets required are identical to the H3 and H5 respectively, so use
those existing structs for the H616 description.

There are two additional 32-bit registers (at offsets 0x24 and 0x28)
which require clearing and setting respectively to bring up the
hardware. The function of these registers is currently unknown, and the
values are taken from the out-of-tree driver.

Add the required clock description struct and compatible string to the
DE2 driver.

Signed-off-by: Ryan Walklin 

--
Changelog v2..v3:
- Lowercase hex value
- Correct #include for writel()
---
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 25 +
 1 file changed, 25 insertions(+)

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c 
b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
index 7683ea08d8e30..e0fdf9bda10b1 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -7,6 +7,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -239,6 +240,16 @@ static const struct sunxi_ccu_desc sun50i_h5_de2_clk_desc 
= {
.num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
 };
 
+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,
+
+   .resets = sun50i_h5_de2_resets,
+   .num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
+};
+
 static int sunxi_de2_clk_probe(struct platform_device *pdev)
 {
struct clk *bus_clk, *mod_clk;
@@ -290,6 +301,16 @@ static int sunxi_de2_clk_probe(struct platform_device 
*pdev)
"Couldn't deassert reset control: %d\n", ret);
goto err_disable_mod_clk;
}
+ 
+   /*
+* The DE33 requires these additional (unknown) registers set
+* during initialisation.
+*/
+   if (of_device_is_compatible(pdev->dev.of_node,
+   "allwinner,sun50i-h616-de33-clk")) {
+   writel(0, reg + 0x24);
+   writel(0xa980, reg + 0x28);
+   }
 
ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
if (ret)
@@ -335,6 +356,10 @@ static const struct of_device_id sunxi_de2_clk_ids[] = {
.compatible = "allwinner,sun50i-h6-de3-clk",
.data = &sun50i_h5_de2_clk_desc,
},
+   {
+   .compatible = "allwinner,sun50i-h616-de33-clk",
+   .data = &sun50i_h616_de33_clk_desc,
+   },
{ }
 };
 MODULE_DEVICE_TABLE(of, sunxi_de2_clk_ids);
-- 
2.46.0



[PATCH v3 05/26] drm: sun4i: de3: Add YUV formatter module

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

The display engine formatter (FMT) module is present in the DE3 engine
and provides YUV444 to YUV422/YUV420 conversion, format re-mapping and
color depth conversion.

Add support for this module.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/Makefile |  3 +-
 drivers/gpu/drm/sun4i/sun50i_fmt.c | 82 ++
 drivers/gpu/drm/sun4i/sun50i_fmt.h | 32 
 3 files changed, 116 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index bad7497a0d11e..3f516329f51ee 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_fmt.o
 
 sun4i-tcon-y   += sun4i_crtc.o
 sun4i-tcon-y   += sun4i_tcon_dclk.o
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.c 
b/drivers/gpu/drm/sun4i/sun50i_fmt.c
new file mode 100644
index 0..050a8716ae862
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Jernej Skrabec 
+ */
+
+#include 
+
+#include "sun50i_fmt.h"
+
+static bool sun50i_fmt_is_10bit(u32 format)
+{
+   switch (format) {
+   case MEDIA_BUS_FMT_RGB101010_1X30:
+   case MEDIA_BUS_FMT_YUV10_1X30:
+   case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+   case MEDIA_BUS_FMT_UYVY10_1X20:
+   return true;
+   default:
+   return false;
+   }
+}
+
+static u32 sun50i_fmt_get_colorspace(u32 format)
+{
+   switch (format) {
+   case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+   case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+   return SUN50I_FMT_CS_YUV420;
+   case MEDIA_BUS_FMT_UYVY8_1X16:
+   case MEDIA_BUS_FMT_UYVY10_1X20:
+   return SUN50I_FMT_CS_YUV422;
+   default:
+   return SUN50I_FMT_CS_YUV444RGB;
+   }
+}
+
+static void sun50i_fmt_de3_limits(u32 *limits, u32 colorspace, bool bit10)
+{
+   if (colorspace != SUN50I_FMT_CS_YUV444RGB) {
+   limits[0] = SUN50I_FMT_LIMIT(64, 940);
+   limits[1] = SUN50I_FMT_LIMIT(64, 960);
+   limits[2] = SUN50I_FMT_LIMIT(64, 960);
+   } else if (bit10) {
+   limits[0] = SUN50I_FMT_LIMIT(0, 1023);
+   limits[1] = SUN50I_FMT_LIMIT(0, 1023);
+   limits[2] = SUN50I_FMT_LIMIT(0, 1023);
+   } else {
+   limits[0] = SUN50I_FMT_LIMIT(0, 1021);
+   limits[1] = SUN50I_FMT_LIMIT(0, 1021);
+   limits[2] = SUN50I_FMT_LIMIT(0, 1021);
+   }
+}
+
+void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
+ u16 height, u32 format)
+{
+   u32 colorspace, limit[3], base;
+   struct regmap *regs;
+   bool bit10;
+
+   colorspace = sun50i_fmt_get_colorspace(format);
+   bit10 = sun50i_fmt_is_10bit(format);
+   base = SUN50I_FMT_DE3;
+   regs = sun8i_blender_regmap(mixer);
+
+   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+
+   regmap_write(regs, SUN50I_FMT_CTRL(base), 0);
+
+   regmap_write(regs, SUN50I_FMT_SIZE(base),
+SUN8I_MIXER_SIZE(width, height));
+   regmap_write(regs, SUN50I_FMT_SWAP(base), 0);
+   regmap_write(regs, SUN50I_FMT_DEPTH(base), bit10);
+   regmap_write(regs, SUN50I_FMT_FORMAT(base), colorspace);
+   regmap_write(regs, SUN50I_FMT_COEF(base), 0);
+
+   regmap_write(regs, SUN50I_FMT_LMT_Y(base), limit[0]);
+   regmap_write(regs, SUN50I_FMT_LMT_C0(base), limit[1]);
+   regmap_write(regs, SUN50I_FMT_LMT_C1(base), limit[2]);
+
+   regmap_write(regs, SUN50I_FMT_CTRL(base), 1);
+}
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.h 
b/drivers/gpu/drm/sun4i/sun50i_fmt.h
new file mode 100644
index 0..4127f7206aade
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) Jernej Skrabec 
+ */
+
+#ifndef _SUN50I_FMT_H_
+#define _SUN50I_FMT_H_
+
+#include "sun8i_mixer.h"
+
+#define SUN50I_FMT_DE3 0xa8000
+
+#define SUN50I_FMT_CTRL(base)   ((base) + 0x00)
+#define SUN50I_FMT_SIZE(base)   ((base) + 0x04)
+#define SUN50I_FMT_SWAP(base)   ((base) + 0x08)
+#define SUN50I_FMT_DEPTH(base)  ((base) + 0x0c)
+#define SUN50I_FMT_FORMAT(base) ((base) + 0x10)
+#define SUN50I_FMT_COEF(base)   ((base) + 0x14)
+#define SUN50I_FMT_LMT_Y(base)  ((base) + 0x20)
+#define SUN50I_FMT_LMT_C0(base) ((ba

[PATCH v3 21/26] dt-bindings: allwinner: add H616 DE33 mixer binding

2024-08-17 Thread Ryan Walklin
The Allwinner H616 and variants have a new display engine revision
(DE33).

The mixer configuration registers are significantly different to the DE3
and DE2 revisions, being split into separate top and display blocks,
therefore a fallback for the mixer compatible is not provided.

Add a display engine mixer binding for the DE33.

Signed-off-by: Ryan Walklin 
Acked-by: Conor Dooley 

--

Changelog v2..v3:
- Separate content into three patches for three separate subsystems
---
 .../bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml | 1 +
 1 file changed, 1 insertion(+)

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 b75c1ec686ad2..c37eb8ae1b8ee 100644
--- 
a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
+++ 
b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
@@ -24,6 +24,7 @@ properties:
   - allwinner,sun50i-a64-de2-mixer-0
   - allwinner,sun50i-a64-de2-mixer-1
   - allwinner,sun50i-h6-de3-mixer-0
+  - allwinner,sun50i-h616-de33-mixer-0
 
   reg:
 maxItems: 1
-- 
2.46.0



[PATCH v3 16/26] drm: sun4i: de2/de3: add generic blender register reference function

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

The DE2 and DE3 engines have a blender register range within the
mixer engine register map, whereas the DE33 separates this out into
a separate display group.

Prepare for this by adding a function to look the blender reference up,
with a subsequent patch to add a conditional based on the DE type.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.h | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h 
b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index 82956cb97cfd9..75facc7d1fa66 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -224,6 +224,12 @@ 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->engine.regs;
+}
+
 static inline u32
 sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
 {
-- 
2.46.0



[PATCH v3 11/26] drm: sun4i: de3: add YUV support to the TCON

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Account for U/V channel subsampling by reducing the dot clock and
resolution with a divider in the DE3 timing controller if a YUV format
is selected.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun4i_tcon.c | 26 +++---
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c 
b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index a1a2c845ade0c..e39926e9f0b5d 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -598,14 +598,26 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon 
*tcon,
 static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
 const struct drm_display_mode *mode)
 {
-   unsigned int bp, hsync, vsync, vtotal;
+   unsigned int bp, hsync, vsync, vtotal, div;
+   struct sun4i_crtc *scrtc = tcon->crtc;
+   struct sunxi_engine *engine = scrtc->engine;
u8 clk_delay;
u32 val;
 
WARN_ON(!tcon->quirks->has_channel_1);
 
+   switch (engine->format) {
+   case MEDIA_BUS_FMT_UYYVYY8_0_5X24:
+   case MEDIA_BUS_FMT_UYYVYY10_0_5X30:
+   div = 2;
+   break;
+   default:
+   div = 1;
+   break;
+   }
+
/* Configure the dot clock */
-   clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000);
+   clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000 / div);
 
/* Adjust clock delay */
clk_delay = sun4i_tcon_get_clk_delay(mode, 1);
@@ -624,17 +636,17 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
 
/* Set the input resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC0_REG,
-SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay) |
+SUN4I_TCON1_BASIC0_X(mode->crtc_hdisplay / div) |
 SUN4I_TCON1_BASIC0_Y(mode->crtc_vdisplay));
 
/* Set the upscaling resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC1_REG,
-SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay) |
+SUN4I_TCON1_BASIC1_X(mode->crtc_hdisplay / div) |
 SUN4I_TCON1_BASIC1_Y(mode->crtc_vdisplay));
 
/* Set the output resolution */
regmap_write(tcon->regs, SUN4I_TCON1_BASIC2_REG,
-SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay) |
+SUN4I_TCON1_BASIC2_X(mode->crtc_hdisplay / div) |
 SUN4I_TCON1_BASIC2_Y(mode->crtc_vdisplay));
 
/* Set horizontal display timings */
@@ -642,8 +654,8 @@ static void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon,
DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
 mode->htotal, bp);
regmap_write(tcon->regs, SUN4I_TCON1_BASIC3_REG,
-SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal) |
-SUN4I_TCON1_BASIC3_H_BACKPORCH(bp));
+SUN4I_TCON1_BASIC3_H_TOTAL(mode->crtc_htotal / div) |
+SUN4I_TCON1_BASIC3_H_BACKPORCH(bp / div));
 
bp = mode->crtc_vtotal - mode->crtc_vsync_start;
DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
-- 
2.46.0



[PATCH v3 19/26] dt-bindings: allwinner: add H616 DE33 bus binding

2024-08-17 Thread Ryan Walklin
The Allwinner H616 and variants have a new display engine revision
(DE33).

Add a display engine bus binding for the DE33.

Signed-off-by: Ryan Walklin 
Acked-by: Conor Dooley 

--
Changelog v1..v2:
- Correct DE2 bus enum to reflect fallback devices accurately.

Changelog v2..v3:
- Separate content into three patches for three separate subsystems
---
 .../devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git 
a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml 
b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
index 9845a187bdf65..ea7ee89158c61 100644
--- a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
+++ b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
@@ -24,7 +24,9 @@ properties:
 oneOf:
   - const: allwinner,sun50i-a64-de2
   - items:
-  - const: allwinner,sun50i-h6-de3
+  - enum:
+  - allwinner,sun50i-h6-de3
+  - allwinner,sun50i-h616-de33
   - const: allwinner,sun50i-a64-de2
 
   reg:
-- 
2.46.0



[PATCH v3 04/26] drm: sun4i: de2: Initialize layer fields earlier

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

drm_universal_plane_init() can already call some callbacks, like
format_mod_supported, during initialization. Because of that, fields
should be initialized beforehand.

Signed-off-by: Jernej Skrabec 
Co-developed-by: Ryan Walklin 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 9 +
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 9 +
 2 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index aa987bca1dbb9..cb9b694fef101 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -295,6 +295,11 @@ struct sun8i_layer *sun8i_ui_layer_init_one(struct 
drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
 
+   layer->mixer = mixer;
+   layer->type = SUN8I_LAYER_TYPE_UI;
+   layer->channel = channel;
+   layer->overlay = 0;
+
if (index == 0)
type = DRM_PLANE_TYPE_PRIMARY;
 
@@ -325,10 +330,6 @@ struct sun8i_layer *sun8i_ui_layer_init_one(struct 
drm_device *drm,
}
 
drm_plane_helper_add(&layer->plane, &sun8i_ui_layer_helper_funcs);
-   layer->mixer = mixer;
-   layer->type = SUN8I_LAYER_TYPE_UI;
-   layer->channel = channel;
-   layer->overlay = 0;
 
return layer;
 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index f3a5329351caa..3c657b069d1f4 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -478,6 +478,11 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct 
drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
 
+   layer->mixer = mixer;
+   layer->type = SUN8I_LAYER_TYPE_VI;
+   layer->channel = index;
+   layer->overlay = 0;
+
if (mixer->cfg->is_de3) {
formats = sun8i_vi_layer_de3_formats;
format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
@@ -536,10 +541,6 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct 
drm_device *drm,
}
 
drm_plane_helper_add(&layer->plane, &sun8i_vi_layer_helper_funcs);
-   layer->mixer = mixer;
-   layer->type = SUN8I_LAYER_TYPE_VI;
-   layer->channel = index;
-   layer->overlay = 0;
 
return layer;
 }
-- 
2.46.0



[PATCH v3 02/26] drm: sun4i: de2/de3: Merge CSC functions into one

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

At the moment the colour space conversion is handled by two functions:
one to setup the conversion parameters, and another one to enable the
conversion. Merging both into one gives more flexibility for upcoming
extensions to support whole YUV pipelines, in the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c  | 89 ++
 drivers/gpu/drm/sun4i/sun8i_csc.h  |  9 ++-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 11 +---
 3 files changed, 40 insertions(+), 69 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 6ebd1c3aa3ab5..0dcbc0866ae82 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -107,23 +107,28 @@ static const u32 yuv2rgb_de3[2][3][12] = {
},
 };
 
-static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
-  enum format_type fmt_type,
-  enum drm_color_encoding encoding,
-  enum drm_color_range range)
+static void sun8i_csc_setup(struct regmap *map, u32 base,
+   enum format_type fmt_type,
+   enum drm_color_encoding encoding,
+   enum drm_color_range range)
 {
+   u32 base_reg, val;
const u32 *table;
-   u32 base_reg;
int i;
 
table = yuv2rgb[range][encoding];
 
switch (fmt_type) {
+   case FORMAT_TYPE_RGB:
+   val = 0;
+   break;
case FORMAT_TYPE_YUV:
+   val = SUN8I_CSC_CTRL_EN;
base_reg = SUN8I_CSC_COEFF(base, 0);
regmap_bulk_write(map, base_reg, table, 12);
break;
case FORMAT_TYPE_YVU:
+   val = SUN8I_CSC_CTRL_EN;
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
base_reg = SUN8I_CSC_COEFF(base, i + 1);
@@ -135,28 +140,37 @@ static void sun8i_csc_set_coefficients(struct regmap 
*map, u32 base,
}
break;
default:
+   val = 0;
DRM_WARN("Wrong CSC mode specified.\n");
return;
}
+
+   regmap_write(map, SUN8I_CSC_CTRL(base), val);
 }
 
-static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
-   enum format_type fmt_type,
-   enum drm_color_encoding encoding,
-   enum drm_color_range range)
+static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
+enum format_type fmt_type,
+enum drm_color_encoding encoding,
+enum drm_color_range range)
 {
+   u32 addr, val, mask;
const u32 *table;
-   u32 addr;
int i;
 
+   mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
table = yuv2rgb_de3[range][encoding];
 
switch (fmt_type) {
+   case FORMAT_TYPE_RGB:
+   val = 0;
+   break;
case FORMAT_TYPE_YUV:
+   val = mask;
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, addr, table, 12);
break;
case FORMAT_TYPE_YVU:
+   val = mask;
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
addr = 
SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
@@ -173,67 +187,30 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap 
*map, int layer,
}
break;
default:
+   val = 0;
DRM_WARN("Wrong CSC mode specified.\n");
return;
}
-}
-
-static void sun8i_csc_enable(struct regmap *map, u32 base, bool enable)
-{
-   u32 val;
-
-   if (enable)
-   val = SUN8I_CSC_CTRL_EN;
-   else
-   val = 0;
-
-   regmap_update_bits(map, SUN8I_CSC_CTRL(base), SUN8I_CSC_CTRL_EN, val);
-}
-
-static void sun8i_de3_ccsc_enable(struct regmap *map, int layer, bool enable)
-{
-   u32 val, mask;
-
-   mask = SUN50I_MIXER_BLEND_CSC_CTL_EN(layer);
-
-   if (enable)
-   val = mask;
-   else
-   val = 0;
 
regmap_update_bits(map, SUN50I_MIXER_BLEND_CSC_CTL(DE3_BLD_BASE),
   mask, val);
 }
 
-void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
-enum format_type fmt_type,
-enum drm_color_encoding encoding,
-enum drm_color_range range)
-{
-   u32 base

[PATCH v3 00/26] drm: sun4i: add Display Engine 3.3 (DE33) support

2024-08-17 Thread Ryan Walklin
Hi,

V3 of this patch series adding support for the Allwinner DE33 display engine 
variant. V3 is rebased on top of layer init and modesetting changes merged for 
6.11. No functional changes from V2, fixes and review from previous V1 and V2 
added, and correction to DT bindings.

Original blurb below:

There is existing mainline support for the DE2 and DE3 AllWinner display 
pipeline IP blocks, used in the A64 and H6 among others, however the H700 (as 
well as the H616/H618 and the T507 automotive SoC) have a newer version of the 
Display Engine (v3.3/DE33) which adds additional high-resolution support as 
well as YUV colour formats and AFBC compression support.

This patch set adds DE33 support, following up from the previous RFC [1], with 
significant rework to break down the previous relatively complex set into more 
logical steps, detailed below.

1. Refactor the existing DE2/DE3 code in readiness to support YUV colour 
formats in the DE3 engine (patches 1-4).
2. Add YUV420 colour format support in the DE3 driver (patches 5-12).
3. Replace the is_de3 mixer flag with an enum to support multiple DE versions 
(patch 13).
4. Refactor the mixer, vi_scaler and some register code to merge common init 
code and more easily support multiple DE versions (patches 14-17).
5. Add Arm Frame Buffer Compression (AFBC) compressed buffer support to the DE3 
driver. This is currently only supported for VI layers (for HW-decoded video 
output) but is well integrated into these changes and a subsequent patchset to 
enable the Video Engine is planned. (patch 18).
6. Add DT bindings for the DE33 engine. (patch 19-21).
7. Extend the DE2/3 driver for the DE33, comprising clock, mixer, vi_scaler, 
fmt and csc module support (patches 22-26).

Further patchsets are planned to support HDMI and the LCD timing controller 
present in these SoCs.

Regards,

Ryan

Jernej Skrabec (23):
  drm: sun4i: de2/de3: Change CSC argument
  drm: sun4i: de2/de3: Merge CSC functions into one
  drm: sun4i: de2/de3: call csc setup also for UI layer
  drm: sun4i: de2: Initialize layer fields earlier
  drm: sun4i: de3: Add YUV formatter module
  drm: sun4i: de3: add format enumeration function to engine
  drm: sun4i: de3: add formatter flag to mixer config
  drm: sun4i: de3: add YUV support to the DE3 mixer
  drm: sun4i: de3: pass engine reference to ccsc setup function
  drm: sun4i: de3: add YUV support to the color space correction module
  drm: sun4i: de3: add YUV support to the TCON
  drm: sun4i: support YUV formats in VI scaler
  drm: sun4i: de2/de3: add mixer version enum
  drm: sun4i: de2/de3: refactor mixer initialisation
  drm: sun4i: vi_scaler refactor vi_scaler enablement
  drm: sun4i: de2/de3: add generic blender register reference function
  drm: sun4i: de2/de3: use generic register reference function for layer
configuration
  drm: sun4i: de3: Implement AFBC support
  clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support
  drm: sun4i: de33: mixer: add Display Engine 3.3 (DE33) support
  drm: sun4i: de33: vi_scaler: add Display Engine 3.3 (DE33) support
  drm: sun4i: de33: fmt: add Display Engine 3.3 (DE33) support
  drm: sun4i: de33: csc: add Display Engine 3.3 (DE33) support

Ryan Walklin (3):
  dt-bindings: allwinner: add H616 DE33 bus binding
  dt-bindings: allwinner: add H616 DE33 clock binding
  dt-bindings: allwinner: add H616 DE33 mixer binding

 .../bus/allwinner,sun50i-a64-de2.yaml |   4 +-
 .../clock/allwinner,sun8i-a83t-de2-clk.yaml   |   1 +
 .../allwinner,sun8i-a83t-de2-mixer.yaml   |   1 +
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c  |  25 ++
 drivers/gpu/drm/sun4i/Makefile|   3 +-
 drivers/gpu/drm/sun4i/sun4i_tcon.c|  26 +-
 drivers/gpu/drm/sun4i/sun50i_afbc.c   | 250 +
 drivers/gpu/drm/sun4i/sun50i_afbc.h   |  87 +
 drivers/gpu/drm/sun4i/sun50i_fmt.c|  99 +
 drivers/gpu/drm/sun4i/sun50i_fmt.h|  33 ++
 drivers/gpu/drm/sun4i/sun8i_csc.c | 341 +++---
 drivers/gpu/drm/sun4i/sun8i_csc.h |  20 +-
 drivers/gpu/drm/sun4i/sun8i_mixer.c   | 229 +---
 drivers/gpu/drm/sun4i/sun8i_mixer.h   |  31 +-
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c|  41 ++-
 drivers/gpu/drm/sun4i/sun8i_ui_scaler.c   |   2 +-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c| 134 +--
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c   | 115 --
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.h   |   2 +-
 drivers/gpu/drm/sun4i/sunxi_engine.h  |  34 ++
 20 files changed, 1271 insertions(+), 207 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.h
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_fmt.h

-- 
2.46.0



[PATCH v3 01/26] drm: sun4i: de2/de3: Change CSC argument

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Currently, CSC module takes care only for converting YUV to RGB.
However, DE3 is more suited to work in YUV color space. Change CSC mode
argument to format type to be more neutral. New argument only tells
layer format type and doesn't imply output type.

This commit doesn't make any functional change.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
Reviewed-by: Andre Przywara 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c  | 22 +++---
 drivers/gpu/drm/sun4i/sun8i_csc.h  | 10 +-
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c | 16 
 3 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 58480d8e4f704..6ebd1c3aa3ab5 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -108,7 +108,7 @@ static const u32 yuv2rgb_de3[2][3][12] = {
 };
 
 static void sun8i_csc_set_coefficients(struct regmap *map, u32 base,
-  enum sun8i_csc_mode mode,
+  enum format_type fmt_type,
   enum drm_color_encoding encoding,
   enum drm_color_range range)
 {
@@ -118,12 +118,12 @@ static void sun8i_csc_set_coefficients(struct regmap 
*map, u32 base,
 
table = yuv2rgb[range][encoding];
 
-   switch (mode) {
-   case SUN8I_CSC_MODE_YUV2RGB:
+   switch (fmt_type) {
+   case FORMAT_TYPE_YUV:
base_reg = SUN8I_CSC_COEFF(base, 0);
regmap_bulk_write(map, base_reg, table, 12);
break;
-   case SUN8I_CSC_MODE_YVU2RGB:
+   case FORMAT_TYPE_YVU:
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
base_reg = SUN8I_CSC_COEFF(base, i + 1);
@@ -141,7 +141,7 @@ static void sun8i_csc_set_coefficients(struct regmap *map, 
u32 base,
 }
 
 static void sun8i_de3_ccsc_set_coefficients(struct regmap *map, int layer,
-   enum sun8i_csc_mode mode,
+   enum format_type fmt_type,
enum drm_color_encoding encoding,
enum drm_color_range range)
 {
@@ -151,12 +151,12 @@ static void sun8i_de3_ccsc_set_coefficients(struct regmap 
*map, int layer,
 
table = yuv2rgb_de3[range][encoding];
 
-   switch (mode) {
-   case SUN8I_CSC_MODE_YUV2RGB:
+   switch (fmt_type) {
+   case FORMAT_TYPE_YUV:
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, addr, table, 12);
break;
-   case SUN8I_CSC_MODE_YVU2RGB:
+   case FORMAT_TYPE_YVU:
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
addr = 
SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
@@ -206,7 +206,7 @@ static void sun8i_de3_ccsc_enable(struct regmap *map, int 
layer, bool enable)
 }
 
 void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
-enum sun8i_csc_mode mode,
+enum format_type fmt_type,
 enum drm_color_encoding encoding,
 enum drm_color_range range)
 {
@@ -214,14 +214,14 @@ void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer 
*mixer, int layer,
 
if (mixer->cfg->is_de3) {
sun8i_de3_ccsc_set_coefficients(mixer->engine.regs, layer,
-   mode, encoding, range);
+   fmt_type, encoding, range);
return;
}
 
base = ccsc_base[mixer->cfg->ccsc][layer];
 
sun8i_csc_set_coefficients(mixer->engine.regs, base,
-  mode, encoding, range);
+  fmt_type, encoding, range);
 }
 
 void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h 
b/drivers/gpu/drm/sun4i/sun8i_csc.h
index 828b86fd0cabb..7322770f39f03 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
@@ -22,14 +22,14 @@ struct sun8i_mixer;
 
 #define SUN8I_CSC_CTRL_EN  BIT(0)
 
-enum sun8i_csc_mode {
-   SUN8I_CSC_MODE_OFF,
-   SUN8I_CSC_MODE_YUV2RGB,
-   SUN8I_CSC_MODE_YVU2RGB,
+enum format_type {
+   FORMAT_TYPE_RGB,
+   FORMAT_TYPE_YUV,
+   FORMAT_TYPE_YVU,
 };
 
 void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
-enum sun8i_csc_mode mode,
+enum format_type fmt_type,
   

[PATCH v3 03/26] drm: sun4i: de2/de3: call csc setup also for UI layer

2024-08-17 Thread Ryan Walklin
From: Jernej Skrabec 

Currently, only VI layer calls CSC setup function. This comes from DE2
limitation, which doesn't have CSC unit for UI layers. However, DE3 has
separate CSC units for each layer. This allows display pipeline to make
output signal in different color spaces. To support both use cases, add
a call to CSC setup function also in UI layer code. For DE2, this will
be a no-op, but it will allow DE3 to output signal in multiple formats.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c  | 8 +---
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c | 6 ++
 2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 0dcbc0866ae82..68d955c63b05b 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -209,8 +209,10 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
return;
}
 
-   base = ccsc_base[mixer->cfg->ccsc][layer];
+   if (layer < mixer->cfg->vi_num) {
+   base = ccsc_base[mixer->cfg->ccsc][layer];
 
-   sun8i_csc_setup(mixer->engine.regs, base,
-   fmt_type, encoding, range);
+   sun8i_csc_setup(mixer->engine.regs, base,
+   fmt_type, encoding, range);
+   }
 }
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index b90e5edef4e88..aa987bca1dbb9 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -20,6 +20,7 @@
 #include 
 #include 
 
+#include "sun8i_csc.h"
 #include "sun8i_mixer.h"
 #include "sun8i_ui_layer.h"
 #include "sun8i_ui_scaler.h"
@@ -135,6 +136,11 @@ static int sun8i_ui_layer_update_formats(struct 
sun8i_mixer *mixer, int channel,
   SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
   SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
 
+   /* Note: encoding and range arguments are ignored for RGB */
+   sun8i_csc_set_ccsc(mixer, channel, FORMAT_TYPE_RGB,
+  DRM_COLOR_YCBCR_BT601,
+  DRM_COLOR_YCBCR_FULL_RANGE);
+
return 0;
 }
 
-- 
2.46.0



Re: [PATCH v2 18/23] dt-bindings: allwinner: add H616 DE33 bus, clock and display bindings

2024-07-05 Thread Ryan Walklin
On Thu, 4 Jul 2024, at 3:28 AM, Conor Dooley wrote:
>> Add display engine bus, clock and mixer bindings for the DE33.
>> 
>> Signed-off-by: Ryan Walklin 
>
> Probably this should be 3 patches given 3 subsystems, but the content is
> Acked-by: Conor Dooley 
>
> Cheers,
> Conor.
>
Thanks Conor, will separate for v3 but ack noted.


Re: [PATCH v2 3/3] dt-bindings: display: panel: correct Anbernic RG35XX panel example

2024-07-05 Thread Ryan Walklin
On Thu, 4 Jul 2024, at 3:38 AM, Conor Dooley wrote:
> I forgot to reply to, or somehow didn't notice your reply to my comments
> on this patch. I would just drop this change as I think it's a tooling
> issue. I checked the version of dt-schema etc that I have here locally
> and there were no complaints with the binding prior to your patches.
>
> Sorry for missing your reply,
> Conor.
>
Thanks Conor, no worries. Happy to resend without this patch in that case, or 
just have it dropped.

Regards,

Ryan


Re: [PATCH v2 19/23] clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support

2024-07-05 Thread Ryan Walklin
Hi Stephen, thanks for reviewing.

On Thu, 4 Jul 2024, at 11:02 AM, Stephen Boyd wrote:
> Quoting Ryan Walklin (2024-07-03 03:51:09)
>> +#include 
>
> What is this include for?
>
for writel, however have confirmed this should instead be #include , 
will correct for v3.

>> +   if (of_device_is_compatible(pdev->dev.of_node,
>> +   "allwinner,sun50i-h616-de33-clk")) {
>> +   writel(0, reg + 0x24);
>> +   writel(0xA980, reg + 0x28);
>
> Lowercase hex please. Did the downstream driver have names for these
> register offsets by way of some sort of #define?

Thanks, will correct. AFAIK no, these are from Jernej's tree which I understand 
he developed independently, there was no vendor driver to reference, nor DE33 
datasheet publicly available. 

Jernej, are you able to weigh in at all?

Thanks,

Ryan


[PATCH v2 19/23] clk: sunxi-ng: ccu: add Display Engine 3.3 (DE33) support

2024-07-03 Thread Ryan Walklin
The DE33 is a newer version of the Allwinner Display Engine IP block,
found in the H616, H618, H700 and T507 SoCs. DE2 and DE3 are already
supported by the mainline driver.

The DE33 in the H616 has mixer0, mixer1 and writeback units. The clocks
and resets required are identical to the H3 and H5 respectively, so use
those existing structs for the H616 description.

There are two additional 32-bit registers (at offsets 0x24 and 0x28)
which require clearing and setting respectively to bring up the
hardware. The function of these registers is currently unknown, and the
values are taken from the out-of-tree driver.

Add the required clock description struct and compatible string to the
DE2 driver.

Signed-off-by: Ryan Walklin 
---
 drivers/clk/sunxi-ng/ccu-sun8i-de2.c | 25 +
 1 file changed, 25 insertions(+)

diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c 
b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
index b0b8dba239aec..36b9eadb80bb5 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c
@@ -7,6 +7,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -239,6 +240,16 @@ static const struct sunxi_ccu_desc sun50i_h5_de2_clk_desc 
= {
.num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
 };
 
+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,
+
+   .resets = sun50i_h5_de2_resets,
+   .num_resets = ARRAY_SIZE(sun50i_h5_de2_resets),
+};
+
 static int sunxi_de2_clk_probe(struct platform_device *pdev)
 {
struct clk *bus_clk, *mod_clk;
@@ -290,6 +301,16 @@ static int sunxi_de2_clk_probe(struct platform_device 
*pdev)
"Couldn't deassert reset control: %d\n", ret);
goto err_disable_mod_clk;
}
+ 
+   /*
+* The DE33 requires these additional (unknown) registers set
+* during initialisation.
+*/
+   if (of_device_is_compatible(pdev->dev.of_node,
+   "allwinner,sun50i-h616-de33-clk")) {
+   writel(0, reg + 0x24);
+   writel(0xA980, reg + 0x28);
+   }
 
ret = devm_sunxi_ccu_probe(&pdev->dev, reg, ccu_desc);
if (ret)
@@ -335,6 +356,10 @@ static const struct of_device_id sunxi_de2_clk_ids[] = {
.compatible = "allwinner,sun50i-h6-de3-clk",
.data = &sun50i_h5_de2_clk_desc,
},
+   {
+   .compatible = "allwinner,sun50i-h616-de33-clk",
+   .data = &sun50i_h616_de33_clk_desc,
+   },
{ }
 };
 MODULE_DEVICE_TABLE(of, sunxi_de2_clk_ids);
-- 
2.45.2



[PATCH v2 23/23] drm: sun4i: de33: csc: add Display Engine 3.3 (DE33) support

2024-07-03 Thread Ryan Walklin
From: Jernej Skrabec 

Like earlier DE versions, the DE33 has a CSC (Color Space Correction)
module. which provides color space conversion between BT2020/BT709, and
dynamic range conversion between SDR/ST2084/HLG.

Add support for the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_csc.c | 96 +++
 drivers/gpu/drm/sun4i/sun8i_csc.h |  3 +
 2 files changed, 99 insertions(+)

diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c 
b/drivers/gpu/drm/sun4i/sun8i_csc.c
index 2d5a2cf7cba24..45bd1ca06400e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -238,6 +238,14 @@ static const u32 yuv2yuv_de3[2][3][3][12] = {
},
 };
 
+static u32 sun8i_csc_base(struct sun8i_mixer *mixer, int layer)
+{
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return sun8i_channel_base(mixer, layer) - 0x800;
+   else
+   return ccsc_base[mixer->cfg->ccsc][layer];
+}
+
 static void sun8i_csc_setup(struct regmap *map, u32 base,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -358,6 +366,90 @@ static void sun8i_de3_ccsc_setup(struct sunxi_engine 
*engine, 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] &= 0x;
+   dst[10] &= 0x;
+   dst[14] &= 0x;
+}
+
+static void sun8i_de33_ccsc_setup(struct sun8i_mixer *mixer, int layer,
+ enum format_type fmt_type,
+ enum drm_color_encoding encoding,
+ enum drm_color_range range)
+{
+   u32 addr, val = 0, base, csc[15];
+   struct sunxi_engine *engine;
+   struct regmap *map;
+   const u32 *table;
+   int i;
+
+   table = yuv2rgb_de3[range][encoding];
+   base = sun8i_csc_base(mixer, layer);
+   engine = &mixer->engine;
+   map = engine->regs;
+
+   switch (fmt_type) {
+   case FORMAT_TYPE_RGB:
+   if (engine->format == MEDIA_BUS_FMT_RGB888_1X24)
+   break;
+   val = SUN8I_CSC_CTRL_EN;
+   sun8i_de33_convert_table(rgb2yuv_de3[engine->encoding], csc);
+   regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+   break;
+   case FORMAT_TYPE_YUV:
+   table = sun8i_csc_get_de3_yuv_table(encoding, range,
+   engine->format,
+   engine->encoding);
+   if (!table)
+   break;
+   val = SUN8I_CSC_CTRL_EN;
+   sun8i_de33_convert_table(table, csc);
+   regmap_bulk_write(map, SUN50I_CSC_COEFF(base, 0), csc, 15);
+   break;
+   case FORMAT_TYPE_YVU:
+   table = sun8i_csc_get_de3_yuv_table(encoding, range,
+   engine->format,
+   engine->encoding);
+   if (!table)
+   table = yuv2yuv_de3[range][encoding][encoding];
+   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);
+}
+
 void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int layer,
enum format_type fmt_type,
enum drm_color_encoding encoding,
@@ -369,6 +461,10 @@ void sun8i_csc_set_ccsc(struct sun8i_mixer *mixer, int 
layer,
sun8i_de3_ccsc_setup(&mixer->engine, layer,
  

[PATCH v2 22/23] drm: sun4i: de33: fmt: add Display Engine 3.3 (DE33) support

2024-07-03 Thread Ryan Walklin
From: Jernej Skrabec 

Like the DE3, the DE33 has a FMT (formatter) module, which
provides YUV444 to YUV422/YUV420 conversion, format re-mapping and color
depth conversion, although the DE33 module appears significantly more
capable, including up to 4K video support.

Add support for the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun50i_fmt.c | 21 +++--
 drivers/gpu/drm/sun4i/sun50i_fmt.h |  1 +
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.c 
b/drivers/gpu/drm/sun4i/sun50i_fmt.c
index 050a8716ae862..39682d4e6d208 100644
--- a/drivers/gpu/drm/sun4i/sun50i_fmt.c
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.c
@@ -51,6 +51,19 @@ static void sun50i_fmt_de3_limits(u32 *limits, u32 
colorspace, bool bit10)
}
 }
 
+static void sun50i_fmt_de33_limits(u32 *limits, u32 colorspace)
+{
+   if (colorspace == SUN50I_FMT_CS_YUV444RGB) {
+   limits[0] = SUN50I_FMT_LIMIT(0, 4095);
+   limits[1] = SUN50I_FMT_LIMIT(0, 4095);
+   limits[2] = SUN50I_FMT_LIMIT(0, 4095);
+   } else {
+   limits[0] = SUN50I_FMT_LIMIT(256, 3840);
+   limits[1] = SUN50I_FMT_LIMIT(256, 3840);
+   limits[2] = SUN50I_FMT_LIMIT(256, 3840);
+   }
+}
+
 void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
  u16 height, u32 format)
 {
@@ -60,10 +73,14 @@ void sun50i_fmt_setup(struct sun8i_mixer *mixer, u16 width,
 
colorspace = sun50i_fmt_get_colorspace(format);
bit10 = sun50i_fmt_is_10bit(format);
-   base = SUN50I_FMT_DE3;
+   base = mixer->cfg->de_type == sun8i_mixer_de3 ?
+   SUN50I_FMT_DE3 : SUN50I_FMT_DE33;
regs = sun8i_blender_regmap(mixer);
 
-   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   sun50i_fmt_de3_limits(limit, colorspace, bit10);
+   else
+   sun50i_fmt_de33_limits(limit, colorspace);
 
regmap_write(regs, SUN50I_FMT_CTRL(base), 0);
 
diff --git a/drivers/gpu/drm/sun4i/sun50i_fmt.h 
b/drivers/gpu/drm/sun4i/sun50i_fmt.h
index 4127f7206aade..3e60d5c788b39 100644
--- a/drivers/gpu/drm/sun4i/sun50i_fmt.h
+++ b/drivers/gpu/drm/sun4i/sun50i_fmt.h
@@ -9,6 +9,7 @@
 #include "sun8i_mixer.h"
 
 #define SUN50I_FMT_DE3 0xa8000
+#define SUN50I_FMT_DE33 0x5000
 
 #define SUN50I_FMT_CTRL(base)   ((base) + 0x00)
 #define SUN50I_FMT_SIZE(base)   ((base) + 0x04)
-- 
2.45.2



[PATCH v2 21/23] drm: sun4i: de33: vi_scaler: add Display Engine 3.3 (DE33) support

2024-07-03 Thread Ryan Walklin
From: Jernej Skrabec 

The vi_scaler appears to be used in preference to the ui_scaler module
for hardware video scaling in the DE33.

Enable support for this scaler.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_ui_layer.c  | 19 +++
 drivers/gpu/drm/sun4i/sun8i_vi_scaler.c |  7 ++-
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c 
b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index 7f4d4dcfdc03d..1649816fe435e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -146,12 +146,23 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer 
*mixer, int channel,
hscale = state->src_w / state->crtc_w;
vscale = state->src_h / state->crtc_h;
 
-   sun8i_ui_scaler_setup(mixer, channel, src_w, src_h, dst_w,
- dst_h, hscale, vscale, hphase, vphase);
-   sun8i_ui_scaler_enable(mixer, channel, true);
+   if (mixer->cfg->de_type == sun8i_mixer_de33) {
+   sun8i_vi_scaler_setup(mixer, channel, src_w, src_h,
+ dst_w, dst_h, hscale, vscale,
+ hphase, vphase,
+ state->fb->format);
+   } else {
+   sun8i_ui_scaler_setup(mixer, channel, src_w, src_h,
+ dst_w, dst_h, hscale, vscale,
+ hphase, vphase);
+   sun8i_ui_scaler_enable(mixer, channel, true);
+   }
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
-   sun8i_ui_scaler_enable(mixer, channel, false);
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   sun8i_vi_scaler_disable(mixer, channel);
+   else
+   sun8i_ui_scaler_enable(mixer, channel, false);
}
 
/* Set base coordinates */
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c 
b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index e7242301b312c..9c7f6e7d71d50 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -835,7 +835,9 @@ static const u32 bicubic4coefftab32[480] = {
 
 static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
 {
-   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return sun8i_channel_base(mixer, channel) + 0x3000;
+   else if (mixer->cfg->de_type == sun8i_mixer_de3)
return DE3_VI_SCALER_UNIT_BASE +
   DE3_VI_SCALER_UNIT_SIZE * channel;
else
@@ -845,6 +847,9 @@ static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, 
int channel)
 
 static bool sun8i_vi_scaler_is_vi_plane(struct sun8i_mixer *mixer, int channel)
 {
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   return mixer->cfg->map[channel] < mixer->cfg->vi_num;
+
return true;
 }
 
-- 
2.45.2



[PATCH v2 20/23] drm: sun4i: de33: mixer: add Display Engine 3.3 (DE33) support

2024-07-03 Thread Ryan Walklin
From: Jernej Skrabec 

The DE33 is a newer version of the Allwinner Display Engine IP block,
found in the H616, H618, H700 and T507 SoCs. DE2 and DE3 are already
supported by the mainline driver.

Notable features (from the H616 datasheet and implemented):
- 4096 x 2048 (4K) output support
- AFBC ARM Frame Buffer Compression support
- YUV420 input support

Extend the mixer to support the DE33.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/sun8i_mixer.c | 110 
 drivers/gpu/drm/sun4i/sun8i_mixer.h |  16 +++-
 2 files changed, 109 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index e634827e16487..39da44ffd033a 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -254,10 +254,16 @@ int sun8i_mixer_drm_format_to_hw(u32 format, u32 
*hw_format)
 
 static void sun8i_mixer_commit(struct sunxi_engine *engine)
 {
+   struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+
DRM_DEBUG_DRIVER("Committing changes\n");
 
-   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
-SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+   if (mixer->cfg->de_type == sun8i_mixer_de33)
+   regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_DBUFF,
+SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
+   else
+   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
+SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
 }
 
 static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
@@ -306,25 +312,33 @@ 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, *disp_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);
 
DRM_DEBUG_DRIVER("Updating global size W: %u H: %u\n",
 mode->hdisplay, mode->vdisplay);
 
-   regmap_write(engine->regs, SUN8I_MIXER_GLOBAL_SIZE, size);
-   regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
+   if (mixer->cfg->de_type == sun8i_mixer_de33) {
+   disp_regs = mixer->disp_regs;
+   regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_SIZE, size);
+   } else {
+   disp_regs = mixer->engine.regs;
+   regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE, size);
+   }
+   regmap_write(bld_regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
 
if (interlaced)
val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
else
val = 0;
 
-   regmap_update_bits(engine->regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
+   regmap_update_bits(bld_regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
   SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
 
DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
@@ -335,10 +349,8 @@ static void sun8i_mixer_mode_set(struct sunxi_engine 
*engine,
else
val = 0xff108080;
 
-   regmap_write(mixer->engine.regs,
-SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
-   regmap_write(mixer->engine.regs,
-SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), val);
+   regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(bld_base), val);
+   regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(bld_base, 0), 
val);
 
if (mixer->cfg->has_formatter)
sun50i_fmt_setup(mixer, mode->hdisplay,
@@ -378,12 +390,29 @@ static const struct sunxi_engine_ops sun8i_engine_ops = {
 };
 
 static const struct regmap_config sun8i_mixer_regmap_config = {
+   .name   = "layers",
.reg_bits   = 32,
.val_bits   = 32,
.reg_stride = 4,
.max_register   = 0xc, /* guessed */
 };
 
+static const struct regmap_config sun8i_top_regmap_config = {
+   .name   = "top",
+   .reg_bits   = 32,
+   .val_bits   = 32,
+   .reg_stride = 4,
+   .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   = 0x2,
+};
+
 static int sun8i_mixer_of_get_id(struct device_node *node)
 {
struct device_node *ep, *remote;
@@ -406,33 +435,44 @@ static int sun8i_mixer_of_get_id(struct device

[PATCH v2 18/23] dt-bindings: allwinner: add H616 DE33 bus, clock and display bindings

2024-07-03 Thread Ryan Walklin
The Allwinner H616 and variants have a new display engine revision
(DE33).

The mixer configuration registers are significantly different to the DE3
and DE2 revisions, being split into separate top and display blocks,
therefore a fallback for the mixer compatible is not provided.

Add display engine bus, clock and mixer bindings for the DE33.

Signed-off-by: Ryan Walklin 

--
Changelog v1..v2:
- Correct DE2 bus enum to reflect fallback devices accurately.
---
 .../devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml | 4 +++-
 .../bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml  | 1 +
 .../bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml  | 1 +
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git 
a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml 
b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
index 9845a187bdf65..ea7ee89158c61 100644
--- a/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
+++ b/Documentation/devicetree/bindings/bus/allwinner,sun50i-a64-de2.yaml
@@ -24,7 +24,9 @@ properties:
 oneOf:
   - const: allwinner,sun50i-a64-de2
   - items:
-  - const: allwinner,sun50i-h6-de3
+  - enum:
+  - allwinner,sun50i-h6-de3
+  - allwinner,sun50i-h616-de33
   - const: allwinner,sun50i-a64-de2
 
   reg:
diff --git 
a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml 
b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
index 70369bd633e40..7fcd55d468d49 100644
--- a/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
+++ b/Documentation/devicetree/bindings/clock/allwinner,sun8i-a83t-de2-clk.yaml
@@ -25,6 +25,7 @@ properties:
   - const: allwinner,sun50i-a64-de2-clk
   - const: allwinner,sun50i-h5-de2-clk
   - const: allwinner,sun50i-h6-de3-clk
+  - const: allwinner,sun50i-h616-de33-clk
   - items:
   - const: allwinner,sun8i-r40-de2-clk
   - const: allwinner,sun8i-h3-de2-clk
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 b75c1ec686ad2..c37eb8ae1b8ee 100644
--- 
a/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
+++ 
b/Documentation/devicetree/bindings/display/allwinner,sun8i-a83t-de2-mixer.yaml
@@ -24,6 +24,7 @@ properties:
   - allwinner,sun50i-a64-de2-mixer-0
   - allwinner,sun50i-a64-de2-mixer-1
   - allwinner,sun50i-h6-de3-mixer-0
+  - allwinner,sun50i-h616-de33-mixer-0
 
   reg:
 maxItems: 1
-- 
2.45.2



[PATCH v2 17/23] drm: sun4i: de3: Implement AFBC support

2024-07-03 Thread Ryan Walklin
From: Jernej Skrabec 

Buffers, compressed with AFBC, are supported by the DE3 and above, and
are generally more efficient for memory transfers. Add support for them.

Currently it's implemented only for VI layers, but vendor code and
documentation suggest UI layers can have them too. However, I haven't
observed any SoC with such feature.

Signed-off-by: Jernej Skrabec 
Signed-off-by: Ryan Walklin 
---
 drivers/gpu/drm/sun4i/Makefile |   2 +-
 drivers/gpu/drm/sun4i/sun50i_afbc.c| 250 +
 drivers/gpu/drm/sun4i/sun50i_afbc.h|  87 +
 drivers/gpu/drm/sun4i/sun8i_vi_layer.c |  84 +++--
 4 files changed, 410 insertions(+), 13 deletions(-)
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.c
 create mode 100644 drivers/gpu/drm/sun4i/sun50i_afbc.h

diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 3f516329f51ee..78290f1660fbd 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -17,7 +17,7 @@ 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 \
-  sun50i_fmt.o
+  sun50i_fmt.o sun50i_afbc.o
 
 sun4i-tcon-y   += sun4i_crtc.o
 sun4i-tcon-y   += sun4i_tcon_dclk.o
diff --git a/drivers/gpu/drm/sun4i/sun50i_afbc.c 
b/drivers/gpu/drm/sun4i/sun50i_afbc.c
new file mode 100644
index 0..b55e1c5533714
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun50i_afbc.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) Jernej Skrabec 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "sun50i_afbc.h"
+#include "sun8i_mixer.h"
+
+static u32 sun50i_afbc_get_base(struct sun8i_mixer *mixer, unsigned int 
channel)
+{
+   u32 base = sun8i_channel_base(mixer, channel);
+
+   if (mixer->cfg->de_type == sun8i_mixer_de3)
+   return base + SUN50I_AFBC_CH_OFFSET;
+
+   return base + 0x4000;
+}
+
+bool sun50i_afbc_format_mod_supported(struct sun8i_mixer *mixer,
+ u32 format, u64 modifier)
+{
+   u64 mode;
+
+   if (modifier == DRM_FORMAT_MOD_INVALID)
+   return false;
+
+   if (modifier == DRM_FORMAT_MOD_LINEAR) {
+   if (format == DRM_FORMAT_YUV420_8BIT ||
+   format == DRM_FORMAT_YUV420_10BIT ||
+   format == DRM_FORMAT_Y210)
+   return false;
+   return true;
+   }
+
+   if (mixer->cfg->de_type == sun8i_mixer_de2)
+   return false;
+
+   mode = AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
+  AFBC_FORMAT_MOD_SPARSE |
+  AFBC_FORMAT_MOD_SPLIT;
+
+   switch (format) {
+   case DRM_FORMAT_RGBA:
+   case DRM_FORMAT_RGB888:
+   case DRM_FORMAT_RGB565:
+   case DRM_FORMAT_RGBA:
+   case DRM_FORMAT_RGBA5551:
+   case DRM_FORMAT_RGBA1010102:
+   mode |= AFBC_FORMAT_MOD_YTR;
+   break;
+   case DRM_FORMAT_YUYV:
+   case DRM_FORMAT_Y210:
+   case DRM_FORMAT_YUV420_8BIT:
+   case DRM_FORMAT_YUV420_10BIT:
+   break;
+   default:
+   return false;
+   }
+
+   return modifier == DRM_FORMAT_MOD_ARM_AFBC(mode);
+}
+
+void sun50i_afbc_atomic_update(struct sun8i_mixer *mixer, unsigned int channel,
+  struct drm_plane *plane)
+{
+   struct drm_plane_state *state = plane->state;
+   struct drm_framebuffer *fb = state->fb;
+   const struct drm_format_info *format = fb->format;
+   struct drm_gem_dma_object *gem;
+   u32 base, val, src_w, src_h;
+   u32 def_color0, def_color1;
+   struct regmap *regs;
+   dma_addr_t dma_addr;
+
+   base = sun50i_afbc_get_base(mixer, channel);
+   regs = mixer->engine.regs;
+
+   src_w = drm_rect_width(&state->src) >> 16;
+   src_h = drm_rect_height(&state->src) >> 16;
+
+   val = SUN50I_FBD_SIZE_HEIGHT(src_h);
+   val |= SUN50I_FBD_SIZE_WIDTH(src_w);
+   regmap_write(regs, SUN50I_FBD_SIZE(base), val);
+
+   val = SUN50I_FBD_BLK_SIZE_HEIGHT(DIV_ROUND_UP(src_h, 16));
+   val = SUN50I_FBD_BLK_SIZE_WIDTH(DIV_ROUND_UP(src_w, 16));
+   regmap_write(regs, SUN50I_FBD_BLK_SIZE(base), val);
+
+   val = SUN50I_FBD_SRC_CROP_TOP(0);
+   val |= SUN50I_FBD_SRC_CROP_LEFT(0);
+   regmap_write(regs, SUN50I_FBD_SRC_CROP(base), val);
+
+   val = SUN50I_FBD_LAY_CROP_TOP(state->src.y1 >> 16);
+   val |= SUN50I_FBD_LAY_CROP_LEFT(state->src.x1 >> 16);
+   regmap_write(regs, SUN50I_FBD_LAY_CROP(base), val);
+
+   /*
+* Default color 

  1   2   >