[PATCH v10 10/11] drm: sun4i: de33: mixer: add Display Engine 3.3 (DE33) support

Maxime Ripard mripard at kernel.org
Wed May 14 15:07:30 UTC 2025


On Sun, May 11, 2025 at 10:31:19PM +1200, Ryan Walklin wrote:
> From: Jernej Skrabec <jernej.skrabec at gmail.com>
> 
> 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
> 
> Other features (implemented but not in this patchset):
> - AFBC ARM Frame Buffer Compression support
> - YUV pipeline 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.
> 
> The DE33 also appears to remove the global double buffer control
> register, present in the DE2 and DE3.
> 
> Extend the mixer to support the DE33.
> 
> Signed-off-by: Jernej Skrabec <jernej.skrabec at gmail.com>
> Signed-off-by: Ryan Walklin <ryan at testtoast.com>
> Signed-off-by: Chris Morgan <macromorgan at hotmail.com>
> 
> ---
> Changelog v4..v5:
> - Whitespace fixes
> - Correct strict mode warnings from checkpatch.pl
> 
> Changelog v7..v8:
> - Add top/disp regmaps to mixer for DE33
> - Remove YUV-specific code
> - Remove use of global double buffer
> - Remove unneeded if/then parentheses and fix an alignment issue as suggested by checkpatch.pl
> 
> Changelog v9..v10:
> - Use names from vendor BSP kernel for register blocks.
> ---
>  drivers/gpu/drm/sun4i/sun8i_mixer.c | 82 +++++++++++++++++++++++++----
>  drivers/gpu/drm/sun4i/sun8i_mixer.h | 22 ++++++--
>  2 files changed, 90 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> index cc4da11e2c10..0d4695132dae 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> @@ -318,8 +318,9 @@ 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(engine->regs, SUN8I_MIXER_GLOBAL_DBUFF,
> +			     SUN8I_MIXER_GLOBAL_DBUFF_ENABLE);
>  }
>  
>  static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
> @@ -368,25 +369,31 @@ static void sun8i_mixer_mode_set(struct sunxi_engine *engine,
>  				 const struct drm_display_mode *mode)
>  {
>  	struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> +	struct regmap *bld_regs;
>  	u32 bld_base, size, val;
>  	bool interlaced;
>  
>  	bld_base = sun8i_blender_base(mixer);
> +	bld_regs = sun8i_blender_regmap(mixer);
>  	interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
>  	size = SUN8I_MIXER_SIZE(mode->hdisplay, mode->vdisplay);
>  
>  	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)
> +		regmap_write(mixer->top_regs, SUN50I_MIXER_GLOBAL_SIZE, size);
> +	else
> +		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,12 +407,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;
> @@ -428,33 +452,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);
>  }
>  
> @@ -526,6 +562,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_byname(pdev, "top");
> +		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_byname(pdev, "display");
> +		if (IS_ERR(regs))
> +			return PTR_ERR(regs);
> +
> +		mixer->disp_regs = devm_regmap_init_mmio(dev, regs,
> +							 &sun8i_disp_regmap_config);
> +		if (IS_ERR(mixer->disp_regs)) {
> +			dev_err(dev, "Couldn't create the disp regmap\n");
> +			return PTR_ERR(mixer->disp_regs);
> +		}
> +	}
> +
>  	mixer->reset = devm_reset_control_get(dev, NULL);
>  	if (IS_ERR(mixer->reset)) {
>  		dev_err(dev, "Couldn't get our reset line\n");
> diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
> index 43c413052a22..d87d197610e1 100644
> --- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
> +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
> @@ -21,6 +21,9 @@
>  #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 SUN8I_MIXER_GLOBAL_CTL_RT_EN		BIT(0)
>  
>  #define SUN8I_MIXER_GLOBAL_DBUFF_ENABLE		BIT(0)
> @@ -151,6 +154,12 @@ enum {
>  	CCSC_D1_MIXER0_LAYOUT,
>  };
>  
> +enum sun8i_mixer_type {
> +	sun8i_mixer_de2,
> +	sun8i_mixer_de3,
> +	sun8i_mixer_de33,
> +};

enum variants typically have their name in upper-case.

With that fixed,
Acked-by: Maxime Ripard <mripard at kernel.org>

Maxime

>  /**
>   * struct sun8i_mixer_cfg - mixer HW configuration
>   * @vi_num: number of VI channels
> @@ -171,8 +180,9 @@ struct sun8i_mixer_cfg {
>  	int		scaler_mask;
>  	int		ccsc;
>  	unsigned long	mod_rate;
> -	unsigned int	is_de3 : 1;
> +	unsigned int	de_type;
>  	unsigned int	scanline_yuv;
> +	unsigned int	map[6];
>  };
>  
>  struct sun8i_mixer {
> @@ -184,6 +194,9 @@ struct sun8i_mixer {
>  
>  	struct clk			*bus_clk;
>  	struct clk			*mod_clk;
> +
> +	struct regmap			*top_regs;
> +	struct regmap			*disp_regs;
>  };
>  
>  enum {
> @@ -220,13 +233,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->is_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.49.0
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 273 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/dri-devel/attachments/20250514/6bc1fa84/attachment-0001.sig>


More information about the dri-devel mailing list