Hi Geert, Laurent,

On Wed, Nov 26, 2025 at 03:07:26PM +0100, Tommaso Merciai wrote:
> The RZ/G3E Soc has 2 LCD controller (LCDC), contain a Frame Compression
> Processor (FCPVD), a Video Signal Processor (VSPD), Video Signal
> Processor (VSPD), and Display Unit (DU).
> 
> LCDC0 supports DSI and LVDS (single or dual-channel) outputs.
> LCDC1 supports DSI, LVDS (single-channel), and RGB outputs.
> 
> Depending on the selected output, the correct SMUX2 clock parent must be
> chosen:
> 
>  - Index 0 if LVDS0 or LVDS1 is used
>  - Index 1 for all other cases
> 
> To support this behavior, introduce the `RG2L_DU_FEATURE_SMUX2_DSI_CLK`
> feature flag and extend the `rzg2l_du_device_info` structure to include a
> features field. Also, add a new helper function `rzg2l_du_has()` to check
> for feature flags.
> 
> Add support for the RZ/G3E SoC by introducing:
>  - `rzg2l_du_r9a09g047_du{0,1}_info` structures
>  - The `renesas,r9a09g047-du{0,1}` compatible strings
> 
> Additionally, introduce the missing output definitions
> `RZG2L_DU_OUTPUT_LVDS{0,1}`.
> 
> Introduce `rzg2l_du_crtc_atomic_check()` helper to store the routes from
> the CRTC output to the DU outputs.
> 
> Signed-off-by: Tommaso Merciai <[email protected]>
> ---
>  drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c | 51 +++++++++++++++++++
>  drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c  | 42 +++++++++++++++
>  drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h  | 11 ++++
>  3 files changed, 104 insertions(+)
> 
> diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c 
> b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c
> index 6e7aac6219be..044ac16256c7 100644
> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c
> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c
> @@ -8,6 +8,7 @@
>   */
>  
>  #include <linux/clk.h>
> +#include <linux/clk-provider.h>
>  #include <linux/mutex.h>
>  #include <linux/platform_device.h>
>  #include <linux/reset.h>
> @@ -64,11 +65,34 @@
>  static void rzg2l_du_crtc_set_display_timing(struct rzg2l_du_crtc *rcrtc)
>  {
>       const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
> +     struct rzg2l_du_crtc_state *rstate =
> +             to_rzg2l_crtc_state(rcrtc->crtc.state);
>       unsigned long mode_clock = mode->clock * 1000;
>       u32 ditr0, ditr1, ditr2, ditr3, ditr4, pbcr0;
>       struct rzg2l_du_device *rcdu = rcrtc->dev;
>  
>       clk_prepare_enable(rcrtc->rzg2l_clocks.dclk);
> +
> +     if (rzg2l_du_has(rcdu, RG2L_DU_FEATURE_SMUX2_DSI_CLK)) {
> +             struct clk_hw *hw_parent, *hw_pparent;
> +             struct clk *clk_parent;
> +
> +             clk_parent = clk_get_parent(rcrtc->rzg2l_clocks.dclk);
> +             hw_parent = __clk_get_hw(clk_parent);
> +
> +             /*
> +              * SMUX2_DSI0_CLK: if LVDS0 is used, be sure to set 0b.
> +              * SMUX2_DSI1_CLK: if LVDS1 is used, be sure to set 0b.
> +              */
> +             if (rstate->outputs == BIT(RZG2L_DU_OUTPUT_LVDS0) ||
> +                 rstate->outputs == BIT(RZG2L_DU_OUTPUT_LVDS1))
> +                     hw_pparent = clk_hw_get_parent_by_index(hw_parent, 0);
> +             else
> +                     hw_pparent = clk_hw_get_parent_by_index(hw_parent, 1);
> +
> +             clk_set_parent(clk_parent, hw_pparent->clk);
> +     }
> +

Here is the reason on why we need the CLK_TYPE_PLLDSI_SMUX.
As LVDS needs clock parent = vclk * 7

For that we need the custom mux (rzv2h_cpg_plldsi_smux_determine_rate())
to generate the rights pll rate.

What do you think? Please gently let me know.

Thanks & Regards,
Tommmaso

>       clk_set_rate(rcrtc->rzg2l_clocks.dclk, mode_clock);
>  
>       ditr0 = (DU_DITR0_DEMD_HIGH
> @@ -248,6 +272,32 @@ static void rzg2l_du_crtc_stop(struct rzg2l_du_crtc 
> *rcrtc)
>   * CRTC Functions
>   */
>  
> +static int rzg2l_du_crtc_atomic_check(struct drm_crtc *crtc,
> +                                   struct drm_atomic_state *state)
> +{
> +     struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
> +                                                                       crtc);
> +     struct rzg2l_du_crtc_state *rstate = to_rzg2l_crtc_state(crtc_state);
> +     struct drm_encoder *encoder;
> +
> +     /* Store the routes from the CRTC output to the DU outputs. */
> +     rstate->outputs = 0;
> +
> +     drm_for_each_encoder_mask(encoder, crtc->dev,
> +                               crtc_state->encoder_mask) {
> +             struct rzg2l_du_encoder *renc;
> +
> +             /* Skip the writeback encoder. */
> +             if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL)
> +                     continue;
> +
> +             renc = to_rzg2l_encoder(encoder);
> +             rstate->outputs |= BIT(renc->output);
> +     }
> +
> +     return 0;
> +}
> +
>  static void rzg2l_du_crtc_atomic_enable(struct drm_crtc *crtc,
>                                       struct drm_atomic_state *state)
>  {
> @@ -296,6 +346,7 @@ static void rzg2l_du_crtc_atomic_flush(struct drm_crtc 
> *crtc,
>  }
>  
>  static const struct drm_crtc_helper_funcs crtc_helper_funcs = {
> +     .atomic_check = rzg2l_du_crtc_atomic_check,
>       .atomic_flush = rzg2l_du_crtc_atomic_flush,
>       .atomic_enable = rzg2l_du_crtc_atomic_enable,
>       .atomic_disable = rzg2l_du_crtc_atomic_disable,
> diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c 
> b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
> index 0fef33a5a089..73ff095e49ae 100644
> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c
> @@ -51,6 +51,44 @@ static const struct rzg2l_du_device_info 
> rzg2l_du_r9a07g044_info = {
>       }
>  };
>  
> +static const struct rzg2l_du_device_info rzg2l_du_r9a09g047_du0_info = {
> +     .features = RG2L_DU_FEATURE_SMUX2_DSI_CLK,
> +     .channels_mask = BIT(0),
> +     .routes = {
> +             [RZG2L_DU_OUTPUT_DSI0] = {
> +                     .possible_outputs = BIT(0),
> +                     .port = 0,
> +             },
> +             [RZG2L_DU_OUTPUT_LVDS0] = {
> +                     .possible_outputs = BIT(0),
> +                     .port = 1,
> +             },
> +             [RZG2L_DU_OUTPUT_LVDS1] = {
> +                     .possible_outputs = BIT(0),
> +                     .port = 2,
> +             },
> +     },
> +};
> +
> +static const struct rzg2l_du_device_info rzg2l_du_r9a09g047_du1_info = {
> +     .features = RG2L_DU_FEATURE_SMUX2_DSI_CLK,
> +     .channels_mask = BIT(0),
> +     .routes = {
> +             [RZG2L_DU_OUTPUT_DSI0] = {
> +                     .possible_outputs = BIT(0),
> +                     .port = 0,
> +             },
> +             [RZG2L_DU_OUTPUT_LVDS0] = {
> +                     .possible_outputs = BIT(0),
> +                     .port = 1,
> +             },
> +             [RZG2L_DU_OUTPUT_DPAD0] = {
> +                     .possible_outputs = BIT(0),
> +                     .port = 2,
> +             },
> +     },
> +};
> +
>  static const struct rzg2l_du_device_info rzg2l_du_r9a09g057_info = {
>       .channels_mask = BIT(0),
>       .routes = {
> @@ -64,6 +102,8 @@ static const struct rzg2l_du_device_info 
> rzg2l_du_r9a09g057_info = {
>  static const struct of_device_id rzg2l_du_of_table[] = {
>       { .compatible = "renesas,r9a07g043u-du", .data = 
> &rzg2l_du_r9a07g043u_info },
>       { .compatible = "renesas,r9a07g044-du", .data = 
> &rzg2l_du_r9a07g044_info },
> +     { .compatible = "renesas,r9a09g047-du0", .data = 
> &rzg2l_du_r9a09g047_du0_info },
> +     { .compatible = "renesas,r9a09g047-du1", .data = 
> &rzg2l_du_r9a09g047_du1_info },
>       { .compatible = "renesas,r9a09g057-du", .data = 
> &rzg2l_du_r9a09g057_info },
>       { /* sentinel */ }
>  };
> @@ -74,6 +114,8 @@ const char *rzg2l_du_output_name(enum rzg2l_du_output 
> output)
>  {
>       static const char * const names[] = {
>               [RZG2L_DU_OUTPUT_DSI0] = "DSI0",
> +             [RZG2L_DU_OUTPUT_LVDS0] = "LVDS0",
> +             [RZG2L_DU_OUTPUT_LVDS1] = "LVDS1",
>               [RZG2L_DU_OUTPUT_DPAD0] = "DPAD0"
>       };
>  
> diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h 
> b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
> index 58806c2a8f2b..c6f9dc46ab31 100644
> --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
> +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h
> @@ -20,8 +20,12 @@
>  struct device;
>  struct drm_property;
>  
> +#define RG2L_DU_FEATURE_SMUX2_DSI_CLK        BIT(0)  /* Per output mux */
> +
>  enum rzg2l_du_output {
>       RZG2L_DU_OUTPUT_DSI0,
> +     RZG2L_DU_OUTPUT_LVDS0,
> +     RZG2L_DU_OUTPUT_LVDS1,
>       RZG2L_DU_OUTPUT_DPAD0,
>       RZG2L_DU_OUTPUT_MAX,
>  };
> @@ -46,6 +50,7 @@ struct rzg2l_du_output_routing {
>   * @routes: array of CRTC to output routes, indexed by output 
> (RZG2L_DU_OUTPUT_*)
>   */
>  struct rzg2l_du_device_info {
> +     unsigned int features;
>       unsigned int channels_mask;
>       struct rzg2l_du_output_routing routes[RZG2L_DU_OUTPUT_MAX];
>  };
> @@ -73,6 +78,12 @@ static inline struct rzg2l_du_device 
> *to_rzg2l_du_device(struct drm_device *dev)
>       return container_of(dev, struct rzg2l_du_device, ddev);
>  }
>  
> +static inline bool rzg2l_du_has(struct rzg2l_du_device *rcdu,
> +                             unsigned int feature)
> +{
> +     return rcdu->info->features & feature;
> +}
> +
>  const char *rzg2l_du_output_name(enum rzg2l_du_output output);
>  
>  #endif /* __RZG2L_DU_DRV_H__ */
> -- 
> 2.43.0
> 

Reply via email to