@@ -747,9 +747,8 @@ int rcar_du_crtc_atomic_modeset(struct drm_device *dev,
!crtc_state->active)
continue;
- /* Configure display timings and output routing. */
+ /* Configure display timings. */
rcar_du_crtc_set_display_timing(rcrtc);
- rcar_du_group_set_routing(rcrtc->group);
if (rcar_du_has(rcrtc->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
rcar_du_vsp_modeset(rcrtc);
@@ -95,7 +95,6 @@ struct rcar_du_device {
} props;
unsigned int dpad0_source;
- unsigned int dpad1_source;
unsigned int vspd1_sink;
};
@@ -46,6 +46,10 @@ void rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data)
rcar_du_write(rgrp->dev, rgrp->mmio_offset + reg, data);
}
+/* -----------------------------------------------------------------------------
+ * Static Group Setup
+ */
+
static void rcar_du_group_setup_pins(struct rcar_du_group *rgrp)
{
u32 defr6 = DEFR6_CODE;
@@ -59,37 +63,6 @@ static void rcar_du_group_setup_pins(struct rcar_du_group *rgrp)
rcar_du_group_write(rgrp, DEFR6, defr6);
}
-static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
-{
- struct rcar_du_device *rcdu = rgrp->dev;
- u32 defr8 = DEFR8_CODE;
-
- if (rcdu->info->gen < 3) {
- defr8 |= DEFR8_DEFE8;
-
- /*
- * On Gen2 the DEFR8 register for the first group also controls
- * RGB output routing to DPAD0 and VSPD1 routing to DU0/1/2 for
- * DU instances that support it.
- */
- if (rgrp->index == 0) {
- defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source);
- if (rgrp->dev->vspd1_sink == 2)
- defr8 |= DEFR8_VSCS;
- }
- } else {
- /*
- * On Gen3 VSPD routing can't be configured, and DPAD routing
- * is set in the group corresponding to the DPAD output (no Gen3
- * SoC has multiple DPAD sources belonging to separate groups).
- */
- if (rgrp->index == rcdu->dpad0_source / 2)
- defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source);
- }
-
- rcar_du_group_write(rgrp, DEFR8, defr8);
-}
-
static void rcar_du_group_setup_didsr(struct rcar_du_group *rgrp)
{
struct rcar_du_device *rcdu = rgrp->dev;
@@ -163,10 +136,8 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
(rgrp->cmms_mask & BIT(0) ? DEFR7_CMME0 : 0);
rcar_du_group_write(rgrp, DEFR7, defr7);
- if (rcdu->info->gen >= 2) {
- rcar_du_group_setup_defr8(rgrp);
+ if (rcdu->info->gen >= 2)
rcar_du_group_setup_didsr(rgrp);
- }
if (rcdu->info->gen >= 3)
rcar_du_group_write(rgrp, DEFR10, DEFR10_CODE | DEFR10_DEFE10);
@@ -184,6 +155,10 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
mutex_unlock(&rgrp->lock);
}
+/* -----------------------------------------------------------------------------
+ * Start & Stop
+ */
+
static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
{
struct rcar_du_device *rcdu = rgrp->dev;
@@ -239,26 +214,63 @@ void rcar_du_group_restart(struct rcar_du_group *rgrp)
__rcar_du_group_start_stop(rgrp, true);
}
+/* -----------------------------------------------------------------------------
+ * Input and Output Routing
+ */
+
+static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
+{
+ struct rcar_du_device *rcdu = rgrp->dev;
+ u32 defr8 = DEFR8_CODE;
+
+ if (rcdu->info->gen < 3) {
+ defr8 |= DEFR8_DEFE8;
+
+ /*
+ * On Gen2 the DEFR8 register for the first group also controls
+ * RGB output routing to DPAD0 and VSPD1 routing to DU0/1/2 for
+ * DU instances that support it.
+ */
+ if (rgrp->index == 0) {
+ defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source);
+ if (rgrp->dev->vspd1_sink == 2)
+ defr8 |= DEFR8_VSCS;
+ }
+ } else {
+ /*
+ * On Gen3 VSPD routing can't be configured, and DPAD routing
+ * is set in the group corresponding to the DPAD output (no Gen3
+ * SoC has multiple DPAD sources belonging to separate groups).
+ */
+ if (rgrp->index == rcdu->dpad0_source / 2)
+ defr8 |= DEFR8_DRGBS_DU(rcdu->dpad0_source);
+ }
+
+ rcar_du_group_write(rgrp, DEFR8, defr8);
+}
+
int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu)
{
struct rcar_du_group *rgrp;
struct rcar_du_crtc *crtc;
- unsigned int index;
int ret;
- if (rcdu->info->gen < 2)
+ /*
+ * Only Gen2 hardware has global routing not handled in the group that
+ * holds the corresponding CRTCs.
+ */
+ if (rcdu->info->gen != 2)
return 0;
/*
- * RGB output routing to DPAD0 and VSP1D routing to DU0/1/2 are
- * configured in the DEFR8 register of the first group on Gen2 and the
- * last group on Gen3. As this function can be called with the DU
- * channels of the corresponding CRTCs disabled, we need to enable the
- * group clock before accessing the register.
+ * RGB output routing to DPAD0 and VSPD1 routing to DU0/1/2 are
+ * configured in the DEFR8 register of the first group on Gen2. As this
+ * function can be called with the DU channels of the corresponding
+ * CRTCs disabled, we need to enable the group clock before accessing
+ * the register.
*/
- index = rcdu->info->gen < 3 ? 0 : DIV_ROUND_UP(rcdu->num_crtcs, 2) - 1;
- rgrp = &rcdu->groups[index];
- crtc = &rcdu->crtcs[index * 2];
+ rgrp = &rcdu->groups[0];
+ crtc = &rcdu->crtcs[0];
ret = clk_prepare_enable(crtc->clock);
if (ret < 0)
@@ -312,19 +324,33 @@ static void rcar_du_group_set_dpad_levels(struct rcar_du_group *rgrp)
rcar_du_group_write(rgrp, DOFLR, doflr);
}
-int rcar_du_group_set_routing(struct rcar_du_group *rgrp)
+static void rcar_du_group_set_routing(struct rcar_du_group *rgrp)
{
struct rcar_du_device *rcdu = rgrp->dev;
u32 dorcr = rcar_du_group_read(rgrp, DORCR);
+ bool sp1_to_pin2 = false;
dorcr &= ~(DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_MASK);
/*
- * Set the DPAD1 pins sources. Select CRTC 0 if explicitly requested and
- * CRTC 1 in all other cases to avoid cloning CRTC 0 to DPAD0 and DPAD1
- * by default.
+ * Configure the superposition processor to pin controller routing.
+ * Hardcode the assignment, except on Gen1 where we use it to route the
+ * DU channels to DPAD1. There we route CRTC 0 to DPAD1 if explicitly
+ * requested, and CRTC 1 in all other cases to avoid cloning CRTC 0 to
+ * DPAD0 and DPAD1 by default.
*/
- if (rcdu->dpad1_source == rgrp->index * 2)
+ if (rcdu->info->gen == 1 && rgrp->index == 0) {
+ struct rcar_du_crtc_state *rstate;
+ struct rcar_du_crtc *rcrtc;
+
+ rcrtc = &rcdu->crtcs[0];
+ rstate = to_rcar_crtc_state(rcrtc->crtc.state);
+
+ if (rstate->outputs & BIT(RCAR_DU_OUTPUT_DPAD1))
+ sp1_to_pin2 = true;
+ }
+
+ if (sp1_to_pin2)
dorcr |= DORCR_PG2D_DS1;
else
dorcr |= DORCR_PG2T | DORCR_DK2S | DORCR_PG2D_DS2;
@@ -333,7 +359,7 @@ int rcar_du_group_set_routing(struct rcar_du_group *rgrp)
rcar_du_group_set_dpad_levels(rgrp);
- return rcar_du_set_dpad0_vsp1_routing(rgrp->dev);
+ rcar_du_group_setup_defr8(rgrp);
}
/* -----------------------------------------------------------------------------
@@ -451,20 +477,36 @@ rcar_du_get_new_group_state(struct drm_atomic_state *state,
int rcar_du_group_atomic_check(struct drm_device *dev,
struct drm_atomic_state *state)
{
- struct drm_crtc_state *crtc_state;
+ static const u32 dpad_mask = BIT(RCAR_DU_OUTPUT_DPAD1)
+ | BIT(RCAR_DU_OUTPUT_DPAD0);
+ struct drm_crtc_state *old_crtc_state;
+ struct drm_crtc_state *new_crtc_state;
struct drm_crtc *crtc;
unsigned int i;
- for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+ struct rcar_du_crtc_state *old_rcrtc_state;
+ struct rcar_du_crtc_state *new_rcrtc_state;
struct rcar_du_group_state *gstate;
gstate = rcar_du_get_group_state(state, rcrtc->group);
if (IS_ERR(gstate))
return PTR_ERR(gstate);
- if (crtc_state->active)
+ if (new_crtc_state->active)
gstate->enabled = true;
+
+ if (!new_crtc_state->active_changed &&
+ !new_crtc_state->connectors_changed)
+ continue;
+
+ old_rcrtc_state = to_rcar_crtc_state(old_crtc_state);
+ new_rcrtc_state = to_rcar_crtc_state(new_crtc_state);
+
+ if ((old_rcrtc_state->outputs & dpad_mask) !=
+ (new_rcrtc_state->outputs & dpad_mask))
+ gstate->dpad_routing_changed = true;
}
return 0;
@@ -484,8 +526,14 @@ void rcar_du_group_atomic_setup(struct drm_device *dev,
old_state = to_rcar_group_state(old_pstate);
new_state = to_rcar_group_state(new_pstate);
- if (!old_state->enabled && new_state->enabled)
+ if (!new_state->enabled)
+ continue;
+
+ if (!old_state->enabled)
rcar_du_group_setup(rgrp);
+
+ if (!old_state->enabled || new_state->dpad_routing_changed)
+ rcar_du_group_set_routing(rgrp);
}
}
@@ -60,11 +60,13 @@ struct rcar_du_group {
* struct rcar_du_group_state - Driver-specific group state
* @state: base DRM private state
* @enabled: true if at least one CRTC in the group is enabled
+ * @dpad_routing_changed: set if CRTC to DPAD output routing has changed
*/
struct rcar_du_group_state {
struct drm_private_state state;
bool enabled;
+ bool dpad_routing_changed;
};
#define to_rcar_group_state(s) \
@@ -75,7 +77,6 @@ void rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data);
void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start);
void rcar_du_group_restart(struct rcar_du_group *rgrp);
-int rcar_du_group_set_routing(struct rcar_du_group *rgrp);
int rcar_du_set_dpad0_vsp1_routing(struct rcar_du_device *rcdu);
@@ -446,14 +446,14 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
struct rcar_du_device *rcdu = to_rcar_du_device(dev);
struct drm_crtc_state *crtc_state;
struct drm_crtc *crtc;
+ unsigned int vspd1_sink = rcdu->vspd1_sink;
+ unsigned int dpad0_source = rcdu->dpad0_source;
unsigned int i;
/*
- * Store RGB routing to DPAD0 and DPAD1, the hardware will be configured
- * when starting the CRTCs.
+ * Store RGB routing to DPAD0, the hardware will be configured when
+ * setting up the groups.
*/
- rcdu->dpad1_source = -1;
-
for_each_new_crtc_in_state(old_state, crtc, crtc_state, i) {
struct rcar_du_crtc_state *rcrtc_state =
to_rcar_crtc_state(crtc_state);
@@ -461,9 +461,6 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD0))
rcdu->dpad0_source = rcrtc->index;
-
- if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD1))
- rcdu->dpad1_source = rcrtc->index;
}
/* Apply the atomic update. */
@@ -474,6 +471,11 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
rcar_du_crtc_atomic_modeset(dev, old_state);
drm_atomic_helper_commit_planes(dev, old_state,
DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+ if (rcdu->vspd1_sink != vspd1_sink ||
+ rcdu->dpad0_source != dpad0_source)
+ rcar_du_set_dpad0_vsp1_routing(rcdu);
+
drm_atomic_helper_commit_modeset_enables(dev, old_state);
rcar_du_crtc_atomic_enter_standby(dev, old_state);
@@ -552,14 +552,8 @@ void __rcar_du_plane_setup(struct rcar_du_group *rgrp,
if (rcdu->info->gen < 3)
rcar_du_plane_setup_scanout(rgrp, state);
- if (state->source == RCAR_DU_PLANE_VSPD1) {
- unsigned int vspd1_sink = rgrp->index ? 2 : 0;
-
- if (rcdu->vspd1_sink != vspd1_sink) {
- rcdu->vspd1_sink = vspd1_sink;
- rcar_du_set_dpad0_vsp1_routing(rcdu);
- }
- }
+ if (state->source == RCAR_DU_PLANE_VSPD1)
+ rcdu->vspd1_sink = rgrp->index ? 2 : 0;
}
int __rcar_du_plane_atomic_check(struct drm_plane *plane,