@@ -70,39 +70,6 @@ static void rcar_du_crtc_clr_set(struct rcar_du_crtc *rcrtc, u32 reg,
rcar_du_write(rcdu, rcrtc->mmio_offset + reg, (value & ~clr) | set);
}
-static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
-{
- int ret;
-
- ret = clk_prepare_enable(rcrtc->clock);
- if (ret < 0)
- return ret;
-
- ret = clk_prepare_enable(rcrtc->extclock);
- if (ret < 0)
- goto error_clock;
-
- ret = rcar_du_group_get(rcrtc->group);
- if (ret < 0)
- goto error_group;
-
- return 0;
-
-error_group:
- clk_disable_unprepare(rcrtc->extclock);
-error_clock:
- clk_disable_unprepare(rcrtc->clock);
- return ret;
-}
-
-static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
-{
- rcar_du_group_put(rcrtc->group);
-
- clk_disable_unprepare(rcrtc->extclock);
- clk_disable_unprepare(rcrtc->clock);
-}
-
/* -----------------------------------------------------------------------------
* Hardware Setup
*/
@@ -473,6 +440,49 @@ static void rcar_du_crtc_setup(struct rcar_du_crtc *rcrtc)
drm_crtc_vblank_on(&rcrtc->crtc);
}
+static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
+{
+ int ret;
+
+ /*
+ * Guard against double-get, as the function is called from both the
+ * .atomic_enable() and .atomic_begin() handlers.
+ */
+ if (rcrtc->initialized)
+ return 0;
+
+ ret = clk_prepare_enable(rcrtc->clock);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare_enable(rcrtc->extclock);
+ if (ret < 0)
+ goto error_clock;
+
+ ret = rcar_du_group_get(rcrtc->group);
+ if (ret < 0)
+ goto error_group;
+
+ rcar_du_crtc_setup(rcrtc);
+ rcrtc->initialized = true;
+
+ return 0;
+
+error_group:
+ clk_disable_unprepare(rcrtc->extclock);
+error_clock:
+ clk_disable_unprepare(rcrtc->clock);
+ return ret;
+}
+
+static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
+{
+ rcar_du_group_put(rcrtc->group);
+
+ clk_disable_unprepare(rcrtc->extclock);
+ clk_disable_unprepare(rcrtc->clock);
+}
+
static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
{
bool interlaced;
@@ -546,7 +556,6 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
return;
rcar_du_crtc_get(rcrtc);
- rcar_du_crtc_setup(rcrtc);
/* Commit the planes state. */
if (!rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE)) {
@@ -573,16 +582,7 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc,
{
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
- /*
- * If the CRTC has already been setup by the .atomic_begin() handler we
- * can skip the setup stage.
- */
- if (!rcrtc->initialized) {
- rcar_du_crtc_get(rcrtc);
- rcar_du_crtc_setup(rcrtc);
- rcrtc->initialized = true;
- }
-
+ rcar_du_crtc_get(rcrtc);
rcar_du_crtc_start(rcrtc);
}
@@ -614,14 +614,17 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc,
/*
* If a mode set is in progress we can be called with the CRTC disabled.
- * We then need to first setup the CRTC in order to configure planes.
- * The .atomic_enable() handler will notice and skip the CRTC setup.
+ * We thus need to first get and setup the CRTC in order to configure
+ * planes. We must *not* put the CRTC in .atomic_flush(), as it must be
+ * kept awake until the .atomic_enable() call that will follow. The get
+ * operation in .atomic_enable() will in that case be a no-op, and the
+ * CRTC will be put later in .atomic_disable().
+ *
+ * If a mode set is not in progress the CRTC is enabled, and the
+ * following get call will be a no-op. There is thus no need to belance
+ * it in .atomic_flush() either.
*/
- if (!rcrtc->initialized) {
- rcar_du_crtc_get(rcrtc);
- rcar_du_crtc_setup(rcrtc);
- rcrtc->initialized = true;
- }
+ rcar_du_crtc_get(rcrtc);
if (rcar_du_has(rcrtc->group->dev, RCAR_DU_FEATURE_VSP1_SOURCE))
rcar_du_vsp_atomic_begin(rcrtc);