[PATCH v2 1/4] drm: rcar-du: lvds: Convert to DRM panel bridge helper

Laurent Pinchart laurent.pinchart at ideasonboard.com
Wed Dec 16 13:49:24 UTC 2020


Hi Jacopo,

On Wed, Dec 16, 2020 at 02:16:56PM +0100, Jacopo Mondi wrote:
> On Wed, Dec 16, 2020 at 02:50:18AM +0200, Laurent Pinchart wrote:
> > Replace the manual panel handling with usage of the DRM panel bridge
> > helper. This simplifies the driver, and brings support for
> > DRM_BRIDGE_ATTACH_NO_CONNECTOR as an added bonus.
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas at ideasonboard.com>
> > ---
> >  drivers/gpu/drm/rcar-du/rcar_lvds.c | 120 +++-------------------------
> >  1 file changed, 12 insertions(+), 108 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > index 70dbbe44bb23..1b360e06658c 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > @@ -63,7 +63,6 @@ struct rcar_lvds {
> >  	struct drm_bridge bridge;
> >
> >  	struct drm_bridge *next_bridge;
> > -	struct drm_connector connector;
> >  	struct drm_panel *panel;
> >
> >  	void __iomem *mmio;
> > @@ -80,73 +79,11 @@ struct rcar_lvds {
> >  #define bridge_to_rcar_lvds(b) \
> >  	container_of(b, struct rcar_lvds, bridge)
> >
> > -#define connector_to_rcar_lvds(c) \
> > -	container_of(c, struct rcar_lvds, connector)
> > -
> >  static void rcar_lvds_write(struct rcar_lvds *lvds, u32 reg, u32 data)
> >  {
> >  	iowrite32(data, lvds->mmio + reg);
> >  }
> >
> > -/* -----------------------------------------------------------------------------
> > - * Connector & Panel
> > - */
> > -
> > -static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
> > -{
> > -	struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
> > -
> > -	return drm_panel_get_modes(lvds->panel, connector);
> > -}
> > -
> > -static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> > -					    struct drm_atomic_state *state)
> > -{
> > -	struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
> > -	const struct drm_display_mode *panel_mode;
> > -	struct drm_connector_state *conn_state;
> > -	struct drm_crtc_state *crtc_state;
> > -
> > -	conn_state = drm_atomic_get_new_connector_state(state, connector);
> > -	if (!conn_state->crtc)
> > -		return 0;
> > -
> > -	if (list_empty(&connector->modes)) {
> > -		dev_dbg(lvds->dev, "connector: empty modes list\n");
> > -		return -EINVAL;
> > -	}
> > -
> > -	panel_mode = list_first_entry(&connector->modes,
> > -				      struct drm_display_mode, head);
> > -
> > -	/* We're not allowed to modify the resolution. */
> > -	crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
> > -	if (IS_ERR(crtc_state))
> > -		return PTR_ERR(crtc_state);
> > -
> > -	if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
> > -	    crtc_state->mode.vdisplay != panel_mode->vdisplay)
> > -		return -EINVAL;
> > -
> > -	/* The flat panel mode is fixed, just copy it to the adjusted mode. */
> > -	drm_mode_copy(&crtc_state->adjusted_mode, panel_mode);
> > -
> > -	return 0;
> > -}
> > -
> > -static const struct drm_connector_helper_funcs rcar_lvds_conn_helper_funcs = {
> > -	.get_modes = rcar_lvds_connector_get_modes,
> > -	.atomic_check = rcar_lvds_connector_atomic_check,
> > -};
> > -
> > -static const struct drm_connector_funcs rcar_lvds_conn_funcs = {
> > -	.reset = drm_atomic_helper_connector_reset,
> > -	.fill_modes = drm_helper_probe_single_connector_modes,
> > -	.destroy = drm_connector_cleanup,
> > -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> > -	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> > -};
> > -
> >  /* -----------------------------------------------------------------------------
> >   * PLL Setup
> >   */
> > @@ -583,11 +520,6 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge,
> >  	/* Turn the output on. */
> >  	lvdcr0 |= LVDCR0_LVRES;
> >  	rcar_lvds_write(lvds, LVDCR0, lvdcr0);
> > -
> > -	if (lvds->panel) {
> > -		drm_panel_prepare(lvds->panel);
> > -		drm_panel_enable(lvds->panel);
> > -	}
> >  }
> >
> >  static void rcar_lvds_atomic_enable(struct drm_bridge *bridge,
> > @@ -609,11 +541,6 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge,
> >  {
> >  	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
> >
> > -	if (lvds->panel) {
> > -		drm_panel_disable(lvds->panel);
> > -		drm_panel_unprepare(lvds->panel);
> > -	}
> > -
> >  	rcar_lvds_write(lvds, LVDCR0, 0);
> >  	rcar_lvds_write(lvds, LVDCR1, 0);
> >  	rcar_lvds_write(lvds, LVDPLLCR, 0);
> > @@ -648,45 +575,13 @@ static int rcar_lvds_attach(struct drm_bridge *bridge,
> >  			    enum drm_bridge_attach_flags flags)
> >  {
> >  	struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
> > -	struct drm_connector *connector = &lvds->connector;
> > -	struct drm_encoder *encoder = bridge->encoder;
> > -	int ret;
> >
> > -	/* If we have a next bridge just attach it. */
> > -	if (lvds->next_bridge)
> > -		return drm_bridge_attach(bridge->encoder, lvds->next_bridge,
> > -					 bridge, flags);
> > -
> > -	if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
> > -		DRM_ERROR("Fix bridge driver to make connector optional!");
> > -		return -EINVAL;
> > -	}
> > -
> > -	/* Otherwise if we have a panel, create a connector. */
> > -	if (!lvds->panel)
> > -		return 0;
> > -
> > -	ret = drm_connector_init(bridge->dev, connector, &rcar_lvds_conn_funcs,
> > -				 DRM_MODE_CONNECTOR_LVDS);
> > -	if (ret < 0)
> > -		return ret;
> > -
> > -	drm_connector_helper_add(connector, &rcar_lvds_conn_helper_funcs);
> > -
> > -	ret = drm_connector_attach_encoder(connector, encoder);
> > -	if (ret < 0)
> > -		return ret;
> > -
> > -	return 0;
> > -}
> > -
> > -static void rcar_lvds_detach(struct drm_bridge *bridge)
> > -{
> > +	return drm_bridge_attach(bridge->encoder, lvds->next_bridge, bridge,
> > +				 flags);
> >  }
> >
> >  static const struct drm_bridge_funcs rcar_lvds_bridge_ops = {
> >  	.attach = rcar_lvds_attach,
> > -	.detach = rcar_lvds_detach,
> >  	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> >  	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> >  	.atomic_reset = drm_atomic_helper_bridge_reset,
> > @@ -759,7 +654,7 @@ static int rcar_lvds_parse_dt_companion(struct rcar_lvds *lvds)
> >  		 * that we are expected to generate even pixels from the primary
> >  		 * encoder, and odd pixels from the companion encoder.
> >  		 */
> > -		if (lvds->next_bridge && lvds->next_bridge->timings &&
> > +		if (lvds->next_bridge->timings &&
> >  		    lvds->next_bridge->timings->dual_link)
> >  			lvds->link_type = RCAR_LVDS_DUAL_LINK_EVEN_ODD_PIXELS;
> >  		else
> > @@ -811,6 +706,15 @@ static int rcar_lvds_parse_dt(struct rcar_lvds *lvds)
> >  	if (ret)
> >  		goto done;
> >
> > +	if (lvds->panel) {
> > +		lvds->next_bridge = devm_drm_panel_bridge_add(lvds->dev,
> > +							      lvds->panel);
> 
> Reading the devm_drm_panel_bridge_add() function documentation:
> 
>  * devm_drm_panel_bridge_add - Creates a managed &drm_bridge and &drm_connector
> 
> Doesn't this conflict with the drm_bridge_connector_init() called by
> the encoder in [4/4] ?

It would, if the documentation was right :-) The function only creates a
bridge. A connector will only be created when the bridge is attached
without DRM_BRIDGE_ATTACH_NO_CONNECTOR.

Would you like to send a patch to fix the documentation ?

> > +		if (IS_ERR_OR_NULL(lvds->next_bridge)) {
> > +			ret = -EINVAL;
> > +			goto done;
> > +		}
> > +	}
> > +
> >  	if (lvds->info->quirks & RCAR_LVDS_QUIRK_DUAL_LINK)
> >  		ret = rcar_lvds_parse_dt_companion(lvds);
> >

-- 
Regards,

Laurent Pinchart


More information about the dri-devel mailing list