@@ -212,6 +212,8 @@ static const struct soc_device_attribute rcar_du_r8a7795_es1[] = {
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
{
+ const struct rcar_du_crtc_state *state =
+ to_rcar_crtc_state(rcrtc->crtc.state);
const struct drm_display_mode *mode = &rcrtc->crtc.state->adjusted_mode;
struct rcar_du_device *rcdu = rcrtc->dev;
unsigned long mode_clock = mode->clock * 1000;
@@ -286,6 +288,9 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
escr = params.escr;
}
+ if (state->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
+ escr |= ESCR_DCLKOINV;
+
dev_dbg(rcrtc->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr);
rcar_du_crtc_write(rcrtc, rcrtc->index % 2 ? ESCR13 : ESCR02, escr);
@@ -684,6 +689,8 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
static int rcar_du_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state)
{
+ const unsigned int bus_flags_mask = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE
+ | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
struct rcar_du_crtc_state *rstate = to_rcar_crtc_state(state);
struct drm_connector_state *conn_state;
struct drm_connector *connector;
@@ -694,11 +701,15 @@ static int rcar_du_crtc_atomic_check(struct drm_crtc *crtc,
if (ret)
return ret;
- /* Store the routes from the CRTC output to the DU outputs. */
+ /*
+ * Store the routes from the CRTC output to the DU outputs and validate
+ * the bus flags.
+ */
rstate->outputs = 0;
for_each_new_connector_in_state(state->state, connector, conn_state, i) {
struct drm_encoder *encoder = conn_state->best_encoder;
+ struct drm_bridge *bridge;
if (!encoder)
continue;
@@ -708,8 +719,22 @@ static int rcar_du_crtc_atomic_check(struct drm_crtc *crtc,
continue;
rstate->outputs |= BIT(to_rcar_encoder(encoder)->output);
+
+ bridge = drm_bridge_chain_get_first_bridge(encoder);
+
+ if (bridge && bridge->timings)
+ rstate->bus_flags |= bridge->timings->input_bus_flags;
+ else
+ rstate->bus_flags |= connector->display_info.bus_flags;
}
+ /*
+ * If multiple connectors require different clock edges the
+ * configuration is invalid.
+ */
+ if (rstate->bus_flags == bus_flags_mask)
+ return -EINVAL;
+
return 0;
}
@@ -944,6 +969,8 @@ rcar_du_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
__drm_atomic_helper_crtc_duplicate_state(crtc, ©->state);
+ copy->bus_flags = 0;
+
return ©->state;
}
@@ -979,6 +1006,8 @@ static void rcar_du_crtc_reset(struct drm_crtc *crtc)
state->crc.source = VSP1_DU_CRC_NONE;
state->crc.index = 0;
+ state->bus_flags = 0;
+
crtc->state = &state->state;
crtc->state->crtc = crtc;
}
@@ -83,12 +83,14 @@ struct rcar_du_crtc {
* @state: base DRM CRTC state
* @crc: CRC computation configuration
* @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC
+ * @bus_flags: signal polarities for the CRTC output bus (DRM_BUS_FLAG_*)
*/
struct rcar_du_crtc_state {
struct drm_crtc_state state;
struct vsp1_du_crc_config crc;
unsigned int outputs;
+ unsigned int bus_flags;
};
#define to_rcar_crtc_state(s) container_of(s, struct rcar_du_crtc_state, state)
The R-Car DU supports inverting the polarity of the output pixel clock. At the moment the driver hardcodes the clock polarity to drive signals on the rising edge of the clock. Configure it instead based on the needs of the display pipeline. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 31 +++++++++++++++++++++++++- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 ++ 2 files changed, 32 insertions(+), 1 deletion(-)