Hi Tommaso, Thank you for the patch.
On Mon, Feb 2, 2026 at 12:04 PM Tommaso Merciai <[email protected]> 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 based on the requested duty cycle: > > - Index 0 for LVDS -> CDIV7_DSIx_CLK (DUTY H/L=4/3, 4/7 duty cycle) > - Index 1 for DSI/DPAD -> CSDIV_2to16_PLLDSIx (symmetric 50% duty cycle) > > 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_info` structure > - The `renesas,r9a09g047-du` compatible string > > 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]> > --- > v1->v2: > - Instead of using clk-provider API to select the right parent clock, > based on the outputs. Just set the correct duty cycle based on the > output, this reflects at CPG lvl to select the right parent. > - Updated commit message accordingly. > > v2->v3: > - No changes. > > v3->v4: > - No changes. > > drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c | 48 +++++++++++++++++++ > drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.c | 26 ++++++++++ > drivers/gpu/drm/renesas/rz-du/rzg2l_du_drv.h | 11 +++++ > 3 files changed, 85 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..c51ba4b8c383 100644 > --- a/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c > +++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_du_crtc.c > @@ -64,11 +64,32 @@ > 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 *clk_parent; > + > + clk_parent = clk_get_parent(rcrtc->rzg2l_clocks.dclk); > + > + /* > + * Request appropriate duty cycle to let clock driver select > + * the correct parent: > + * - CDIV7_DSIx_CLK (LVDS path) has DUTY H/L=4/3, 4/7 duty > cycle. > + * - CSDIV_2to16_PLLDSIx (DSI/RGB path) has symmetric 50% > duty cycle. > + */ > + if (rstate->outputs == BIT(RZG2L_DU_OUTPUT_LVDS0) || > + rstate->outputs == BIT(RZG2L_DU_OUTPUT_LVDS1)) > + clk_set_duty_cycle(clk_parent, 4, 7); > + else > + clk_set_duty_cycle(clk_parent, 1, 2); > + } > + > clk_set_rate(rcrtc->rzg2l_clocks.dclk, mode_clock); > > ditr0 = (DU_DITR0_DEMD_HIGH > @@ -248,6 +269,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 +343,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, This change and adding rzg2l_du_crtc_atomic_check() can be a separate patch as the same changes are required for T2H and its not specific to G3E. > .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..84e6bf186f5d 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,29 @@ static const struct rzg2l_du_device_info > rzg2l_du_r9a07g044_info = { > } > }; > > +static const struct rzg2l_du_device_info rzg2l_du_r9a09g047_du_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, > + }, > + [RZG2L_DU_OUTPUT_DPAD0] = { > + .possible_outputs = BIT(0), > + .port = 3, > + }, > + }, > +}; > + > static const struct rzg2l_du_device_info rzg2l_du_r9a09g057_info = { > .channels_mask = BIT(0), > .routes = { > @@ -64,6 +87,7 @@ 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-du", .data = > &rzg2l_du_r9a09g047_du_info }, > { .compatible = "renesas,r9a09g057-du", .data = > &rzg2l_du_r9a09g057_info }, > { /* sentinel */ } > }; > @@ -74,6 +98,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; The member description needs adding. Cheers, Prabhakar > 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 > >
