On Sun, Feb 15, 2026 at 3:03 PM Jernej Škrabec <[email protected]> wrote:
>
> Hi Chen-Yu,
>
> Dne četrtek, 25. december 2025 ob 10:49:47 Srednjeevropski standardni čas je 
> Chen-Yu Tsai napisal(a):
> > On Sat, Nov 15, 2025 at 10:14 PM Jernej Skrabec
> > <[email protected]> wrote:
> > >
> > > Now that everything is in place, switch DE33 to new bindings.
> > >
> > > Signed-off-by: Jernej Skrabec <[email protected]>
> > > ---
> > >  drivers/gpu/drm/sun4i/sun8i_mixer.c | 130 +++++++++++++++-------------
> > >  drivers/gpu/drm/sun4i/sun8i_mixer.h |  10 +--
> > >  2 files changed, 71 insertions(+), 69 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c 
> > > b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> > > index fde3b677e925..da213e54e653 100644
> > > --- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
> > > +++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
> > > @@ -13,6 +13,7 @@
> > >  #include <linux/of.h>
> > >  #include <linux/of_device.h>
> > >  #include <linux/of_graph.h>
> > > +#include <linux/of_platform.h>
> > >  #include <linux/platform_device.h>
> > >  #include <linux/reset.h>
> > >
> > > @@ -24,6 +25,7 @@
> > >  #include <drm/drm_probe_helper.h>
> > >
> > >  #include "sun4i_drv.h"
> > > +#include "sun50i_planes.h"
> > >  #include "sun8i_mixer.h"
> > >  #include "sun8i_ui_layer.h"
> > >  #include "sun8i_vi_layer.h"
> > > @@ -256,7 +258,6 @@ static void sun8i_mixer_commit(struct sunxi_engine 
> > > *engine,
> > >  {
> > >         struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> > >         u32 bld_base = sun8i_blender_base(mixer);
> > > -       struct regmap *bld_regs = sun8i_blender_regmap(mixer);
> > >         struct drm_plane_state *plane_state;
> > >         struct drm_plane *plane;
> > >         u32 route = 0, pipe_en = 0;
> > > @@ -293,16 +294,16 @@ static void sun8i_mixer_commit(struct sunxi_engine 
> > > *engine,
> > >                 route |= layer->index << 
> > > SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
> > >                 pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
> > >
> > > -               regmap_write(bld_regs,
> > > +               regmap_write(engine->regs,
> > >                              SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
> > >                              SUN8I_MIXER_COORD(x, y));
> > > -               regmap_write(bld_regs,
> > > +               regmap_write(engine->regs,
> > >                              SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, 
> > > zpos),
> > >                              SUN8I_MIXER_SIZE(w, h));
> > >         }
> > >
> > > -       regmap_write(bld_regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
> > > -       regmap_write(bld_regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
> > > +       regmap_write(engine->regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), 
> > > route);
> > > +       regmap_write(engine->regs, SUN8I_MIXER_BLEND_PIPE_CTL(bld_base),
> > >                      pipe_en | SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
> > >
> > >         if (mixer->cfg->de_type != SUN8I_MIXER_DE33)
> > > @@ -317,7 +318,6 @@ static struct drm_plane **sun8i_layers_init(struct 
> > > drm_device *drm,
> > >         struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> > >         int plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
> > >         enum drm_plane_type type;
> > > -       unsigned int phy_index;
> > >         int i;
> > >
> > >         planes = devm_kcalloc(drm->dev, plane_cnt, sizeof(*planes), 
> > > GFP_KERNEL);
> > > @@ -332,12 +332,8 @@ static struct drm_plane **sun8i_layers_init(struct 
> > > drm_device *drm,
> > >                 else
> > >                         type = DRM_PLANE_TYPE_OVERLAY;
> > >
> > > -               phy_index = i;
> > > -               if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> > > -                       phy_index = mixer->cfg->map[i];
> > > -
> > >                 layer = sun8i_vi_layer_init_one(drm, type, 
> > > mixer->engine.regs,
> > > -                                               i, phy_index, plane_cnt,
> > > +                                               i, i, plane_cnt,
> > >                                                 &mixer->cfg->lay_cfg);
> > >                 if (IS_ERR(layer)) {
> > >                         dev_err(drm->dev,
> > > @@ -357,12 +353,8 @@ static struct drm_plane **sun8i_layers_init(struct 
> > > drm_device *drm,
> > >                 else
> > >                         type = DRM_PLANE_TYPE_OVERLAY;
> > >
> > > -               phy_index = index;
> > > -               if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> > > -                       phy_index = mixer->cfg->map[index];
> > > -
> > >                 layer = sun8i_ui_layer_init_one(drm, type, 
> > > mixer->engine.regs,
> > > -                                               index, phy_index, 
> > > plane_cnt,
> > > +                                               index, index, plane_cnt,
> > >                                                 &mixer->cfg->lay_cfg);
> > >                 if (IS_ERR(layer)) {
> > >                         dev_err(drm->dev, "Couldn't initialize %s 
> > > plane\n",
> > > @@ -376,16 +368,25 @@ static struct drm_plane **sun8i_layers_init(struct 
> > > drm_device *drm,
> > >         return planes;
> > >  }
> > >
> > > +static struct drm_plane **sun50i_layers_init(struct drm_device *drm,
> > > +                                            struct sunxi_engine *engine)
> > > +{
> > > +       struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
> > > +
> > > +       if (IS_ENABLED(CONFIG_DRM_SUN50I_PLANES))
> > > +               return sun50i_planes_setup(mixer->planes_dev, drm, 
> > > engine->id);
> > > +
> > > +       return NULL;
> > > +}
> > > +
> > >  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);
> > >
> > > @@ -397,14 +398,14 @@ static void sun8i_mixer_mode_set(struct 
> > > sunxi_engine *engine,
> > >         else
> > >                 regmap_write(mixer->engine.regs, SUN8I_MIXER_GLOBAL_SIZE, 
> > > size);
> > >
> > > -       regmap_write(bld_regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), size);
> > > +       regmap_write(engine->regs, SUN8I_MIXER_BLEND_OUTSIZE(bld_base), 
> > > size);
> > >
> > >         if (interlaced)
> > >                 val = SUN8I_MIXER_BLEND_OUTCTL_INTERLACED;
> > >         else
> > >                 val = 0;
> > >
> > > -       regmap_update_bits(bld_regs, SUN8I_MIXER_BLEND_OUTCTL(bld_base),
> > > +       regmap_update_bits(engine->regs, 
> > > SUN8I_MIXER_BLEND_OUTCTL(bld_base),
> > >                            SUN8I_MIXER_BLEND_OUTCTL_INTERLACED, val);
> > >
> > >         DRM_DEBUG_DRIVER("Switching display mixer interlaced mode %s\n",
> > > @@ -417,8 +418,14 @@ static const struct sunxi_engine_ops 
> > > sun8i_engine_ops = {
> > >         .mode_set       = sun8i_mixer_mode_set,
> > >  };
> > >
> > > +static const struct sunxi_engine_ops sun50i_engine_ops = {
> > > +       .commit         = sun8i_mixer_commit,
> > > +       .layers_init    = sun50i_layers_init,
> > > +       .mode_set       = sun8i_mixer_mode_set,
> > > +};
> > > +
> > >  static const struct regmap_config sun8i_mixer_regmap_config = {
> > > -       .name           = "layers",
> > > +       .name           = "display",
> > >         .reg_bits       = 32,
> > >         .val_bits       = 32,
> > >         .reg_stride     = 4,
> > > @@ -433,14 +440,6 @@ static const struct regmap_config 
> > > sun8i_top_regmap_config = {
> > >         .max_register   = 0x3c,
> > >  };
> > >
> > > -static const struct regmap_config sun8i_disp_regmap_config = {
> > > -       .name           = "display",
> > > -       .reg_bits       = 32,
> > > -       .val_bits       = 32,
> > > -       .reg_stride     = 4,
> > > -       .max_register   = 0x20000,
> > > -};
> > > -
> > >  static int sun8i_mixer_of_get_id(struct device_node *node)
> > >  {
> > >         struct device_node *ep, *remote;
> > > @@ -463,17 +462,14 @@ static int sun8i_mixer_of_get_id(struct device_node 
> > > *node)
> > >
> > >  static void sun8i_mixer_init(struct sun8i_mixer *mixer)
> > >  {
> > > -       struct regmap *top_regs, *disp_regs;
> > >         unsigned int base = sun8i_blender_base(mixer);
> > > +       struct regmap *top_regs;
> > >         int plane_cnt, i;
> > >
> > > -       if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
> > > +       if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> > >                 top_regs = mixer->top_regs;
> > > -               disp_regs = mixer->disp_regs;
> > > -       } else {
> > > +       else
> > >                 top_regs = mixer->engine.regs;
> > > -               disp_regs = mixer->engine.regs;
> > > -       }
> > >
> > >         /* Enable the mixer */
> > >         regmap_write(top_regs, SUN8I_MIXER_GLOBAL_CTL,
> > > @@ -483,25 +479,25 @@ static void sun8i_mixer_init(struct sun8i_mixer 
> > > *mixer)
> > >                 regmap_write(top_regs, SUN50I_MIXER_GLOBAL_CLK, 1);
> > >
> > >         /* Set background color to black */
> > > -       regmap_write(disp_regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
> > > +       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_BKCOLOR(base),
> > >                      SUN8I_MIXER_BLEND_COLOR_BLACK);
> > >
> > >         /*
> > >          * Set fill color of bottom plane to black. Generally not needed
> > >          * except when VI plane is at bottom (zpos = 0) and enabled.
> > >          */
> > > -       regmap_write(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
> > > +       regmap_write(mixer->engine.regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
> > >                      SUN8I_MIXER_BLEND_PIPE_CTL_FC_EN(0));
> > > -       regmap_write(disp_regs, SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
> > > +       regmap_write(mixer->engine.regs, 
> > > SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, 0),
> > >                      SUN8I_MIXER_BLEND_COLOR_BLACK);
> > >
> > >         plane_cnt = mixer->cfg->vi_num + mixer->cfg->ui_num;
> > >         for (i = 0; i < plane_cnt; i++)
> > > -               regmap_write(disp_regs,
> > > +               regmap_write(mixer->engine.regs,
> > >                              SUN8I_MIXER_BLEND_MODE(base, i),
> > >                              SUN8I_MIXER_BLEND_MODE_DEF);
> > >
> > > -       regmap_update_bits(disp_regs, SUN8I_MIXER_BLEND_PIPE_CTL(base),
> > > +       regmap_update_bits(mixer->engine.regs, 
> > > SUN8I_MIXER_BLEND_PIPE_CTL(base),
> > >                            SUN8I_MIXER_BLEND_PIPE_CTL_EN_MSK, 0);
> > >  }
> > >
> > > @@ -532,7 +528,6 @@ static int sun8i_mixer_bind(struct device *dev, 
> > > struct device *master,
> > >         if (!mixer)
> > >                 return -ENOMEM;
> > >         dev_set_drvdata(dev, mixer);
> > > -       mixer->engine.ops = &sun8i_engine_ops;
> > >         mixer->engine.node = dev->of_node;
> > >
> > >         if (of_property_present(dev->of_node, "iommus")) {
> > > @@ -562,6 +557,11 @@ static int sun8i_mixer_bind(struct device *dev, 
> > > struct device *master,
> > >         if (!mixer->cfg)
> > >                 return -EINVAL;
> > >
> > > +       if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
> > > +               mixer->engine.ops = &sun50i_engine_ops;
> >
> > You're missing an IS_ENABLED() clause here if you wanted to make the DE 3.3
> > planes driver optional. Though as I mentioned in the other patch, splittig
> > the two modules might not work.
> >
> > > +       else
> > > +               mixer->engine.ops = &sun8i_engine_ops;
> > > +
> > >         regs = devm_platform_ioremap_resource(pdev, 0);
> > >         if (IS_ERR(regs))
> > >                 return PTR_ERR(regs);
> > > @@ -584,17 +584,6 @@ static int sun8i_mixer_bind(struct device *dev, 
> > > struct device *master,
> > >                         dev_err(dev, "Couldn't create the top regmap\n");
> > >                         return PTR_ERR(mixer->top_regs);
> > >                 }
> > > -
> > > -               regs = devm_platform_ioremap_resource_byname(pdev, 
> > > "display");
> > > -               if (IS_ERR(regs))
> > > -                       return PTR_ERR(regs);
> > > -
> > > -               mixer->disp_regs = devm_regmap_init_mmio(dev, regs,
> > > -                                                        
> > > &sun8i_disp_regmap_config);
> > > -               if (IS_ERR(mixer->disp_regs)) {
> > > -                       dev_err(dev, "Couldn't create the disp regmap\n");
> > > -                       return PTR_ERR(mixer->disp_regs);
> > > -               }
> > >         }
> > >
> > >         mixer->reset = devm_reset_control_get(dev, NULL);
> > > @@ -634,6 +623,33 @@ static int sun8i_mixer_bind(struct device *dev, 
> > > struct device *master,
> > >
> > >         clk_prepare_enable(mixer->mod_clk);
> > >
> > > +       if (mixer->cfg->de_type == SUN8I_MIXER_DE33) {
> > > +               struct platform_device *pdev;
> > > +               struct device_node *np;
> > > +               void *data;
> > > +
> > > +               np = of_parse_phandle(dev->of_node, "allwinner,planes", 
> > > 0);
> > > +               if (!np) {
> > > +                       ret = -ENODEV;
> > > +                       goto err_disable_mod_clk;
> > > +               }
> > > +
> > > +               pdev = of_find_device_by_node(np);
> >
> > You need to add a matching put_device() in the unbind function.
> >
> > Side note:
> >
> > This bind function is using a lot of devm_ functions. These have the wrong
> > lifetime. I think it would be better if we could move resource acquisition
> > into the probe function.
>
> Looking a bit more into this, this requires a bit more work. For example, 
> clocks
> can be provided by tcon-top, which are created only in bind callback. 
> Basically,
> whole sun4i-drm driver depends on devm_* calls in bind functions. This would
> need careful analysis of all driver calls and then refactoring drivers one by 
> one.

Unfortunately so. However most of them just require moving the initial
context memory allocation and whatever resource acquisition over. It
shouldn't be that messy.

> IMO tcon-top driver needs to be refactored to plain clock driver without 
> component
> bind/unbind functions. Although this may cause slightly higher power 
> consumption
> if device doesn't have display but driver is loaded nevertheless.
>
> What do you think?

It's just the bus clock that's enabled all the time, so I think that's fine.
However since it sits in the middle of the whole OF graph, you either need
to make sun4i-drm know to skip that when adding all the components, or just
keep a dummy bind callback and component to make it happy.


Thanks
ChenYu

Reply via email to