On 22/08/2021 01:36, Laurent Pinchart wrote: > On R-Car D3 and E3, the LVDS encoders provide the pixel clock to the DU, > even when LVDS outputs are not used. For this reason, the rcar-lvds > driver probes successfully on those platforms even if no further bridge > or panel is connected to the LVDS output, in order to provide the > rcar_lvds_clk_enable() and rcar_lvds_clk_disable() functions to the DU > driver. > > If an LVDS output isn't connected, trying to create a DRM connector for > the output will fail. Fix this by skipping connector creation in that > case, and also skip creation of the DRM encoder as there's no point in > an encoder without a connector. > > Fixes: e9e056949c92 ("drm: rcar-du: lvds: Convert to DRM panel bridge helper") > Reported-by: Geert Uytterhoeven <geert@xxxxxxxxxxxxxx> > Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@xxxxxxxxxxxxxxxx> Perhaps this helps it get upstream... Reviewed-by: Kieran Bingham <kieran.bingham+renesas@xxxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/rcar-du/rcar_du_encoder.c | 16 ++++++++++++---- > drivers/gpu/drm/rcar-du/rcar_lvds.c | 11 +++++++++++ > drivers/gpu/drm/rcar-du/rcar_lvds.h | 5 +++++ > 3 files changed, 28 insertions(+), 4 deletions(-) > > diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c > index 0daa8bba50f5..4bf4e25d7f01 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c > +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c > @@ -86,12 +86,20 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, > } > > /* > - * Create and initialize the encoder. On Gen3 skip the LVDS1 output if > + * Create and initialize the encoder. On Gen3, skip the LVDS1 output if > * the LVDS1 encoder is used as a companion for LVDS0 in dual-link > - * mode. > + * mode, or any LVDS output if it isn't connected. The latter may happen > + * on D3 or E3 as the LVDS encoders are needed to provide the pixel > + * clock to the DU, even when the LVDS outputs are not used. > */ > - if (rcdu->info->gen >= 3 && output == RCAR_DU_OUTPUT_LVDS1) { > - if (rcar_lvds_dual_link(bridge)) > + if (rcdu->info->gen >= 3) { > + if (output == RCAR_DU_OUTPUT_LVDS1 && > + rcar_lvds_dual_link(bridge)) > + return -ENOLINK; > + > + if ((output == RCAR_DU_OUTPUT_LVDS0 || > + output == RCAR_DU_OUTPUT_LVDS1) && > + !rcar_lvds_is_connected(bridge)) > return -ENOLINK; > } > > diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c > index d061b8de748f..b672c5bd72ee 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c > +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c > @@ -576,6 +576,9 @@ static int rcar_lvds_attach(struct drm_bridge *bridge, > { > struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); > > + if (!lvds->next_bridge) > + return 0; > + > return drm_bridge_attach(bridge->encoder, lvds->next_bridge, bridge, > flags); > } > @@ -598,6 +601,14 @@ bool rcar_lvds_dual_link(struct drm_bridge *bridge) > } > EXPORT_SYMBOL_GPL(rcar_lvds_dual_link); > > +bool rcar_lvds_is_connected(struct drm_bridge *bridge) > +{ > + struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); > + > + return lvds->next_bridge != NULL; > +} > +EXPORT_SYMBOL_GPL(rcar_lvds_is_connected); > + > /* ----------------------------------------------------------------------------- > * Probe & Remove > */ > diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.h b/drivers/gpu/drm/rcar-du/rcar_lvds.h > index 222ec0e60785..eb7c6ef03b00 100644 > --- a/drivers/gpu/drm/rcar-du/rcar_lvds.h > +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.h > @@ -16,6 +16,7 @@ struct drm_bridge; > int rcar_lvds_clk_enable(struct drm_bridge *bridge, unsigned long freq); > void rcar_lvds_clk_disable(struct drm_bridge *bridge); > bool rcar_lvds_dual_link(struct drm_bridge *bridge); > +bool rcar_lvds_is_connected(struct drm_bridge *bridge); > #else > static inline int rcar_lvds_clk_enable(struct drm_bridge *bridge, > unsigned long freq) > @@ -27,6 +28,10 @@ static inline bool rcar_lvds_dual_link(struct drm_bridge *bridge) > { > return false; > } > +static inline bool rcar_lvds_is_connected(struct drm_bridge *bridge) > +{ > + return false; > +} > #endif /* CONFIG_DRM_RCAR_LVDS */ > > #endif /* __RCAR_LVDS_H__ */ >