Messages in this thread Patch in this message |  | | From | Tommaso Merciai <> | | Subject | [PATCH 14/22] drm: renesas: rz-du: Add RZ/G3E support | | Date | Wed, 26 Nov 2025 15:07:26 +0100 |
| |
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 <tommaso.merciai.xr@bp.renesas.com> --- 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); + } + 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
|  |