mirror of
https://github.com/andreili/SBC_builder.git
synced 2025-08-24 03:14:06 +02:00
303 lines
9.6 KiB
Diff
303 lines
9.6 KiB
Diff
From 66c111f3315d2c34c2f9bfb39de61bf3ec46a5f6 Mon Sep 17 00:00:00 2001
|
|
From: Jernej Skrabec <jernej.skrabec@gmail.com>
|
|
Date: Sun, 29 Sep 2024 22:04:55 +1300
|
|
Subject: drm: sun4i: de33: mixer: add Display Engine 3.3 (DE33) support
|
|
|
|
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 <jernej.skrabec@gmail.com>
|
|
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
|
|
---
|
|
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 600084286b39..204fc8055b32 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 = 0xffffc, /* 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 = 0x20000,
|
|
+};
|
|
+
|
|
static int sun8i_mixer_of_get_id(struct device_node *node)
|
|
{
|
|
struct device_node *ep, *remote;
|
|
@@ -471,33 +498,45 @@ static int sun8i_mixer_of_get_id(struct device_node *node)
|
|
|
|
static void sun8i_mixer_init(struct sun8i_mixer *mixer)
|
|
{
|
|
+ struct regmap *top_regs, *disp_regs;
|
|
unsigned int base = sun8i_blender_base(mixer);
|
|
int plane_cnt, i;
|
|
|
|
+ if (mixer->cfg->de_type == sun8i_mixer_de33) {
|
|
+ top_regs = mixer->top_regs;
|
|
+ disp_regs = mixer->disp_regs;
|
|
+ } else {
|
|
+ top_regs = mixer->engine.regs;
|
|
+ disp_regs = mixer->engine.regs;
|
|
+ }
|
|
+
|
|
/* Enable the mixer */
|
|
- regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_CTL,
|
|
+ regmap_write(top_regs, SUN8I_MIXER_GLOBAL_CTL,
|
|
SUN8I_MIXER_GLOBAL_CTL_RT_EN);
|
|
|
|
+ if (mixer->cfg->de_type == sun8i_mixer_de33)
|
|
+ regmap_write(top_regs, SUN50I_MIXER_GLOBAL_CLK, 1);
|
|
+
|
|
/* Set background color to black */
|
|
- regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
|
|
+ regmap_write(disp_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),
|
|
+ regmap_write(disp_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),
|
|
+ regmap_write(disp_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,
|
|
+ regmap_write(disp_regs,
|
|
SUN8I_MIXER_BLEND_MODE(base, i),
|
|
SUN8I_MIXER_BLEND_MODE_DEF);
|
|
|
|
- regmap_update_bits(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
|
|
+ regmap_update_bits(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
|
|
SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
|
|
}
|
|
|
|
@@ -573,6 +612,30 @@ static int sun8i_mixer_bind(struct device *dev, struct device *master,
|
|
return PTR_ERR(mixer->engine.regs);
|
|
}
|
|
|
|
+ if (mixer->cfg->de_type == sun8i_mixer_de33) {
|
|
+ regs = devm_platform_ioremap_resource(pdev, 1);
|
|
+ if (IS_ERR(regs))
|
|
+ return PTR_ERR(regs);
|
|
+
|
|
+ mixer->top_regs = devm_regmap_init_mmio(dev, regs,
|
|
+ &sun8i_top_regmap_config);
|
|
+ if (IS_ERR(mixer->top_regs)) {
|
|
+ dev_err(dev, "Couldn't create the top regmap\n");
|
|
+ return PTR_ERR(mixer->top_regs);
|
|
+ }
|
|
+
|
|
+ regs = devm_platform_ioremap_resource(pdev, 2);
|
|
+ if (IS_ERR(regs))
|
|
+ return PTR_ERR(regs);
|
|
+
|
|
+ mixer->disp_regs = devm_regmap_init_mmio(dev, regs,
|
|
+ &sun8i_disp_regmap_config);
|
|
+ if (IS_ERR(mixer->disp_regs)) {
|
|
+ dev_err(dev, "Couldn't create the disp regmap\n");
|
|
+ return PTR_ERR(mixer->disp_regs);
|
|
+ }
|
|
+ }
|
|
+
|
|
mixer->reset = devm_reset_control_get(dev, NULL);
|
|
if (IS_ERR(mixer->reset)) {
|
|
dev_err(dev, "Couldn't get our reset line\n");
|
|
@@ -787,6 +850,18 @@ static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
|
|
.vi_num = 1,
|
|
};
|
|
|
|
+static const struct sun8i_mixer_cfg sun50i_h616_mixer0_cfg = {
|
|
+ .ccsc = CCSC_MIXER0_LAYOUT,
|
|
+ .de_type = sun8i_mixer_de33,
|
|
+ .has_formatter = 1,
|
|
+ .mod_rate = 600000000,
|
|
+ .scaler_mask = 0xf,
|
|
+ .scanline_yuv = 4096,
|
|
+ .ui_num = 3,
|
|
+ .vi_num = 1,
|
|
+ .map = {0, 6, 7, 8},
|
|
+};
|
|
+
|
|
static const struct of_device_id sun8i_mixer_of_table[] = {
|
|
{
|
|
.compatible = "allwinner,sun8i-a83t-de2-mixer-0",
|
|
@@ -832,6 +907,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
|
|
.compatible = "allwinner,sun50i-h6-de3-mixer-0",
|
|
.data = &sun50i_h6_mixer0_cfg,
|
|
},
|
|
+ {
|
|
+ .compatible = "allwinner,sun50i-h616-de33-mixer-0",
|
|
+ .data = &sun50i_h616_mixer0_cfg,
|
|
+ },
|
|
{ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, sun8i_mixer_of_table);
|
|
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
|
|
index 75facc7d1fa6..26b001164647 100644
|
|
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
|
|
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
|
|
@@ -21,6 +21,10 @@
|
|
#define SUN8I_MIXER_GLOBAL_DBUFF 0x8
|
|
#define SUN8I_MIXER_GLOBAL_SIZE 0xc
|
|
|
|
+#define SUN50I_MIXER_GLOBAL_SIZE 0x8
|
|
+#define SUN50I_MIXER_GLOBAL_CLK 0xc
|
|
+#define SUN50I_MIXER_GLOBAL_DBUFF 0x10
|
|
+
|
|
#define SUN8I_MIXER_GLOBAL_CTL_RT_EN BIT(0)
|
|
|
|
#define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE BIT(0)
|
|
@@ -154,6 +158,7 @@ enum {
|
|
enum sun8i_mixer_type {
|
|
sun8i_mixer_de2,
|
|
sun8i_mixer_de3,
|
|
+ sun8i_mixer_de33,
|
|
};
|
|
|
|
/**
|
|
@@ -180,6 +185,7 @@ struct sun8i_mixer_cfg {
|
|
unsigned int de_type;
|
|
unsigned int has_formatter : 1;
|
|
unsigned int scanline_yuv;
|
|
+ unsigned int map[6];
|
|
};
|
|
|
|
struct sun8i_mixer {
|
|
@@ -191,6 +197,9 @@ struct sun8i_mixer {
|
|
|
|
struct clk *bus_clk;
|
|
struct clk *mod_clk;
|
|
+
|
|
+ struct regmap *top_regs;
|
|
+ struct regmap *disp_regs;
|
|
};
|
|
|
|
enum {
|
|
@@ -227,13 +236,16 @@ sun8i_blender_base(struct sun8i_mixer *mixer)
|
|
static inline struct regmap *
|
|
sun8i_blender_regmap(struct sun8i_mixer *mixer)
|
|
{
|
|
- return mixer->engine.regs;
|
|
+ return mixer->cfg->de_type == sun8i_mixer_de33 ?
|
|
+ mixer->disp_regs : mixer->engine.regs;
|
|
}
|
|
|
|
static inline u32
|
|
sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
|
|
{
|
|
- if (mixer->cfg->de_type == sun8i_mixer_de3)
|
|
+ if (mixer->cfg->de_type == sun8i_mixer_de33)
|
|
+ return mixer->cfg->map[channel] * 0x20000 + DE2_CH_SIZE;
|
|
+ else if (mixer->cfg->de_type == sun8i_mixer_de3)
|
|
return DE3_CH_BASE + channel * DE3_CH_SIZE;
|
|
else
|
|
return DE2_CH_BASE + channel * DE2_CH_SIZE;
|
|
--
|
|
2.35.3
|
|
|