LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH v3 01/10] drm: Add atomic variants of enable/disable to encoder helper funcs
       [not found] <20190502194956.218441-1-sean@poorly.run>
@ 2019-05-02 19:49 ` Sean Paul
  2019-05-03  7:51   ` Daniel Vetter
  2019-05-02 19:49 ` [PATCH v3 02/10] drm: Add drm_atomic_crtc_state_for_encoder helper Sean Paul
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 29+ messages in thread
From: Sean Paul @ 2019-05-02 19:49 UTC (permalink / raw)
  To: dri-devel
  Cc: Sean Paul, Daniel Vetter, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, Sean Paul, David Airlie,
	linux-kernel

From: Sean Paul <seanpaul@chromium.org>

This patch adds atomic_enable and atomic_disable callbacks to the
encoder helpers. This will allow encoders to make informed decisions in
their start-up/shutdown based on the committed state.

Aside from the new hooks, this patch also introduces the new signature
for .atomic_* functions going forward. Instead of passing object state
(well, encoders don't have atomic state, but let's ignore that), we pass
the entire atomic state so the driver can inspect more than what's
happening locally.

This is particularly important for the upcoming self refresh helpers.

Changes in v3:
- Added patch to the set

Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 drivers/gpu/drm/drm_atomic_helper.c      |  6 +++-
 include/drm/drm_modeset_helper_vtables.h | 45 ++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 553415fe8ede..71cc7d6b0644 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -1001,6 +1001,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 		if (funcs) {
 			if (new_conn_state->crtc && funcs->prepare)
 				funcs->prepare(encoder);
+			else if (funcs->atomic_disable)
+				funcs->atomic_disable(encoder, old_state);
 			else if (funcs->disable)
 				funcs->disable(encoder);
 			else if (funcs->dpms)
@@ -1309,7 +1311,9 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 		drm_bridge_pre_enable(encoder->bridge);
 
 		if (funcs) {
-			if (funcs->enable)
+			if (funcs->atomic_enable)
+				funcs->atomic_enable(encoder, old_state);
+			else if (funcs->enable)
 				funcs->enable(encoder);
 			else if (funcs->commit)
 				funcs->commit(encoder);
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index 8f3602811eb5..de57fb40cb6e 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -675,6 +675,51 @@ struct drm_encoder_helper_funcs {
 	enum drm_connector_status (*detect)(struct drm_encoder *encoder,
 					    struct drm_connector *connector);
 
+	/**
+	 * @atomic_disable:
+	 *
+	 * This callback should be used to disable the encoder. With the atomic
+	 * drivers it is called before this encoder's CRTC has been shut off
+	 * using their own &drm_crtc_helper_funcs.atomic_disable hook. If that
+	 * sequence is too simple drivers can just add their own driver private
+	 * encoder hooks and call them from CRTC's callback by looping over all
+	 * encoders connected to it using for_each_encoder_on_crtc().
+	 *
+	 * This callback is a variant of @disable that provides the atomic state
+	 * to the driver. It takes priority over @disable during atomic commits.
+	 *
+	 * This hook is used only by atomic helpers. Atomic drivers don't need
+	 * to implement it if there's no need to disable anything at the encoder
+	 * level. To ensure that runtime PM handling (using either DPMS or the
+	 * new "ACTIVE" property) works @atomic_disable must be the inverse of
+	 * @atomic_enable.
+	 */
+	void (*atomic_disable)(struct drm_encoder *encoder,
+			       struct drm_atomic_state *state);
+
+	/**
+	 * @atomic_enable:
+	 *
+	 * This callback should be used to enable the encoder. It is called
+	 * after this encoder's CRTC has been enabled using their own
+	 * &drm_crtc_helper_funcs.atomic_enable hook. If that sequence is
+	 * too simple drivers can just add their own driver private encoder
+	 * hooks and call them from CRTC's callback by looping over all encoders
+	 * connected to it using for_each_encoder_on_crtc().
+	 *
+	 * This callback is a variant of @enable that provides the atomic state
+	 * to the driver. It is called in place of @enable during atomic
+	 * commits.
+	 *
+	 * This hook is used only by atomic helpers, for symmetry with @disable.
+	 * Atomic drivers don't need to implement it if there's no need to
+	 * enable anything at the encoder level. To ensure that runtime PM
+	 * handling (using either DPMS or the new "ACTIVE" property) works
+	 * @enable must be the inverse of @disable for atomic drivers.
+	 */
+	void (*atomic_enable)(struct drm_encoder *encoder,
+			      struct drm_atomic_state *state);
+
 	/**
 	 * @disable:
 	 *
-- 
Sean Paul, Software Engineer, Google / Chromium OS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 02/10] drm: Add drm_atomic_crtc_state_for_encoder helper
       [not found] <20190502194956.218441-1-sean@poorly.run>
  2019-05-02 19:49 ` [PATCH v3 01/10] drm: Add atomic variants of enable/disable to encoder helper funcs Sean Paul
@ 2019-05-02 19:49 ` Sean Paul
  2019-05-03  8:18   ` Daniel Vetter
  2019-05-02 19:49 ` [PATCH v3 03/10] drm: Add atomic variants for bridge enable/disable Sean Paul
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 29+ messages in thread
From: Sean Paul @ 2019-05-02 19:49 UTC (permalink / raw)
  To: dri-devel
  Cc: Sean Paul, Daniel Vetter, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, Sean Paul, David Airlie,
	linux-kernel

From: Sean Paul <seanpaul@chromium.org>

This patch adds a helper to tease out the currently connected crtc for
an encoder, along with its state. This follows the same pattern as the
drm_atomic_crtc_*_for_* macros in the atomic helpers. Since the
relationship of crtc:encoder is 1:n, we don't need a loop since there is
only one crtc per encoder.

Instead of splitting this into 3 functions which all do the same thing,
this is presented as one function. Perhaps that's too ugly and it should
be split to:
struct drm_crtc *drm_atomic_crtc_for_encoder(state, encoder);
struct drm_crtc_state *drm_atomic_new_crtc_state_for_encoder(state, encoder);
struct drm_crtc_state *drm_atomic_old_crtc_state_for_encoder(state, encoder);

Suggestions welcome.

Changes in v3:
- Added to the set

Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 drivers/gpu/drm/drm_atomic_helper.c | 48 +++++++++++++++++++++++++++++
 include/drm/drm_atomic_helper.h     |  6 ++++
 2 files changed, 54 insertions(+)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 71cc7d6b0644..1f81ca8daad7 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -3591,3 +3591,51 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
 	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
+
+/**
+ * drm_atomic_crtc_state_for_encoder - Get crtc and new/old state for an encoder
+ * @state: Atomic state
+ * @encoder: The encoder to fetch the crtc information for
+ * @crtc: If not NULL, receives the currently connected crtc
+ * @old_crtc_state: If not NULL, receives the crtc's old state
+ * @new_crtc_state: If not NULL, receives the crtc's new state
+ *
+ * This function finds the crtc which is currently connected to @encoder and
+ * returns it as well as its old and new state. If there is no crtc currently
+ * connected, the function will clear @crtc, @old_crtc_state, @new_crtc_state.
+ *
+ * All of @crtc, @old_crtc_state, and @new_crtc_state are optional.
+ */
+void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
+				       struct drm_encoder *encoder,
+				       struct drm_crtc **crtc,
+				       struct drm_crtc_state **old_crtc_state,
+				       struct drm_crtc_state **new_crtc_state)
+{
+	struct drm_crtc *tmp_crtc;
+	struct drm_crtc_state *tmp_new_crtc_state, *tmp_old_crtc_state;
+	u32 enc_mask = drm_encoder_mask(encoder);
+	int i;
+
+	for_each_oldnew_crtc_in_state(state, tmp_crtc, tmp_old_crtc_state,
+				      tmp_new_crtc_state, i) {
+		if (!(tmp_new_crtc_state->encoder_mask & enc_mask))
+			continue;
+
+		if (new_crtc_state)
+			*new_crtc_state = tmp_new_crtc_state;
+		if (old_crtc_state)
+			*old_crtc_state = tmp_old_crtc_state;
+		if (crtc)
+			*crtc = tmp_crtc;
+		return;
+	}
+
+	if (new_crtc_state)
+		*new_crtc_state = NULL;
+	if (old_crtc_state)
+		*old_crtc_state = NULL;
+	if (crtc)
+		*crtc = NULL;
+}
+EXPORT_SYMBOL(drm_atomic_crtc_state_for_encoder);
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
index 58214be3bf3d..2383550a0cc8 100644
--- a/include/drm/drm_atomic_helper.h
+++ b/include/drm/drm_atomic_helper.h
@@ -153,6 +153,12 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
 				       uint32_t size,
 				       struct drm_modeset_acquire_ctx *ctx);
 
+void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
+				       struct drm_encoder *encoder,
+				       struct drm_crtc **crtc,
+				       struct drm_crtc_state **old_crtc_state,
+				       struct drm_crtc_state **new_crtc_state);
+
 /**
  * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
  * @plane: the loop cursor
-- 
Sean Paul, Software Engineer, Google / Chromium OS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 03/10] drm: Add atomic variants for bridge enable/disable
       [not found] <20190502194956.218441-1-sean@poorly.run>
  2019-05-02 19:49 ` [PATCH v3 01/10] drm: Add atomic variants of enable/disable to encoder helper funcs Sean Paul
  2019-05-02 19:49 ` [PATCH v3 02/10] drm: Add drm_atomic_crtc_state_for_encoder helper Sean Paul
@ 2019-05-02 19:49 ` Sean Paul
  2019-05-03  7:45   ` Daniel Vetter
  2019-05-02 19:49 ` [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state Sean Paul
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 29+ messages in thread
From: Sean Paul @ 2019-05-02 19:49 UTC (permalink / raw)
  To: dri-devel
  Cc: Sean Paul, Daniel Vetter, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, Sean Paul, David Airlie,
	linux-kernel

From: Sean Paul <seanpaul@chromium.org>

This patch adds atomic variants for all of
pre_enable/enable/disable/post_disable bridge functions. These will be
called from the appropriate atomic helper functions. If the bridge
driver doesn't implement the atomic version of the function, we will
fall back to the vanilla implementation.

Note that some drivers call drm_bridge_disable directly, and these cases
are not covered. It's up to the driver to decide whether to implement
both atomic_disable and disable, or if it's not necessary.

Changes in v3:
- Added to the patchset

Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 drivers/gpu/drm/drm_atomic_helper.c |   8 +-
 drivers/gpu/drm/drm_bridge.c        | 110 +++++++++++++++++++++++++++
 include/drm/drm_bridge.h            | 114 ++++++++++++++++++++++++++++
 3 files changed, 228 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 1f81ca8daad7..9d9e47276839 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -995,7 +995,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 		 * Each encoder has at most one connector (since we always steal
 		 * it away), so we won't call disable hooks twice.
 		 */
-		drm_bridge_disable(encoder->bridge);
+		drm_atomic_bridge_disable(encoder->bridge, old_state);
 
 		/* Right function depends upon target state. */
 		if (funcs) {
@@ -1009,7 +1009,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 				funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
 		}
 
-		drm_bridge_post_disable(encoder->bridge);
+		drm_atomic_bridge_post_disable(encoder->bridge, old_state);
 	}
 
 	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
@@ -1308,7 +1308,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 		 * Each encoder has at most one connector (since we always steal
 		 * it away), so we won't call enable hooks twice.
 		 */
-		drm_bridge_pre_enable(encoder->bridge);
+		drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
 
 		if (funcs) {
 			if (funcs->atomic_enable)
@@ -1319,7 +1319,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
 				funcs->commit(encoder);
 		}
 
-		drm_bridge_enable(encoder->bridge);
+		drm_atomic_bridge_enable(encoder->bridge, old_state);
 	}
 
 	drm_atomic_helper_commit_writebacks(dev, old_state);
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 138b2711d389..accccb586adf 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -352,6 +352,116 @@ void drm_bridge_enable(struct drm_bridge *bridge)
 }
 EXPORT_SYMBOL(drm_bridge_enable);
 
+/**
+ * drm_atomic_bridge_disable - disables all bridges in the encoder chain
+ * @bridge: bridge control structure
+ * @state: atomic state being committed
+ *
+ * Calls &drm_bridge_funcs.atomic_disable (falls back on
+ * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain,
+ * starting from the last bridge to the first. These are called before calling
+ * the encoder's prepare op.
+ *
+ * Note: the bridge passed should be the one closest to the encoder
+ */
+void drm_atomic_bridge_disable(struct drm_bridge *bridge,
+			       struct drm_atomic_state *state)
+{
+	if (!bridge)
+		return;
+
+	drm_atomic_bridge_disable(bridge->next, state);
+
+	if (bridge->funcs->atomic_disable)
+		bridge->funcs->atomic_disable(bridge, state);
+	else if (bridge->funcs->disable)
+		bridge->funcs->disable(bridge);
+}
+EXPORT_SYMBOL(drm_atomic_bridge_disable);
+
+/**
+ * drm_atomic_bridge_post_disable - cleans up after disabling all bridges in the
+ *				    encoder chain
+ * @bridge: bridge control structure
+ * @state: atomic state being committed
+ *
+ * Calls &drm_bridge_funcs.atomic_post_disable (falls back on
+ * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
+ * starting from the first bridge to the last. These are called after completing
+ * the encoder's prepare op.
+ *
+ * Note: the bridge passed should be the one closest to the encoder
+ */
+void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
+				    struct drm_atomic_state *state)
+{
+	if (!bridge)
+		return;
+
+	if (bridge->funcs->atomic_post_disable)
+		bridge->funcs->atomic_post_disable(bridge, state);
+	else if (bridge->funcs->post_disable)
+		bridge->funcs->post_disable(bridge);
+
+	drm_atomic_bridge_post_disable(bridge->next, state);
+}
+EXPORT_SYMBOL(drm_atomic_bridge_post_disable);
+
+/**
+ * drm_bridge_pre_enable - prepares for enabling all bridges in the encoder
+ *			   chain
+ * @bridge: bridge control structure
+ * @state: atomic state being committed
+ *
+ * Calls &drm_bridge_funcs.pre_enable (falls back on
+ * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain,
+ * starting from the last bridge to the first. These are called before calling
+ * the encoder's commit op.
+ *
+ * Note: the bridge passed should be the one closest to the encoder
+ */
+void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
+				  struct drm_atomic_state *state)
+{
+	if (!bridge)
+		return;
+
+	drm_atomic_bridge_pre_enable(bridge->next, state);
+
+	if (bridge->funcs->atomic_pre_enable)
+		bridge->funcs->atomic_pre_enable(bridge, state);
+	else if (bridge->funcs->pre_enable)
+		bridge->funcs->pre_enable(bridge);
+}
+EXPORT_SYMBOL(drm_atomic_bridge_pre_enable);
+
+/**
+ * drm_atomic_bridge_enable - enables all bridges in the encoder chain
+ * @bridge: bridge control structure
+ * @state: atomic state being committed
+ *
+ * Calls &drm_bridge_funcs.atomic_enable (falls back on
+ * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain,
+ * starting from the first bridge to the last. These are called after completing
+ * the encoder's commit op.
+ *
+ * Note: the bridge passed should be the one closest to the encoder
+ */
+void drm_atomic_bridge_enable(struct drm_bridge *bridge,
+			      struct drm_atomic_state *state)
+{
+	if (!bridge)
+		return;
+
+	if (bridge->funcs->atomic_enable)
+		bridge->funcs->atomic_enable(bridge, state);
+	else if (bridge->funcs->enable)
+		bridge->funcs->enable(bridge);
+
+	drm_atomic_bridge_enable(bridge->next, state);
+}
+EXPORT_SYMBOL(drm_atomic_bridge_enable);
+
 #ifdef CONFIG_OF
 /**
  * of_drm_find_bridge - find the bridge corresponding to the device node in
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index d4428913a4e1..86f436895c7b 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -237,6 +237,111 @@ struct drm_bridge_funcs {
 	 * The enable callback is optional.
 	 */
 	void (*enable)(struct drm_bridge *bridge);
+
+	/**
+	 * @atomic_pre_enable:
+	 *
+	 * This callback should enable the bridge. It is called right before
+	 * the preceding element in the display pipe is enabled. If the
+	 * preceding element is a bridge this means it's called before that
+	 * bridge's @atomic_pre_enable or @pre_enable function. If the preceding
+	 * element is a &drm_encoder it's called right before the encoder's
+	 * &drm_encoder_helper_funcs.atomic_enable,
+	 * &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or
+	 * &drm_encoder_helper_funcs.dpms hook.
+	 *
+	 * The display pipe (i.e. clocks and timing signals) feeding this bridge
+	 * will not yet be running when this callback is called. The bridge must
+	 * not enable the display link feeding the next bridge in the chain (if
+	 * there is one) when this callback is called.
+	 *
+	 * Note that this function will only be invoked in the context of an
+	 * atomic commit. It will not be invoked from &drm_bridge_pre_enable. It
+	 * would be prudent to also provide an implementation of @pre_enable if
+	 * you are expecting driver calls into &drm_bridge_pre_enable.
+	 *
+	 * The @atomic_pre_enable callback is optional.
+	 */
+	void (*atomic_pre_enable)(struct drm_bridge *bridge,
+				  struct drm_atomic_state *state);
+
+	/**
+	 * @atomic_enable:
+	 *
+	 * This callback should enable the bridge. It is called right after
+	 * the preceding element in the display pipe is enabled. If the
+	 * preceding element is a bridge this means it's called after that
+	 * bridge's @atomic_enable or @enable function. If the preceding element
+	 * is a &drm_encoder it's called right after the encoder's
+	 * &drm_encoder_helper_funcs.atomic_enable,
+	 * &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or
+	 * &drm_encoder_helper_funcs.dpms hook.
+	 *
+	 * The bridge can assume that the display pipe (i.e. clocks and timing
+	 * signals) feeding it is running when this callback is called. This
+	 * callback must enable the display link feeding the next bridge in the
+	 * chain if there is one.
+	 *
+	 * Note that this function will only be invoked in the context of an
+	 * atomic commit. It will not be invoked from &drm_bridge_enable. It
+	 * would be prudent to also provide an implementation of @enable if
+	 * you are expecting driver calls into &drm_bridge_enable.
+	 *
+	 * The enable callback is optional.
+	 */
+	void (*atomic_enable)(struct drm_bridge *bridge,
+			      struct drm_atomic_state *state);
+	/**
+	 * @atomic_disable:
+	 *
+	 * This callback should disable the bridge. It is called right before
+	 * the preceding element in the display pipe is disabled. If the
+	 * preceding element is a bridge this means it's called before that
+	 * bridge's @atomic_disable or @disable vfunc. If the preceding element
+	 * is a &drm_encoder it's called right before the
+	 * &drm_encoder_helper_funcs.atomic_disable,
+	 * &drm_encoder_helper_funcs.disable, &drm_encoder_helper_funcs.prepare
+	 * or &drm_encoder_helper_funcs.dpms hook.
+	 *
+	 * The bridge can assume that the display pipe (i.e. clocks and timing
+	 * signals) feeding it is still running when this callback is called.
+	 *
+	 * Note that this function will only be invoked in the context of an
+	 * atomic commit. It will not be invoked from &drm_bridge_disable. It
+	 * would be prudent to also provide an implementation of @disable if
+	 * you are expecting driver calls into &drm_bridge_disable.
+	 *
+	 * The disable callback is optional.
+	 */
+	void (*atomic_disable)(struct drm_bridge *bridge,
+			       struct drm_atomic_state *state);
+
+	/**
+	 * @atomic_post_disable:
+	 *
+	 * This callback should disable the bridge. It is called right after the
+	 * preceding element in the display pipe is disabled. If the preceding
+	 * element is a bridge this means it's called after that bridge's
+	 * @atomic_post_disable or @post_disable function. If the preceding
+	 * element is a &drm_encoder it's called right after the encoder's
+	 * &drm_encoder_helper_funcs.atomic_disable,
+	 * &drm_encoder_helper_funcs.disable, &drm_encoder_helper_funcs.prepare
+	 * or &drm_encoder_helper_funcs.dpms hook.
+	 *
+	 * The bridge must assume that the display pipe (i.e. clocks and timing
+	 * singals) feeding it is no longer running when this callback is
+	 * called.
+	 *
+	 * Note that this function will only be invoked in the context of an
+	 * atomic commit. It will not be invoked from &drm_bridge_post_disable.
+	 * It would be prudent to also provide an implementation of
+	 * @post_disable if you are expecting driver calls into
+	 * &drm_bridge_post_disable.
+	 *
+	 * The post_disable callback is optional.
+	 */
+	void (*atomic_post_disable)(struct drm_bridge *bridge,
+				    struct drm_atomic_state *state);
 };
 
 /**
@@ -314,6 +419,15 @@ void drm_bridge_mode_set(struct drm_bridge *bridge,
 void drm_bridge_pre_enable(struct drm_bridge *bridge);
 void drm_bridge_enable(struct drm_bridge *bridge);
 
+void drm_atomic_bridge_disable(struct drm_bridge *bridge,
+			       struct drm_atomic_state *state);
+void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
+				    struct drm_atomic_state *state);
+void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
+				  struct drm_atomic_state *state);
+void drm_atomic_bridge_enable(struct drm_bridge *bridge,
+			      struct drm_atomic_state *state);
+
 #ifdef CONFIG_DRM_PANEL_BRIDGE
 struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
 					u32 connector_type);
-- 
Sean Paul, Software Engineer, Google / Chromium OS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state
       [not found] <20190502194956.218441-1-sean@poorly.run>
                   ` (2 preceding siblings ...)
  2019-05-02 19:49 ` [PATCH v3 03/10] drm: Add atomic variants for bridge enable/disable Sean Paul
@ 2019-05-02 19:49 ` Sean Paul
  2019-05-03  8:19   ` Daniel Vetter
  2019-05-11 19:12   ` Laurent Pinchart
  2019-05-02 19:49 ` [PATCH v3 05/10] drm: Add helpers to kick off self refresh mode in drivers Sean Paul
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 29+ messages in thread
From: Sean Paul @ 2019-05-02 19:49 UTC (permalink / raw)
  To: dri-devel
  Cc: Sean Paul, Daniel Vetter, Ville Syrjälä,
	Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs,
	Laurent Pinchart, Kieran Bingham, Eric Anholt, Maarten Lankhorst,
	Maxime Ripard, Sean Paul, David Airlie, linux-kernel, intel-gfx,
	nouveau, linux-renesas-soc

From: Sean Paul <seanpaul@chromium.org>

Everyone who implements connector_helper_funcs->atomic_check reaches
into the connector state to get the atomic state. Instead of continuing
this pattern, change the callback signature to just give atomic state
and let the driver determine what it does and does not need from it.

Eventually all atomic functions should do this, but that's just too much
busy work for me.

Changes in v3:
- Added to the set

Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: Jani Nikula <jani.nikula@linux.intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Ben Skeggs <bskeggs@redhat.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Cc: Eric Anholt <eric@anholt.net>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 drivers/gpu/drm/drm_atomic_helper.c      |  4 ++--
 drivers/gpu/drm/i915/intel_atomic.c      |  8 +++++---
 drivers/gpu/drm/i915/intel_dp_mst.c      |  7 ++++---
 drivers/gpu/drm/i915/intel_drv.h         |  2 +-
 drivers/gpu/drm/i915/intel_sdvo.c        |  9 +++++----
 drivers/gpu/drm/i915/intel_tv.c          |  8 +++++---
 drivers/gpu/drm/nouveau/dispnv50/disp.c  |  5 +++--
 drivers/gpu/drm/rcar-du/rcar_lvds.c      | 12 +++++++-----
 drivers/gpu/drm/vc4/vc4_txp.c            |  7 ++++---
 include/drm/drm_modeset_helper_vtables.h |  2 +-
 10 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 9d9e47276839..fa5a367507c1 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -683,7 +683,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
 		}
 
 		if (funcs->atomic_check)
-			ret = funcs->atomic_check(connector, new_connector_state);
+			ret = funcs->atomic_check(connector, state);
 		if (ret)
 			return ret;
 
@@ -725,7 +725,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
 			continue;
 
 		if (funcs->atomic_check)
-			ret = funcs->atomic_check(connector, new_connector_state);
+			ret = funcs->atomic_check(connector, state);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index b844e8840c6f..e8a5b82e9242 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -103,12 +103,14 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
 }
 
 int intel_digital_connector_atomic_check(struct drm_connector *conn,
-					 struct drm_connector_state *new_state)
+					 struct drm_atomic_state *state)
 {
+	struct drm_connector_state *new_state =
+		drm_atomic_get_new_connector_state(state, conn);
 	struct intel_digital_connector_state *new_conn_state =
 		to_intel_digital_connector_state(new_state);
 	struct drm_connector_state *old_state =
-		drm_atomic_get_old_connector_state(new_state->state, conn);
+		drm_atomic_get_old_connector_state(state, conn);
 	struct intel_digital_connector_state *old_conn_state =
 		to_intel_digital_connector_state(old_state);
 	struct drm_crtc_state *crtc_state;
@@ -118,7 +120,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
 	if (!new_state->crtc)
 		return 0;
 
-	crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
+	crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
 
 	/*
 	 * These properties are handled by fastset, and might not end
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 19d81cef2ab6..89cfec128ba0 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -143,9 +143,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
 
 static int
 intel_dp_mst_atomic_check(struct drm_connector *connector,
-			  struct drm_connector_state *new_conn_state)
+			  struct drm_atomic_state *state)
 {
-	struct drm_atomic_state *state = new_conn_state->state;
+	struct drm_connector_state *new_conn_state =
+		drm_atomic_get_new_connector_state(state, connector);
 	struct drm_connector_state *old_conn_state =
 		drm_atomic_get_old_connector_state(state, connector);
 	struct intel_connector *intel_connector =
@@ -155,7 +156,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
 	struct drm_dp_mst_topology_mgr *mgr;
 	int ret;
 
-	ret = intel_digital_connector_atomic_check(connector, new_conn_state);
+	ret = intel_digital_connector_atomic_check(connector, state);
 	if (ret)
 		return ret;
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index f8c7b291fdc3..88571b8e8d62 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -2481,7 +2481,7 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
 						struct drm_property *property,
 						u64 val);
 int intel_digital_connector_atomic_check(struct drm_connector *conn,
-					 struct drm_connector_state *new_state);
+					 struct drm_atomic_state *state);
 struct drm_connector_state *
 intel_digital_connector_duplicate_state(struct drm_connector *connector);
 
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 68f497493d43..72ea164b971c 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2342,9 +2342,10 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
 };
 
 static int intel_sdvo_atomic_check(struct drm_connector *conn,
-				   struct drm_connector_state *new_conn_state)
+				   struct drm_atomic_state *state)
 {
-	struct drm_atomic_state *state = new_conn_state->state;
+	struct drm_connector_state *new_conn_state =
+		drm_atomic_get_new_connector_state(state, conn);
 	struct drm_connector_state *old_conn_state =
 		drm_atomic_get_old_connector_state(state, conn);
 	struct intel_sdvo_connector_state *old_state =
@@ -2356,13 +2357,13 @@ static int intel_sdvo_atomic_check(struct drm_connector *conn,
 	    (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
 	     memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
 		struct drm_crtc_state *crtc_state =
-			drm_atomic_get_new_crtc_state(new_conn_state->state,
+			drm_atomic_get_new_crtc_state(state,
 						      new_conn_state->crtc);
 
 		crtc_state->connectors_changed = true;
 	}
 
-	return intel_digital_connector_atomic_check(conn, new_conn_state);
+	return intel_digital_connector_atomic_check(conn, state);
 }
 
 static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 3924c4944e1f..a41c5b467c14 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1817,16 +1817,18 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
 };
 
 static int intel_tv_atomic_check(struct drm_connector *connector,
-				 struct drm_connector_state *new_state)
+				 struct drm_atomic_state *state)
 {
+	struct drm_connector_state *new_state;
 	struct drm_crtc_state *new_crtc_state;
 	struct drm_connector_state *old_state;
 
+	new_state = drm_atomic_get_new_connector_state(state, connector);
 	if (!new_state->crtc)
 		return 0;
 
-	old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
-	new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
+	old_state = drm_atomic_get_old_connector_state(state, connector);
+	new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
 
 	if (old_state->tv.mode != new_state->tv.mode ||
 	    old_state->tv.margins.left != new_state->tv.margins.left ||
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 4b1650f51955..7ba373f493b2 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -948,11 +948,12 @@ nv50_mstc_get_modes(struct drm_connector *connector)
 
 static int
 nv50_mstc_atomic_check(struct drm_connector *connector,
-		       struct drm_connector_state *new_conn_state)
+		       struct drm_atomic_state *state)
 {
-	struct drm_atomic_state *state = new_conn_state->state;
 	struct nv50_mstc *mstc = nv50_mstc(connector);
 	struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr;
+	struct drm_connector_state *new_conn_state =
+		drm_atomic_get_new_connector_state(state, connector);
 	struct drm_connector_state *old_conn_state =
 		drm_atomic_get_old_connector_state(state, connector);
 	struct drm_crtc_state *crtc_state;
diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
index 620b51aab291..5b81ba2a7f27 100644
--- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
+++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
@@ -92,13 +92,15 @@ static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
 }
 
 static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
-					    struct drm_connector_state *state)
+					    struct drm_atomic_state *state)
 {
 	struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
 	const struct drm_display_mode *panel_mode;
+	struct drm_connector_state *conn_state;
 	struct drm_crtc_state *crtc_state;
 
-	if (!state->crtc)
+	conn_state = drm_atomic_get_new_connector_state(state, connector);
+	if (!conn_state->crtc)
 		return 0;
 
 	if (list_empty(&connector->modes)) {
@@ -110,9 +112,9 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
 				      struct drm_display_mode, head);
 
 	/* We're not allowed to modify the resolution. */
-	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
-	if (IS_ERR(crtc_state))
-		return PTR_ERR(crtc_state);
+	crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
+	if (!crtc_state)
+		return -EINVAL;
 
 	if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
 	    crtc_state->mode.vdisplay != panel_mode->vdisplay)
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
index c8b89a78f9f4..96f91c1b4b6e 100644
--- a/drivers/gpu/drm/vc4/vc4_txp.c
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
@@ -221,17 +221,18 @@ static const u32 txp_fmts[] = {
 };
 
 static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
-					struct drm_connector_state *conn_state)
+					  struct drm_atomic_state *state)
 {
+	struct drm_connector_state *conn_state;
 	struct drm_crtc_state *crtc_state;
 	struct drm_framebuffer *fb;
 	int i;
 
+	conn_state = drm_atomic_get_new_connector_state(state, conn);
 	if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
 		return 0;
 
-	crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
-						   conn_state->crtc);
+	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
 
 	fb = conn_state->writeback_job->fb;
 	if (fb->width != crtc_state->mode.hdisplay ||
diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
index de57fb40cb6e..adc8b7cf64b5 100644
--- a/include/drm/drm_modeset_helper_vtables.h
+++ b/include/drm/drm_modeset_helper_vtables.h
@@ -1020,7 +1020,7 @@ struct drm_connector_helper_funcs {
 	 * deadlock.
 	 */
 	int (*atomic_check)(struct drm_connector *connector,
-			    struct drm_connector_state *state);
+			    struct drm_atomic_state *state);
 
 	/**
 	 * @atomic_commit:
-- 
Sean Paul, Software Engineer, Google / Chromium OS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 05/10] drm: Add helpers to kick off self refresh mode in drivers
       [not found] <20190502194956.218441-1-sean@poorly.run>
                   ` (3 preceding siblings ...)
  2019-05-02 19:49 ` [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state Sean Paul
@ 2019-05-02 19:49 ` Sean Paul
  2019-05-03  7:36   ` Daniel Vetter
  2019-05-02 19:49 ` [PATCH v3 06/10] drm/rockchip: Use dirtyfb helper Sean Paul
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 29+ messages in thread
From: Sean Paul @ 2019-05-02 19:49 UTC (permalink / raw)
  To: dri-devel
  Cc: Sean Paul, Daniel Vetter, Jose Souza, Zain Wang, Tomasz Figa,
	Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, Sean Paul, David Airlie,
	Jonathan Corbet, linux-doc, linux-kernel

From: Sean Paul <seanpaul@chromium.org>

This patch adds a new drm helper library to help drivers implement
self refresh. Drivers choosing to use it will register crtcs and
will receive callbacks when it's time to enter or exit self refresh
mode.

In its current form, it has a timer which will trigger after a
driver-specified amount of inactivity. When the timer triggers, the
helpers will submit a new atomic commit to shut the refreshing pipe
off. On the next atomic commit, the drm core will revert the self
refresh state and bring everything back up to be actively driven.

From the driver's perspective, this works like a regular disable/enable
cycle. The driver need only check the 'self_refresh_active' state in
crtc_state. It should initiate self refresh mode on the panel and enter
an off or low-power state.

Changes in v2:
- s/psr/self_refresh/ (Daniel)
- integrated the psr exit into the commit that wakes it up (Jose/Daniel)
- made the psr state per-crtc (Jose/Daniel)
Changes in v3:
- Remove the self_refresh_(active|changed) from connector state (Daniel)
- Simplify loop in drm_self_refresh_helper_alter_state (Daniel)
- Improve self_refresh_aware comment (Daniel)
- s/self_refresh_state/self_refresh_data/ (Daniel)

Link to v1: https://patchwork.freedesktop.org/patch/msgid/20190228210939.83386-2-sean@poorly.run
Link to v2: https://patchwork.freedesktop.org/patch/msgid/20190326204509.96515-1-sean@poorly.run

Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Jose Souza <jose.souza@intel.com>
Cc: Zain Wang <wzz@rock-chips.com>
Cc: Tomasz Figa <tfiga@chromium.org>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 Documentation/gpu/drm-kms-helpers.rst     |   9 +
 drivers/gpu/drm/Makefile                  |   2 +-
 drivers/gpu/drm/drm_atomic.c              |   2 +
 drivers/gpu/drm/drm_atomic_helper.c       |  35 +++-
 drivers/gpu/drm/drm_atomic_state_helper.c |   4 +
 drivers/gpu/drm/drm_atomic_uapi.c         |   7 +-
 drivers/gpu/drm/drm_self_refresh_helper.c | 205 ++++++++++++++++++++++
 include/drm/drm_atomic.h                  |  15 ++
 include/drm/drm_connector.h               |  14 ++
 include/drm/drm_crtc.h                    |  19 ++
 include/drm/drm_self_refresh_helper.h     |  22 +++
 11 files changed, 329 insertions(+), 5 deletions(-)
 create mode 100644 drivers/gpu/drm/drm_self_refresh_helper.c
 create mode 100644 include/drm/drm_self_refresh_helper.h

diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
index 14102ae035dc..d8a13c6b4db3 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -113,6 +113,15 @@ format Helper Functions Reference
 .. kernel-doc:: drivers/gpu/drm/drm_format_helper.c
    :export:
 
+Panel Self Refresh Helper Reference
+===================================
+
+.. kernel-doc:: drivers/gpu/drm/drm_self_refresh_helper.c
+   :doc: overview
+
+.. kernel-doc:: drivers/gpu/drm/drm_self_refresh_helper.c
+   :export:
+
 Framebuffer CMA Helper Functions Reference
 ==========================================
 
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 3d0c75cd687c..c4852604fc1d 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -39,7 +39,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
 		drm_simple_kms_helper.o drm_modeset_helper.o \
 		drm_scdc_helper.o drm_gem_framebuffer_helper.o \
 		drm_atomic_state_helper.o drm_damage_helper.o \
-		drm_format_helper.o
+		drm_format_helper.o drm_self_refresh_helper.o
 
 drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
 drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 5eb40130fafb..4449956241f2 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -379,6 +379,7 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p,
 	drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name);
 	drm_printf(p, "\tenable=%d\n", state->enable);
 	drm_printf(p, "\tactive=%d\n", state->active);
+	drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active);
 	drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed);
 	drm_printf(p, "\tmode_changed=%d\n", state->mode_changed);
 	drm_printf(p, "\tactive_changed=%d\n", state->active_changed);
@@ -881,6 +882,7 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
 
 	drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name);
 	drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
+	drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware);
 
 	if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
 		if (state->writeback_job && state->writeback_job->fb)
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index fa5a367507c1..3c26f04cd6b8 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -30,6 +30,7 @@
 #include <drm/drm_atomic_uapi.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_self_refresh_helper.h>
 #include <drm/drm_writeback.h>
 #include <drm/drm_damage_helper.h>
 #include <linux/dma-fence.h>
@@ -950,10 +951,33 @@ int drm_atomic_helper_check(struct drm_device *dev,
 	if (state->legacy_cursor_update)
 		state->async_update = !drm_atomic_helper_async_check(dev, state);
 
+	drm_self_refresh_helper_alter_state(state);
+
 	return ret;
 }
 EXPORT_SYMBOL(drm_atomic_helper_check);
 
+static bool
+crtc_needs_disable(struct drm_crtc_state *old_state,
+		   struct drm_crtc_state *new_state)
+{
+	/*
+	 * No new_state means the crtc is off, so the only criteria is whether
+	 * it's currently active or in self refresh mode.
+	 */
+	if (!new_state)
+		return drm_atomic_crtc_effectively_active(old_state);
+
+	/*
+	 * We need to run through the crtc_funcs->disable() function if the crtc
+	 * is currently on, if it's transitioning to self refresh mode, or if
+	 * it's in self refresh mode and needs to be fully disabled.
+	 */
+	return old_state->active ||
+	       (old_state->self_refresh_active && !new_state->enable) ||
+	       new_state->self_refresh_active;
+}
+
 static void
 disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 {
@@ -974,7 +998,14 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 
 		old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc);
 
-		if (!old_crtc_state->active ||
+		if (new_conn_state->crtc)
+			new_crtc_state = drm_atomic_get_new_crtc_state(
+						old_state,
+						new_conn_state->crtc);
+		else
+			new_crtc_state = NULL;
+
+		if (!crtc_needs_disable(old_crtc_state, new_crtc_state) ||
 		    !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state))
 			continue;
 
@@ -1020,7 +1051,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
 			continue;
 
-		if (!old_crtc_state->active)
+		if (!crtc_needs_disable(old_crtc_state, new_crtc_state))
 			continue;
 
 		funcs = crtc->helper_private;
diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
index ac929f68ff31..ca18008043e5 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -128,6 +128,10 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
 	state->commit = NULL;
 	state->event = NULL;
 	state->pageflip_flags = 0;
+
+	/* Self refresh should be canceled when a new update is available */
+	state->active = drm_atomic_crtc_effectively_active(state);
+	state->self_refresh_active = false;
 }
 EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
 
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index ea797d4c82ee..a75c633ff0c0 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -490,7 +490,7 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
 	struct drm_mode_config *config = &dev->mode_config;
 
 	if (property == config->prop_active)
-		*val = state->active;
+		*val = drm_atomic_crtc_effectively_active(state);
 	else if (property == config->prop_mode_id)
 		*val = (state->mode_blob) ? state->mode_blob->base.id : 0;
 	else if (property == config->prop_vrr_enabled)
@@ -772,7 +772,10 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
 	if (property == config->prop_crtc_id) {
 		*val = (state->crtc) ? state->crtc->base.id : 0;
 	} else if (property == config->dpms_property) {
-		*val = connector->dpms;
+		if (state->crtc && state->crtc->state->self_refresh_active)
+			*val = DRM_MODE_DPMS_ON;
+		else
+			*val = connector->dpms;
 	} else if (property == config->tv_select_subconnector_property) {
 		*val = state->tv.subconnector;
 	} else if (property == config->tv_left_margin_property) {
diff --git a/drivers/gpu/drm/drm_self_refresh_helper.c b/drivers/gpu/drm/drm_self_refresh_helper.c
new file mode 100644
index 000000000000..f46e7639d277
--- /dev/null
+++ b/drivers/gpu/drm/drm_self_refresh_helper.c
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2019 Google, Inc.
+ *
+ * Authors:
+ * Sean Paul <seanpaul@chromium.org>
+ */
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_device.h>
+#include <drm/drm_mode_config.h>
+#include <drm/drm_modeset_lock.h>
+#include <drm/drm_print.h>
+#include <drm/drm_self_refresh_helper.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+/**
+ * DOC: overview
+ *
+ * This helper library provides an easy way for drivers to leverage the atomic
+ * framework to implement panel self refresh (SR) support. Drivers are
+ * responsible for registering and unregistering the SR helpers on load/unload.
+ *
+ * Once a crtc has enabled SR, the helpers will monitor activity and
+ * call back into the driver to enable/disable SR as appropriate. The best way
+ * to think about this is that it's a DPMS on/off request with a flag set in
+ * state that tells you to disable/enable SR on the panel instead of power-
+ * cycling it.
+ *
+ * Drivers may choose to fully disable their crtc/encoder/bridge hardware, or
+ * they can use the "self_refresh_active" flags in crtc state if they want to
+ * enter low power mode without full disable (in case full disable/enable is too
+ * slow).
+ *
+ * SR will be deactivated if there are any atomic updates affecting the
+ * pipe that is in SR mode. If a crtc is driving multiple connectors, all
+ * connectors must be SR aware and all will enter SR mode.
+ */
+
+struct drm_self_refresh_data {
+	struct drm_crtc *crtc;
+	struct delayed_work entry_work;
+	struct drm_atomic_state *save_state;
+	unsigned int entry_delay_ms;
+};
+
+static void drm_self_refresh_helper_entry_work(struct work_struct *work)
+{
+	struct drm_self_refresh_data *sr_data = container_of(
+				to_delayed_work(work),
+				struct drm_self_refresh_data, entry_work);
+	struct drm_crtc *crtc = sr_data->crtc;
+	struct drm_device *dev = crtc->dev;
+	struct drm_modeset_acquire_ctx ctx;
+	struct drm_atomic_state *state;
+	struct drm_connector *conn;
+	struct drm_connector_state *conn_state;
+	struct drm_crtc_state *crtc_state;
+	int i, ret;
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	state = drm_atomic_state_alloc(dev);
+	if (!state) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+retry:
+	state->acquire_ctx = &ctx;
+
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		goto out;
+	}
+
+	if (!crtc_state->enable)
+		goto out;
+
+	ret = drm_atomic_add_affected_connectors(state, crtc);
+	if (ret)
+		goto out;
+
+	for_each_new_connector_in_state(state, conn, conn_state, i) {
+		if (!conn_state->self_refresh_aware)
+			goto out;
+	}
+
+	crtc_state->active = false;
+	crtc_state->self_refresh_active = true;
+
+	ret = drm_atomic_commit(state);
+	if (ret)
+		goto out;
+
+out:
+	if (ret == -EDEADLK) {
+		drm_atomic_state_clear(state);
+		ret = drm_modeset_backoff(&ctx);
+		if (!ret)
+			goto retry;
+	}
+
+	drm_atomic_state_put(state);
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+}
+
+/**
+ * drm_self_refresh_helper_alter_state - Alters the atomic state for SR exit
+ * @state: the state currently being checked
+ *
+ * Called at the end of atomic check. This function checks the state for flags
+ * incompatible with self refresh exit and changes them. This is a bit
+ * disingenuous since userspace is expecting one thing and we're giving it
+ * another. However in order to keep self refresh entirely hidden from
+ * userspace, this is required.
+ *
+ * At the end, we queue up the self refresh entry work so we can enter PSR after
+ * the desired delay.
+ */
+void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state)
+{
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *crtc_state;
+	int i;
+
+	if (state->async_update || !state->allow_modeset) {
+		for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
+			if (crtc_state->self_refresh_active) {
+				state->async_update = false;
+				state->allow_modeset = true;
+				break;
+			}
+		}
+	}
+
+	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
+		struct drm_self_refresh_data *sr_data;
+
+		/* Don't trigger the entry timer when we're already in SR */
+		if (crtc_state->self_refresh_active)
+			continue;
+
+		sr_data = crtc->self_refresh_data;
+		if (!sr_data)
+			continue;
+
+		mod_delayed_work(system_wq, &sr_data->entry_work,
+				 msecs_to_jiffies(sr_data->entry_delay_ms));
+	}
+}
+EXPORT_SYMBOL(drm_self_refresh_helper_alter_state);
+
+/**
+ * drm_self_refresh_helper_register - Registers self refresh helpers for a crtc
+ * @crtc: the crtc which supports self refresh supported displays
+ * @entry_delay_ms: amount of inactivity to wait before entering self refresh
+ */
+int drm_self_refresh_helper_register(struct drm_crtc *crtc,
+				     unsigned int entry_delay_ms)
+{
+	struct drm_self_refresh_data *sr_data = crtc->self_refresh_data;
+
+	/* Helper is already registered */
+	if (WARN_ON(sr_data))
+		return -EINVAL;
+
+	sr_data = kzalloc(sizeof(*sr_data), GFP_KERNEL);
+	if (!sr_data)
+		return -ENOMEM;
+
+	INIT_DELAYED_WORK(&sr_data->entry_work,
+			  drm_self_refresh_helper_entry_work);
+	sr_data->entry_delay_ms = entry_delay_ms;
+	sr_data->crtc = crtc;
+
+	crtc->self_refresh_data = sr_data;
+	return 0;
+}
+EXPORT_SYMBOL(drm_self_refresh_helper_register);
+
+/**
+ * drm_self_refresh_helper_unregister - Unregisters self refresh helpers
+ * @crtc: the crtc to unregister
+ */
+void drm_self_refresh_helper_unregister(struct drm_crtc *crtc)
+{
+	struct drm_self_refresh_data *sr_data = crtc->self_refresh_data;
+
+	/* Helper is already unregistered */
+	if (sr_data)
+		return;
+
+	crtc->self_refresh_data = NULL;
+
+	cancel_delayed_work_sync(&sr_data->entry_work);
+	kfree(sr_data);
+}
+EXPORT_SYMBOL(drm_self_refresh_helper_unregister);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 824a5ed4e216..1e9cab1da97a 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -944,4 +944,19 @@ drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state)
 	       state->connectors_changed;
 }
 
+/**
+ * drm_atomic_crtc_effectively_active - compute whether crtc is actually active
+ * @state: &drm_crtc_state for the CRTC
+ *
+ * When in self refresh mode, the crtc_state->active value will be false, since
+ * the crtc is off. However in some cases we're interested in whether the crtc
+ * is active, or effectively active (ie: it's connected to an active display).
+ * In these cases, use this function instead of just checking active.
+ */
+static inline bool
+drm_atomic_crtc_effectively_active(const struct drm_crtc_state *state)
+{
+	return state->active || state->self_refresh_active;
+}
+
 #endif /* DRM_ATOMIC_H_ */
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 02a131202add..9b40eb6f0ef4 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -539,6 +539,20 @@ struct drm_connector_state {
 	/** @tv: TV connector state */
 	struct drm_tv_connector_state tv;
 
+	/**
+	 * @self_refresh_aware:
+	 *
+	 * This tracks whether a connector is aware of the self refresh state.
+	 * It should be set to true for those connector implementations which
+	 * understand the self refresh state. This is needed since the crtc
+	 * registers the self refresh helpers and it doesn't know if the
+	 * connectors downstream have implemented self refresh entry/exit.
+	 *
+	 * Drivers should set this to true in atomic_check if they know how to
+	 * handle self_refresh requests.
+	 */
+	bool self_refresh_aware;
+
 	/**
 	 * @picture_aspect_ratio: Connector property to control the
 	 * HDMI infoframe aspect ratio setting.
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 58ad983d7cd6..67e3075a8784 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -53,6 +53,7 @@ struct drm_mode_set;
 struct drm_file;
 struct drm_clip_rect;
 struct drm_printer;
+struct drm_self_refresh_data;
 struct device_node;
 struct dma_fence;
 struct edid;
@@ -299,6 +300,17 @@ struct drm_crtc_state {
 	 */
 	bool vrr_enabled;
 
+	/**
+	 * @self_refresh_active:
+	 *
+	 * Used by the self refresh helpers to denote when a self refresh
+	 * transition is occuring. This will be set on enable/disable callbacks
+	 * when self refresh is being enabled or disabled. In some cases, it may
+	 * not be desirable to fully shut off the crtc during self refresh.
+	 * CRTC's can inspect this flag and determine the best course of action.
+	 */
+	bool self_refresh_active;
+
 	/**
 	 * @event:
 	 *
@@ -1087,6 +1099,13 @@ struct drm_crtc {
 	 * The name of the CRTC's fence timeline.
 	 */
 	char timeline_name[32];
+
+	/**
+	 * @self_refresh_data: Holds the state for the self refresh helpers
+	 *
+	 * Initialized via drm_self_refresh_helper_register().
+	 */
+	struct drm_self_refresh_data *self_refresh_data;
 };
 
 /**
diff --git a/include/drm/drm_self_refresh_helper.h b/include/drm/drm_self_refresh_helper.h
new file mode 100644
index 000000000000..efb2e6e3249f
--- /dev/null
+++ b/include/drm/drm_self_refresh_helper.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright (C) 2019 Google, Inc.
+ *
+ * Authors:
+ * Sean Paul <seanpaul@chromium.org>
+ */
+#ifndef DRM_SELF_REFRESH_HELPER_H_
+#define DRM_SELF_REFRESH_HELPER_H_
+
+struct drm_atomic_state;
+struct drm_connector;
+struct drm_device;
+struct drm_modeset_acquire_ctx;
+
+void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state);
+
+int drm_self_refresh_helper_register(struct drm_crtc *crtc,
+				     unsigned int entry_delay_ms);
+
+void drm_self_refresh_helper_unregister(struct drm_crtc *crtc);
+#endif
-- 
Sean Paul, Software Engineer, Google / Chromium OS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 06/10] drm/rockchip: Use dirtyfb helper
       [not found] <20190502194956.218441-1-sean@poorly.run>
                   ` (4 preceding siblings ...)
  2019-05-02 19:49 ` [PATCH v3 05/10] drm: Add helpers to kick off self refresh mode in drivers Sean Paul
@ 2019-05-02 19:49 ` Sean Paul
  2019-05-02 19:49 ` [PATCH v3 07/10] drm/rockchip: Check for fast link training before enabling psr Sean Paul
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 29+ messages in thread
From: Sean Paul @ 2019-05-02 19:49 UTC (permalink / raw)
  To: dri-devel
  Cc: Sean Paul, Daniel Vetter, Sandy Huang, Heiko Stübner,
	David Airlie, linux-arm-kernel, linux-rockchip, linux-kernel

From: Sean Paul <seanpaul@chromium.org>

Instead of flushing all vops every time we get a dirtyfb call, use the
damage helper to kick off an atomic commit. Even though we don't use
damage clips, the helper commit will force us through the normal
psr_inhibit_get/put sequence.

Changes in v3:
- Added to the set

Suggested-by: Daniel Vetter <daniel@ffwll.ch>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 13 ++-----------
 1 file changed, 2 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 97438bbbe389..02e81ca2d933 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -16,6 +16,7 @@
 #include <drm/drm.h>
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_damage_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_probe_helper.h>
@@ -25,20 +26,10 @@
 #include "rockchip_drm_gem.h"
 #include "rockchip_drm_psr.h"
 
-static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb,
-				 struct drm_file *file,
-				 unsigned int flags, unsigned int color,
-				 struct drm_clip_rect *clips,
-				 unsigned int num_clips)
-{
-	rockchip_drm_psr_flush_all(fb->dev);
-	return 0;
-}
-
 static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
 	.destroy       = drm_gem_fb_destroy,
 	.create_handle = drm_gem_fb_create_handle,
-	.dirty	       = rockchip_drm_fb_dirty,
+	.dirty	       = drm_atomic_helper_dirtyfb,
 };
 
 static struct drm_framebuffer *
-- 
Sean Paul, Software Engineer, Google / Chromium OS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 07/10] drm/rockchip: Check for fast link training before enabling psr
       [not found] <20190502194956.218441-1-sean@poorly.run>
                   ` (5 preceding siblings ...)
  2019-05-02 19:49 ` [PATCH v3 06/10] drm/rockchip: Use dirtyfb helper Sean Paul
@ 2019-05-02 19:49 ` Sean Paul
  2019-05-02 19:49 ` [PATCH v3 08/10] drm/rockchip: Use the helpers for PSR Sean Paul
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 29+ messages in thread
From: Sean Paul @ 2019-05-02 19:49 UTC (permalink / raw)
  To: dri-devel
  Cc: Sean Paul, Zain Wang, Tomasz Figa, Andrzej Hajda,
	Laurent Pinchart, David Airlie, Daniel Vetter, linux-kernel

From: Sean Paul <seanpaul@chromium.org>

Once we start shutting off the link during PSR, we're going to want fast
training to work. If the display doesn't support fast training, don't
enable psr.

Changes in v2:
- None
Changes in v3:
- None

Link to v1: https://patchwork.freedesktop.org/patch/msgid/20190228210939.83386-3-sean@poorly.run
Link to v2: https://patchwork.freedesktop.org/patch/msgid/20190326204509.96515-2-sean@poorly.run

Cc: Zain Wang <wzz@rock-chips.com>
Cc: Tomasz Figa <tfiga@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 225f5e5dd69b..af34554a5a02 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1040,16 +1040,17 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
 	if (ret)
 		return ret;
 
+	/* Check whether panel supports fast training */
+	ret = analogix_dp_fast_link_train_detection(dp);
+	if (ret)
+		dp->psr_enable = false;
+
 	if (dp->psr_enable) {
 		ret = analogix_dp_enable_sink_psr(dp);
 		if (ret)
 			return ret;
 	}
 
-	/* Check whether panel supports fast training */
-	ret =  analogix_dp_fast_link_train_detection(dp);
-	if (ret)
-		dp->psr_enable = false;
 
 	return ret;
 }
-- 
Sean Paul, Software Engineer, Google / Chromium OS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 08/10] drm/rockchip: Use the helpers for PSR
       [not found] <20190502194956.218441-1-sean@poorly.run>
                   ` (6 preceding siblings ...)
  2019-05-02 19:49 ` [PATCH v3 07/10] drm/rockchip: Check for fast link training before enabling psr Sean Paul
@ 2019-05-02 19:49 ` Sean Paul
  2019-05-02 19:49 ` [PATCH v3 09/10] drm/rockchip: Don't fully disable vop on self refresh Sean Paul
  2019-05-02 19:49 ` [PATCH v3 10/10] drm/rockchip: Use drm_atomic_helper_commit_tail_rpm Sean Paul
  9 siblings, 0 replies; 29+ messages in thread
From: Sean Paul @ 2019-05-02 19:49 UTC (permalink / raw)
  To: dri-devel
  Cc: Sean Paul, Zain Wang, Tomasz Figa, Andrzej Hajda,
	Laurent Pinchart, David Airlie, Daniel Vetter, Sandy Huang,
	Heiko Stübner, linux-kernel, linux-arm-kernel,
	linux-rockchip

From: Sean Paul <seanpaul@chromium.org>

Instead of rolling our own implementation for tracking when PSR should
be [in]active, use the new self refresh helpers to do the heavy lifting.

Changes in v2:
- updated to reflect changes made in the helpers
Changes in v3:
- use the new atomic hooks to inspect crtc state instead of needing conn state (Daniel)

Link to v1: https://patchwork.freedesktop.org/patch/msgid/20190228210939.83386-4-sean@poorly.run
Link to v2: https://patchwork.freedesktop.org/patch/msgid/20190326204509.96515-3-sean@poorly.run

Cc: Zain Wang <wzz@rock-chips.com>
Cc: Tomasz Figa <tfiga@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 .../drm/bridge/analogix/analogix_dp_core.c    | 265 +++++++++++-----
 .../drm/bridge/analogix/analogix_dp_core.h    |   2 +-
 drivers/gpu/drm/rockchip/Makefile             |   3 +-
 .../gpu/drm/rockchip/analogix_dp-rockchip.c   |  86 +++---
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c    |   5 -
 drivers/gpu/drm/rockchip/rockchip_drm_psr.c   | 290 ------------------
 drivers/gpu/drm/rockchip/rockchip_drm_psr.h   |  30 --
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c   |  33 +-
 include/drm/bridge/analogix_dp.h              |   4 -
 9 files changed, 243 insertions(+), 475 deletions(-)
 delete mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.c
 delete mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_psr.h

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index af34554a5a02..e66c105c3b68 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -24,6 +24,7 @@
 #include <linux/phy/phy.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_panel.h>
@@ -106,63 +107,7 @@ static int analogix_dp_detect_hpd(struct analogix_dp_device *dp)
 	return 0;
 }
 
-int analogix_dp_psr_enabled(struct analogix_dp_device *dp)
-{
-
-	return dp->psr_enable;
-}
-EXPORT_SYMBOL_GPL(analogix_dp_psr_enabled);
-
-int analogix_dp_enable_psr(struct analogix_dp_device *dp)
-{
-	struct edp_vsc_psr psr_vsc;
-
-	if (!dp->psr_enable)
-		return 0;
-
-	/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-
-	psr_vsc.DB0 = 0;
-	psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
-
-	return analogix_dp_send_psr_spd(dp, &psr_vsc, true);
-}
-EXPORT_SYMBOL_GPL(analogix_dp_enable_psr);
-
-int analogix_dp_disable_psr(struct analogix_dp_device *dp)
-{
-	struct edp_vsc_psr psr_vsc;
-	int ret;
-
-	if (!dp->psr_enable)
-		return 0;
-
-	/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
-	memset(&psr_vsc, 0, sizeof(psr_vsc));
-	psr_vsc.sdp_header.HB0 = 0;
-	psr_vsc.sdp_header.HB1 = 0x7;
-	psr_vsc.sdp_header.HB2 = 0x2;
-	psr_vsc.sdp_header.HB3 = 0x8;
-
-	psr_vsc.DB0 = 0;
-	psr_vsc.DB1 = 0;
-
-	ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
-	if (ret != 1) {
-		dev_err(dp->dev, "Failed to set DP Power0 %d\n", ret);
-		return ret;
-	}
-
-	return analogix_dp_send_psr_spd(dp, &psr_vsc, false);
-}
-EXPORT_SYMBOL_GPL(analogix_dp_disable_psr);
-
-static int analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
+static bool analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
 {
 	unsigned char psr_version;
 	int ret;
@@ -170,14 +115,11 @@ static int analogix_dp_detect_sink_psr(struct analogix_dp_device *dp)
 	ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_SUPPORT, &psr_version);
 	if (ret != 1) {
 		dev_err(dp->dev, "failed to get PSR version, disable it\n");
-		return ret;
+		return false;
 	}
 
 	dev_dbg(dp->dev, "Panel PSR version : %x\n", psr_version);
-
-	dp->psr_enable = (psr_version & DP_PSR_IS_SUPPORTED) ? true : false;
-
-	return 0;
+	return psr_version & DP_PSR_IS_SUPPORTED;
 }
 
 static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
@@ -200,7 +142,7 @@ static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
 	}
 
 	/* Main-Link transmitter remains active during PSR active states */
-	psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+	psr_en = DP_PSR_CRC_VERIFICATION;
 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
 	if (ret != 1) {
 		dev_err(dp->dev, "failed to set panel psr\n");
@@ -208,8 +150,7 @@ static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
 	}
 
 	/* Enable psr function */
-	psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
-		 DP_PSR_CRC_VERIFICATION;
+	psr_en = DP_PSR_ENABLE | DP_PSR_CRC_VERIFICATION;
 	ret = drm_dp_dpcd_writeb(&dp->aux, DP_PSR_EN_CFG, psr_en);
 	if (ret != 1) {
 		dev_err(dp->dev, "failed to set panel psr\n");
@@ -218,10 +159,11 @@ static int analogix_dp_enable_sink_psr(struct analogix_dp_device *dp)
 
 	analogix_dp_enable_psr_crc(dp);
 
+	dp->psr_supported = true;
+
 	return 0;
 end:
 	dev_err(dp->dev, "enable psr fail, force to disable psr\n");
-	dp->psr_enable = false;
 
 	return ret;
 }
@@ -1036,25 +978,90 @@ static int analogix_dp_commit(struct analogix_dp_device *dp)
 		}
 	}
 
-	ret = analogix_dp_detect_sink_psr(dp);
-	if (ret)
-		return ret;
-
 	/* Check whether panel supports fast training */
 	ret = analogix_dp_fast_link_train_detection(dp);
 	if (ret)
-		dp->psr_enable = false;
+		return ret;
 
-	if (dp->psr_enable) {
+	if (analogix_dp_detect_sink_psr(dp)) {
 		ret = analogix_dp_enable_sink_psr(dp);
 		if (ret)
 			return ret;
 	}
 
+	return ret;
+}
+
+static int analogix_dp_enable_psr(struct analogix_dp_device *dp)
+{
+	struct edp_vsc_psr psr_vsc;
+	int ret;
+	u8 sink;
+
+	ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &sink);
+	if (ret != 1)
+		DRM_DEV_ERROR(dp->dev, "Failed to read psr status %d\n", ret);
+	else if (sink == DP_PSR_SINK_ACTIVE_RFB)
+		return 0;
+
+	/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+	memset(&psr_vsc, 0, sizeof(psr_vsc));
+	psr_vsc.sdp_header.HB0 = 0;
+	psr_vsc.sdp_header.HB1 = 0x7;
+	psr_vsc.sdp_header.HB2 = 0x2;
+	psr_vsc.sdp_header.HB3 = 0x8;
+	psr_vsc.DB0 = 0;
+	psr_vsc.DB1 = EDP_VSC_PSR_STATE_ACTIVE | EDP_VSC_PSR_CRC_VALUES_VALID;
+
+	ret = analogix_dp_send_psr_spd(dp, &psr_vsc, true);
+	if (!ret)
+		analogix_dp_set_analog_power_down(dp, POWER_ALL, true);
 
 	return ret;
 }
 
+static int analogix_dp_disable_psr(struct analogix_dp_device *dp)
+{
+	struct edp_vsc_psr psr_vsc;
+	int ret;
+	u8 sink;
+
+	analogix_dp_set_analog_power_down(dp, POWER_ALL, false);
+
+	ret = drm_dp_dpcd_writeb(&dp->aux, DP_SET_POWER, DP_SET_POWER_D0);
+	if (ret != 1) {
+		DRM_DEV_ERROR(dp->dev, "Failed to set DP Power0 %d\n", ret);
+		return ret;
+	}
+
+	ret = drm_dp_dpcd_readb(&dp->aux, DP_PSR_STATUS, &sink);
+	if (ret != 1) {
+		DRM_DEV_ERROR(dp->dev, "Failed to read psr status %d\n", ret);
+		return ret;
+	} else if (sink == DP_PSR_SINK_INACTIVE) {
+		DRM_DEV_ERROR(dp->dev, "sink inactive, skip disable psr");
+		return 0;
+	}
+
+	ret = analogix_dp_train_link(dp);
+	if (ret) {
+		DRM_DEV_ERROR(dp->dev, "Failed to train the link %d\n", ret);
+		return ret;
+	}
+
+	/* Prepare VSC packet as per EDP 1.4 spec, Table 6.9 */
+	memset(&psr_vsc, 0, sizeof(psr_vsc));
+	psr_vsc.sdp_header.HB0 = 0;
+	psr_vsc.sdp_header.HB1 = 0x7;
+	psr_vsc.sdp_header.HB2 = 0x2;
+	psr_vsc.sdp_header.HB3 = 0x8;
+
+	psr_vsc.DB0 = 0;
+	psr_vsc.DB1 = 0;
+
+	return analogix_dp_send_psr_spd(dp, &psr_vsc, true);
+}
+
 /*
  * This function is a bit of a catch-all for panel preparation, hopefully
  * simplifying the logic of functions that need to prepare/unprepare the panel
@@ -1145,9 +1152,37 @@ analogix_dp_best_encoder(struct drm_connector *connector)
 	return dp->encoder;
 }
 
+
+int analogix_dp_atomic_check(struct drm_connector *connector,
+			     struct drm_atomic_state *state)
+{
+	struct analogix_dp_device *dp = to_dp(connector);
+	struct drm_connector_state *conn_state;
+	struct drm_crtc_state *crtc_state;
+
+	conn_state = drm_atomic_get_new_connector_state(state, connector);
+	if (WARN_ON(!conn_state))
+		return -ENODEV;
+
+	conn_state->self_refresh_aware = true;
+
+	if (!conn_state->crtc)
+		return 0;
+
+	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+	if (!crtc_state)
+		return 0;
+
+	if (crtc_state->self_refresh_active && !dp->psr_supported)
+		return -EINVAL;
+
+	return 0;
+}
+
 static const struct drm_connector_helper_funcs analogix_dp_connector_helper_funcs = {
 	.get_modes = analogix_dp_get_modes,
 	.best_encoder = analogix_dp_best_encoder,
+	.atomic_check = analogix_dp_atomic_check,
 };
 
 static enum drm_connector_status
@@ -1239,11 +1274,22 @@ static int analogix_dp_bridge_attach(struct drm_bridge *bridge)
 	return 0;
 }
 
-static void analogix_dp_bridge_pre_enable(struct drm_bridge *bridge)
+static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+						 struct drm_atomic_state *state)
 {
 	struct analogix_dp_device *dp = bridge->driver_private;
+	struct drm_crtc_state *old_crtc_state = NULL;
 	int ret;
 
+	drm_atomic_crtc_state_for_encoder(state, dp->encoder, NULL,
+					  &old_crtc_state, NULL);
+	if (!old_crtc_state)
+		return;
+
+	/* Don't touch the panel if we're coming back from PSR */
+	if (old_crtc_state->self_refresh_active)
+		return;
+
 	ret = analogix_dp_prepare_panel(dp, true, true);
 	if (ret)
 		DRM_ERROR("failed to setup the panel ret = %d\n", ret);
@@ -1304,10 +1350,26 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp)
 	return ret;
 }
 
-static void analogix_dp_bridge_enable(struct drm_bridge *bridge)
+static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge,
+					     struct drm_atomic_state *state)
 {
 	struct analogix_dp_device *dp = bridge->driver_private;
+	struct drm_crtc_state *old_crtc_state = NULL;
 	int timeout_loop = 0;
+	int ret;
+
+	drm_atomic_crtc_state_for_encoder(state, dp->encoder, NULL,
+					  &old_crtc_state, NULL);
+	if (!old_crtc_state)
+		return;
+
+	/* Not a full enable, just disable PSR and continue */
+	if (old_crtc_state->self_refresh_active) {
+		ret = analogix_dp_disable_psr(dp);
+		if (ret)
+			DRM_ERROR("Failed to disable psr %d\n", ret);
+		return;
+	}
 
 	if (dp->dpms_mode == DRM_MODE_DPMS_ON)
 		return;
@@ -1356,11 +1418,51 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge)
 	if (ret)
 		DRM_ERROR("failed to setup the panel ret = %d\n", ret);
 
-	dp->psr_enable = false;
 	dp->fast_train_enable = false;
+	dp->psr_supported = false;
 	dp->dpms_mode = DRM_MODE_DPMS_OFF;
 }
 
+static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge,
+					      struct drm_atomic_state *state)
+{
+	struct analogix_dp_device *dp = bridge->driver_private;
+	struct drm_crtc_state *new_crtc_state = NULL;
+
+	drm_atomic_crtc_state_for_encoder(state, dp->encoder, NULL, NULL,
+					  &new_crtc_state);
+	if (!new_crtc_state)
+		goto out;
+
+	/* Don't do a full disable on PSR transitions */
+	if (new_crtc_state->self_refresh_active)
+		return;
+
+out:
+	analogix_dp_bridge_disable(bridge);
+}
+
+static
+void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge,
+					    struct drm_atomic_state *state)
+{
+	struct analogix_dp_device *dp = bridge->driver_private;
+	struct drm_crtc_state *new_crtc_state = NULL;
+	int ret;
+
+	drm_atomic_crtc_state_for_encoder(state, dp->encoder, NULL, NULL,
+					  &new_crtc_state);
+	if (!new_crtc_state)
+		return;
+
+	if (!new_crtc_state->self_refresh_active)
+		return;
+
+	ret = analogix_dp_enable_psr(dp);
+	if (ret)
+		DRM_ERROR("Failed to enable psr (%d)\n", ret);
+}
+
 static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
 				const struct drm_display_mode *orig_mode,
 				const struct drm_display_mode *mode)
@@ -1440,16 +1542,11 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge,
 		video->interlaced = true;
 }
 
-static void analogix_dp_bridge_nop(struct drm_bridge *bridge)
-{
-	/* do nothing */
-}
-
 static const struct drm_bridge_funcs analogix_dp_bridge_funcs = {
-	.pre_enable = analogix_dp_bridge_pre_enable,
-	.enable = analogix_dp_bridge_enable,
-	.disable = analogix_dp_bridge_disable,
-	.post_disable = analogix_dp_bridge_nop,
+	.atomic_pre_enable = analogix_dp_bridge_atomic_pre_enable,
+	.atomic_enable = analogix_dp_bridge_atomic_enable,
+	.atomic_disable = analogix_dp_bridge_atomic_disable,
+	.atomic_post_disable = analogix_dp_bridge_atomic_post_disable,
 	.mode_set = analogix_dp_bridge_mode_set,
 	.attach = analogix_dp_bridge_attach,
 };
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index 769255dc6e99..d937fa3d9ee8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -173,8 +173,8 @@ struct analogix_dp_device {
 	int			dpms_mode;
 	int			hpd_gpio;
 	bool                    force_hpd;
-	bool			psr_enable;
 	bool			fast_train_enable;
+	bool			psr_supported;
 
 	struct mutex		panel_lock;
 	bool			panel_is_modeset;
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 524684ba7f6a..17a9e7eb2130 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -4,8 +4,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-		rockchip_drm_gem.o rockchip_drm_psr.o \
-		rockchip_drm_vop.o rockchip_vop_reg.o
+		rockchip_drm_gem.o rockchip_drm_vop.o rockchip_vop_reg.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index bc4423624209..624daa886d57 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -21,6 +21,8 @@
 #include <linux/clk.h>
 
 #include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_of.h>
 #include <drm/drm_panel.h>
@@ -32,7 +34,6 @@
 #include <drm/bridge/analogix_dp.h>
 
 #include "rockchip_drm_drv.h"
-#include "rockchip_drm_psr.h"
 #include "rockchip_drm_vop.h"
 
 #define RK3288_GRF_SOC_CON6		0x25c
@@ -77,29 +78,6 @@ struct rockchip_dp_device {
 	struct analogix_dp_plat_data plat_data;
 };
 
-static int analogix_dp_psr_set(struct drm_encoder *encoder, bool enabled)
-{
-	struct rockchip_dp_device *dp = to_dp(encoder);
-	int ret;
-
-	if (!analogix_dp_psr_enabled(dp->adp))
-		return 0;
-
-	DRM_DEV_DEBUG(dp->dev, "%s PSR...\n", enabled ? "Entry" : "Exit");
-
-	ret = rockchip_drm_wait_vact_end(dp->encoder.crtc,
-					 PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
-	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "line flag interrupt did not arrive\n");
-		return -ETIMEDOUT;
-	}
-
-	if (enabled)
-		return analogix_dp_enable_psr(dp->adp);
-	else
-		return analogix_dp_disable_psr(dp->adp);
-}
-
 static int rockchip_dp_pre_init(struct rockchip_dp_device *dp)
 {
 	reset_control_assert(dp->rst);
@@ -130,21 +108,9 @@ static int rockchip_dp_poweron_start(struct analogix_dp_plat_data *plat_data)
 	return ret;
 }
 
-static int rockchip_dp_poweron_end(struct analogix_dp_plat_data *plat_data)
-{
-	struct rockchip_dp_device *dp = to_dp(plat_data);
-
-	return rockchip_drm_psr_inhibit_put(&dp->encoder);
-}
-
 static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
 {
 	struct rockchip_dp_device *dp = to_dp(plat_data);
-	int ret;
-
-	ret = rockchip_drm_psr_inhibit_get(&dp->encoder);
-	if (ret != 0)
-		return ret;
 
 	clk_disable_unprepare(dp->pclk);
 
@@ -184,12 +150,23 @@ static void rockchip_dp_drm_encoder_mode_set(struct drm_encoder *encoder,
 	/* do nothing */
 }
 
-static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder)
+static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder,
+					   struct drm_atomic_state *state)
 {
 	struct rockchip_dp_device *dp = to_dp(encoder);
+	struct drm_crtc_state *old_crtc_state = NULL;
 	int ret;
 	u32 val;
 
+	drm_atomic_crtc_state_for_encoder(state, encoder, NULL, &old_crtc_state,
+					  NULL);
+	if (!old_crtc_state)
+		return;
+
+	/* Coming back from self refresh, nothing to do */
+	if (old_crtc_state->self_refresh_active)
+		return;
+
 	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
 	if (ret < 0)
 		return;
@@ -214,9 +191,26 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder)
 	clk_disable_unprepare(dp->grfclk);
 }
 
-static void rockchip_dp_drm_encoder_nop(struct drm_encoder *encoder)
+static void rockchip_dp_drm_encoder_disable(struct drm_encoder *encoder,
+					    struct drm_atomic_state *state)
 {
-	/* do nothing */
+	struct rockchip_dp_device *dp = to_dp(encoder);
+	struct drm_crtc *crtc = NULL;
+	struct drm_crtc_state *new_crtc_state = NULL;
+	int ret;
+
+	drm_atomic_crtc_state_for_encoder(state, encoder, &crtc, NULL,
+					  &new_crtc_state);
+	if (!crtc || !new_crtc_state)
+		return;
+
+	/* Only wait for vactive end on self refresh transitions */
+	if (!new_crtc_state->self_refresh_active)
+		return;
+
+	ret = rockchip_drm_wait_vact_end(crtc, PSR_WAIT_LINE_FLAG_TIMEOUT_MS);
+	if (ret)
+		DRM_DEV_ERROR(dp->dev, "line flag irq timed out\n");
 }
 
 static int
@@ -245,8 +239,8 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
 static struct drm_encoder_helper_funcs rockchip_dp_encoder_helper_funcs = {
 	.mode_fixup = rockchip_dp_drm_encoder_mode_fixup,
 	.mode_set = rockchip_dp_drm_encoder_mode_set,
-	.enable = rockchip_dp_drm_encoder_enable,
-	.disable = rockchip_dp_drm_encoder_nop,
+	.atomic_enable = rockchip_dp_drm_encoder_enable,
+	.atomic_disable = rockchip_dp_drm_encoder_disable,
 	.atomic_check = rockchip_dp_drm_encoder_atomic_check,
 };
 
@@ -338,23 +332,16 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
 	dp->plat_data.dev_type = dp->data->chip_type;
 	dp->plat_data.power_on_start = rockchip_dp_poweron_start;
-	dp->plat_data.power_on_end = rockchip_dp_poweron_end;
 	dp->plat_data.power_off = rockchip_dp_powerdown;
 	dp->plat_data.get_modes = rockchip_dp_get_modes;
 
-	ret = rockchip_drm_psr_register(&dp->encoder, analogix_dp_psr_set);
-	if (ret < 0)
-		goto err_cleanup_encoder;
-
 	dp->adp = analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
 	if (IS_ERR(dp->adp)) {
 		ret = PTR_ERR(dp->adp);
-		goto err_unreg_psr;
+		goto err_cleanup_encoder;
 	}
 
 	return 0;
-err_unreg_psr:
-	rockchip_drm_psr_unregister(&dp->encoder);
 err_cleanup_encoder:
 	dp->encoder.funcs->destroy(&dp->encoder);
 	return ret;
@@ -366,7 +353,6 @@ static void rockchip_dp_unbind(struct device *dev, struct device *master,
 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
 
 	analogix_dp_unbind(dp->adp);
-	rockchip_drm_psr_unregister(&dp->encoder);
 	dp->encoder.funcs->destroy(&dp->encoder);
 
 	dp->adp = ERR_PTR(-ENODEV);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 02e81ca2d933..214064d599ee 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -24,7 +24,6 @@
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_gem.h"
-#include "rockchip_drm_psr.h"
 
 static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
 	.destroy       = drm_gem_fb_destroy,
@@ -123,8 +122,6 @@ rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
 {
 	struct drm_device *dev = old_state->dev;
 
-	rockchip_drm_psr_inhibit_get_state(old_state);
-
 	drm_atomic_helper_commit_modeset_disables(dev, old_state);
 
 	drm_atomic_helper_commit_modeset_enables(dev, old_state);
@@ -132,8 +129,6 @@ rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
 	drm_atomic_helper_commit_planes(dev, old_state,
 					DRM_PLANE_COMMIT_ACTIVE_ONLY);
 
-	rockchip_drm_psr_inhibit_put_state(old_state);
-
 	drm_atomic_helper_commit_hw_done(old_state);
 
 	drm_atomic_helper_wait_for_vblanks(dev, old_state);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c b/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
deleted file mode 100644
index a0c8bd235b67..000000000000
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
- * Author: Yakir Yang <ykk@rock-chips.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <drm/drmP.h>
-#include <drm/drm_atomic.h>
-#include <drm/drm_probe_helper.h>
-
-#include "rockchip_drm_drv.h"
-#include "rockchip_drm_psr.h"
-
-#define PSR_FLUSH_TIMEOUT_MS	100
-
-struct psr_drv {
-	struct list_head	list;
-	struct drm_encoder	*encoder;
-
-	struct mutex		lock;
-	int			inhibit_count;
-	bool			enabled;
-
-	struct delayed_work	flush_work;
-
-	int (*set)(struct drm_encoder *encoder, bool enable);
-};
-
-static struct psr_drv *find_psr_by_encoder(struct drm_encoder *encoder)
-{
-	struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
-	struct psr_drv *psr;
-
-	mutex_lock(&drm_drv->psr_list_lock);
-	list_for_each_entry(psr, &drm_drv->psr_list, list) {
-		if (psr->encoder == encoder)
-			goto out;
-	}
-	psr = ERR_PTR(-ENODEV);
-
-out:
-	mutex_unlock(&drm_drv->psr_list_lock);
-	return psr;
-}
-
-static int psr_set_state_locked(struct psr_drv *psr, bool enable)
-{
-	int ret;
-
-	if (psr->inhibit_count > 0)
-		return -EINVAL;
-
-	if (enable == psr->enabled)
-		return 0;
-
-	ret = psr->set(psr->encoder, enable);
-	if (ret)
-		return ret;
-
-	psr->enabled = enable;
-	return 0;
-}
-
-static void psr_flush_handler(struct work_struct *work)
-{
-	struct psr_drv *psr = container_of(to_delayed_work(work),
-					   struct psr_drv, flush_work);
-
-	mutex_lock(&psr->lock);
-	psr_set_state_locked(psr, true);
-	mutex_unlock(&psr->lock);
-}
-
-/**
- * rockchip_drm_psr_inhibit_put - release PSR inhibit on given encoder
- * @encoder: encoder to obtain the PSR encoder
- *
- * Decrements PSR inhibit count on given encoder. Should be called only
- * for a PSR inhibit count increment done before. If PSR inhibit counter
- * reaches zero, PSR flush work is scheduled to make the hardware enter
- * PSR mode in PSR_FLUSH_TIMEOUT_MS.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder)
-{
-	struct psr_drv *psr = find_psr_by_encoder(encoder);
-
-	if (IS_ERR(psr))
-		return PTR_ERR(psr);
-
-	mutex_lock(&psr->lock);
-	--psr->inhibit_count;
-	WARN_ON(psr->inhibit_count < 0);
-	if (!psr->inhibit_count)
-		mod_delayed_work(system_wq, &psr->flush_work,
-				 PSR_FLUSH_TIMEOUT_MS);
-	mutex_unlock(&psr->lock);
-
-	return 0;
-}
-EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put);
-
-void rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state)
-{
-	struct drm_crtc *crtc;
-	struct drm_crtc_state *crtc_state;
-	struct drm_encoder *encoder;
-	u32 encoder_mask = 0;
-	int i;
-
-	for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
-		encoder_mask |= crtc_state->encoder_mask;
-		encoder_mask |= crtc->state->encoder_mask;
-	}
-
-	drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
-		rockchip_drm_psr_inhibit_get(encoder);
-}
-EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get_state);
-
-void rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state)
-{
-	struct drm_crtc *crtc;
-	struct drm_crtc_state *crtc_state;
-	struct drm_encoder *encoder;
-	u32 encoder_mask = 0;
-	int i;
-
-	for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
-		encoder_mask |= crtc_state->encoder_mask;
-		encoder_mask |= crtc->state->encoder_mask;
-	}
-
-	drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
-		rockchip_drm_psr_inhibit_put(encoder);
-}
-EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put_state);
-
-/**
- * rockchip_drm_psr_inhibit_get - acquire PSR inhibit on given encoder
- * @encoder: encoder to obtain the PSR encoder
- *
- * Increments PSR inhibit count on given encoder. This function guarantees
- * that after it returns PSR is turned off on given encoder and no PSR-related
- * hardware state change occurs at least until a matching call to
- * rockchip_drm_psr_inhibit_put() is done.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder)
-{
-	struct psr_drv *psr = find_psr_by_encoder(encoder);
-
-	if (IS_ERR(psr))
-		return PTR_ERR(psr);
-
-	mutex_lock(&psr->lock);
-	psr_set_state_locked(psr, false);
-	++psr->inhibit_count;
-	mutex_unlock(&psr->lock);
-	cancel_delayed_work_sync(&psr->flush_work);
-
-	return 0;
-}
-EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get);
-
-static void rockchip_drm_do_flush(struct psr_drv *psr)
-{
-	cancel_delayed_work_sync(&psr->flush_work);
-
-	mutex_lock(&psr->lock);
-	if (!psr_set_state_locked(psr, false))
-		mod_delayed_work(system_wq, &psr->flush_work,
-				 PSR_FLUSH_TIMEOUT_MS);
-	mutex_unlock(&psr->lock);
-}
-
-/**
- * rockchip_drm_psr_flush_all - force to flush all registered PSR encoders
- * @dev: drm device
- *
- * Disable the PSR function for all registered encoders, and then enable the
- * PSR function back after PSR_FLUSH_TIMEOUT. If encoder PSR state have been
- * changed during flush time, then keep the state no change after flush
- * timeout.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-void rockchip_drm_psr_flush_all(struct drm_device *dev)
-{
-	struct rockchip_drm_private *drm_drv = dev->dev_private;
-	struct psr_drv *psr;
-
-	mutex_lock(&drm_drv->psr_list_lock);
-	list_for_each_entry(psr, &drm_drv->psr_list, list)
-		rockchip_drm_do_flush(psr);
-	mutex_unlock(&drm_drv->psr_list_lock);
-}
-EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
-
-/**
- * rockchip_drm_psr_register - register encoder to psr driver
- * @encoder: encoder that obtain the PSR function
- * @psr_set: call back to set PSR state
- *
- * The function returns with PSR inhibit counter initialized with one
- * and the caller (typically encoder driver) needs to call
- * rockchip_drm_psr_inhibit_put() when it becomes ready to accept PSR
- * enable request.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-int rockchip_drm_psr_register(struct drm_encoder *encoder,
-			int (*psr_set)(struct drm_encoder *, bool enable))
-{
-	struct rockchip_drm_private *drm_drv;
-	struct psr_drv *psr;
-
-	if (!encoder || !psr_set)
-		return -EINVAL;
-
-	drm_drv = encoder->dev->dev_private;
-
-	psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
-	if (!psr)
-		return -ENOMEM;
-
-	INIT_DELAYED_WORK(&psr->flush_work, psr_flush_handler);
-	mutex_init(&psr->lock);
-
-	psr->inhibit_count = 1;
-	psr->enabled = false;
-	psr->encoder = encoder;
-	psr->set = psr_set;
-
-	mutex_lock(&drm_drv->psr_list_lock);
-	list_add_tail(&psr->list, &drm_drv->psr_list);
-	mutex_unlock(&drm_drv->psr_list_lock);
-
-	return 0;
-}
-EXPORT_SYMBOL(rockchip_drm_psr_register);
-
-/**
- * rockchip_drm_psr_unregister - unregister encoder to psr driver
- * @encoder: encoder that obtain the PSR function
- * @psr_set: call back to set PSR state
- *
- * It is expected that the PSR inhibit counter is 1 when this function is
- * called, which corresponds to a state when related encoder has been
- * disconnected from any CRTCs and its driver called
- * rockchip_drm_psr_inhibit_get() to stop the PSR logic.
- *
- * Returns:
- * Zero on success, negative errno on failure.
- */
-void rockchip_drm_psr_unregister(struct drm_encoder *encoder)
-{
-	struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
-	struct psr_drv *psr, *n;
-
-	mutex_lock(&drm_drv->psr_list_lock);
-	list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
-		if (psr->encoder == encoder) {
-			/*
-			 * Any other value would mean that the encoder
-			 * is still in use.
-			 */
-			WARN_ON(psr->inhibit_count != 1);
-
-			list_del(&psr->list);
-			kfree(psr);
-		}
-	}
-	mutex_unlock(&drm_drv->psr_list_lock);
-}
-EXPORT_SYMBOL(rockchip_drm_psr_unregister);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h b/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
deleted file mode 100644
index 25350ba3237b..000000000000
--- a/drivers/gpu/drm/rockchip/rockchip_drm_psr.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
- * Author: Yakir Yang <ykk@rock-chips.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#ifndef __ROCKCHIP_DRM_PSR___
-#define __ROCKCHIP_DRM_PSR___
-
-void rockchip_drm_psr_flush_all(struct drm_device *dev);
-
-int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder);
-int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder);
-
-void rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state);
-void rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state);
-
-int rockchip_drm_psr_register(struct drm_encoder *encoder,
-			int (*psr_set)(struct drm_encoder *, bool enable));
-void rockchip_drm_psr_unregister(struct drm_encoder *encoder);
-
-#endif /* __ROCKCHIP_DRM_PSR__ */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 9254747ef65b..45a38a332827 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -21,6 +21,7 @@
 #include <drm/drm_gem_framebuffer_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_probe_helper.h>
+#include <drm/drm_self_refresh_helper.h>
 #ifdef CONFIG_DRM_ANALOGIX_DP
 #include <drm/bridge/analogix_dp.h>
 #endif
@@ -42,10 +43,11 @@
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_gem.h"
 #include "rockchip_drm_fb.h"
-#include "rockchip_drm_psr.h"
 #include "rockchip_drm_vop.h"
 #include "rockchip_rgb.h"
 
+#define VOP_SELF_REFRESH_ENTRY_DELAY_MS 100
+
 #define VOP_WIN_SET(vop, win, name, v) \
 		vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name)
 #define VOP_SCL_SET(vop, win, name, v) \
@@ -541,7 +543,7 @@ static void vop_core_clks_disable(struct vop *vop)
 	clk_disable(vop->hclk);
 }
 
-static int vop_enable(struct drm_crtc *crtc)
+static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
 {
 	struct vop *vop = to_vop(crtc);
 	int ret, i;
@@ -581,12 +583,18 @@ static int vop_enable(struct drm_crtc *crtc)
 	 * We need to make sure that all windows are disabled before we
 	 * enable the crtc. Otherwise we might try to scan from a destroyed
 	 * buffer later.
+	 *
+	 * In the case of enable-after-PSR, we don't need to worry about this
+	 * case since the buffer is guaranteed to be valid and disabling the
+	 * window will result in screen glitches on PSR exit.
 	 */
-	for (i = 0; i < vop->data->win_size; i++) {
-		struct vop_win *vop_win = &vop->win[i];
-		const struct vop_win_data *win = vop_win->data;
+	if (!old_state || !old_state->self_refresh_active) {
+		for (i = 0; i < vop->data->win_size; i++) {
+			struct vop_win *vop_win = &vop->win[i];
+			const struct vop_win_data *win = vop_win->data;
 
-		VOP_WIN_SET(vop, win, enable, 0);
+			VOP_WIN_SET(vop, win, enable, 0);
+		}
 	}
 	spin_unlock(&vop->reg_lock);
 
@@ -937,12 +945,10 @@ static void vop_plane_atomic_async_update(struct drm_plane *plane,
 	}
 
 	if (vop->is_enabled) {
-		rockchip_drm_psr_inhibit_get_state(new_state->state);
 		vop_plane_atomic_update(plane, plane->state);
 		spin_lock(&vop->reg_lock);
 		vop_cfg_done(vop);
 		spin_unlock(&vop->reg_lock);
-		rockchip_drm_psr_inhibit_put_state(new_state->state);
 	}
 
 	plane->funcs->atomic_destroy_state(plane, plane_state);
@@ -1036,7 +1042,7 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
 
 	WARN_ON(vop->event);
 
-	ret = vop_enable(crtc);
+	ret = vop_enable(crtc, old_state);
 	if (ret) {
 		mutex_unlock(&vop->vop_lock);
 		DRM_DEV_ERROR(vop->dev, "Failed to enable vop (%d)\n", ret);
@@ -1518,6 +1524,13 @@ static int vop_create_crtc(struct vop *vop)
 	init_completion(&vop->line_flag_completion);
 	crtc->port = port;
 
+	ret = drm_self_refresh_helper_register(crtc,
+					       VOP_SELF_REFRESH_ENTRY_DELAY_MS);
+	if (ret)
+		DRM_DEV_DEBUG_KMS(vop->dev,
+			"Failed to register %s with SR helpers %d, ignoring\n",
+			crtc->name, ret);
+
 	return 0;
 
 err_cleanup_crtc:
@@ -1535,6 +1548,8 @@ static void vop_destroy_crtc(struct vop *vop)
 	struct drm_device *drm_dev = vop->drm_dev;
 	struct drm_plane *plane, *tmp;
 
+	drm_self_refresh_helper_unregister(crtc);
+
 	of_node_put(crtc->port);
 
 	/*
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 475b706b49de..7c5c13803673 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -42,10 +42,6 @@ struct analogix_dp_plat_data {
 			 struct drm_connector *);
 };
 
-int analogix_dp_psr_enabled(struct analogix_dp_device *dp);
-int analogix_dp_enable_psr(struct analogix_dp_device *dp);
-int analogix_dp_disable_psr(struct analogix_dp_device *dp);
-
 int analogix_dp_resume(struct analogix_dp_device *dp);
 int analogix_dp_suspend(struct analogix_dp_device *dp);
 
-- 
Sean Paul, Software Engineer, Google / Chromium OS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 09/10] drm/rockchip: Don't fully disable vop on self refresh
       [not found] <20190502194956.218441-1-sean@poorly.run>
                   ` (7 preceding siblings ...)
  2019-05-02 19:49 ` [PATCH v3 08/10] drm/rockchip: Use the helpers for PSR Sean Paul
@ 2019-05-02 19:49 ` Sean Paul
  2019-05-02 19:49 ` [PATCH v3 10/10] drm/rockchip: Use drm_atomic_helper_commit_tail_rpm Sean Paul
  9 siblings, 0 replies; 29+ messages in thread
From: Sean Paul @ 2019-05-02 19:49 UTC (permalink / raw)
  To: dri-devel
  Cc: Sean Paul, Zain Wang, Tomasz Figa, Kristian H . Kristensen,
	Sandy Huang, Heiko Stübner, David Airlie, Daniel Vetter,
	linux-arm-kernel, linux-rockchip, linux-kernel

From: Sean Paul <seanpaul@chromium.org>

Instead of fully disabling and re-enabling the vop on self refresh
transitions, only disable the active windows. This will speed up
self refresh exits substantially and is still a power-savings win.

This patch integrates portions of Zain's patch from here:
https://patchwork.kernel.org/patch/9615063/

Changes in v2:
- None
Changes in v3:
- None

Link to v1: https://patchwork.freedesktop.org/patch/msgid/20190228210939.83386-5-sean@poorly.run
Link to v2: https://patchwork.freedesktop.org/patch/msgid/20190326204509.96515-4-sean@poorly.run

Cc: Zain Wang <wzz@rock-chips.com>
Cc: Tomasz Figa <tfiga@chromium.org>
Cc: Kristian H. Kristensen <hoegsberg@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 38 +++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 45a38a332827..d171d90418c8 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -134,6 +134,7 @@ struct vop {
 	bool is_enabled;
 
 	struct completion dsp_hold_completion;
+	unsigned int win_enabled;
 
 	/* protected by dev->event_lock */
 	struct drm_pending_vblank_event *event;
@@ -594,6 +595,7 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
 			const struct vop_win_data *win = vop_win->data;
 
 			VOP_WIN_SET(vop, win, enable, 0);
+			vop->win_enabled &= ~BIT(i);
 		}
 	}
 	spin_unlock(&vop->reg_lock);
@@ -624,6 +626,25 @@ static int vop_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state)
 	return ret;
 }
 
+static void rockchip_drm_set_win_enabled(struct drm_crtc *crtc, bool enabled)
+{
+        struct vop *vop = to_vop(crtc);
+        int i;
+
+        spin_lock(&vop->reg_lock);
+
+        for (i = 0; i < vop->data->win_size; i++) {
+                struct vop_win *vop_win = &vop->win[i];
+                const struct vop_win_data *win = vop_win->data;
+
+                VOP_WIN_SET(vop, win, enable,
+                            enabled && (vop->win_enabled & BIT(i)));
+        }
+        vop_cfg_done(vop);
+
+        spin_unlock(&vop->reg_lock);
+}
+
 static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
 				    struct drm_crtc_state *old_state)
 {
@@ -631,9 +652,15 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
 
 	WARN_ON(vop->event);
 
+	if (crtc->state->self_refresh_active)
+		rockchip_drm_set_win_enabled(crtc, false);
+
 	mutex_lock(&vop->vop_lock);
 	drm_crtc_vblank_off(crtc);
 
+	if (crtc->state->self_refresh_active)
+		goto out;
+
 	/*
 	 * Vop standby will take effect at end of current frame,
 	 * if dsp hold valid irq happen, it means standby complete.
@@ -664,6 +691,8 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
 	clk_disable(vop->dclk);
 	vop_core_clks_disable(vop);
 	pm_runtime_put(vop->dev);
+
+out:
 	mutex_unlock(&vop->vop_lock);
 
 	if (crtc->state->event && !crtc->state->active) {
@@ -744,6 +773,7 @@ static void vop_plane_atomic_disable(struct drm_plane *plane,
 	spin_lock(&vop->reg_lock);
 
 	VOP_WIN_SET(vop, win, enable, 0);
+	vop->win_enabled &= ~BIT(VOP_WIN_TO_INDEX(vop_win));
 
 	spin_unlock(&vop->reg_lock);
 }
@@ -882,6 +912,7 @@ static void vop_plane_atomic_update(struct drm_plane *plane,
 	}
 
 	VOP_WIN_SET(vop, win, enable, 1);
+	vop->win_enabled |= BIT(win_index);
 	spin_unlock(&vop->reg_lock);
 }
 
@@ -1038,6 +1069,12 @@ static void vop_crtc_atomic_enable(struct drm_crtc *crtc,
 	int dither_bpc = s->output_bpc ? s->output_bpc : 10;
 	int ret;
 
+	if (old_state && old_state->self_refresh_active) {
+		drm_crtc_vblank_on(crtc);
+		rockchip_drm_set_win_enabled(crtc, true);
+		return;
+	}
+
 	mutex_lock(&vop->vop_lock);
 
 	WARN_ON(vop->event);
@@ -1648,6 +1685,7 @@ static int vop_initial(struct vop *vop)
 		VOP_WIN_SET(vop, win, channel, (channel + 1) << 4 | channel);
 		VOP_WIN_SET(vop, win, enable, 0);
 		VOP_WIN_SET(vop, win, gate, 1);
+		vop->win_enabled &= ~BIT(i);
 	}
 
 	vop_cfg_done(vop);
-- 
Sean Paul, Software Engineer, Google / Chromium OS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v3 10/10] drm/rockchip: Use drm_atomic_helper_commit_tail_rpm
       [not found] <20190502194956.218441-1-sean@poorly.run>
                   ` (8 preceding siblings ...)
  2019-05-02 19:49 ` [PATCH v3 09/10] drm/rockchip: Don't fully disable vop on self refresh Sean Paul
@ 2019-05-02 19:49 ` Sean Paul
  9 siblings, 0 replies; 29+ messages in thread
From: Sean Paul @ 2019-05-02 19:49 UTC (permalink / raw)
  To: dri-devel
  Cc: Sean Paul, Zain Wang, Tomasz Figa, Sandy Huang,
	Heiko Stübner, David Airlie, Daniel Vetter,
	linux-arm-kernel, linux-rockchip, linux-kernel

From: Sean Paul <seanpaul@chromium.org>

Now that we use the drm psr helpers, we no longer need to hand-roll our
atomic_commit_tail implementation. So use the helper

Changes in v2:
- None
Changes in v3:
- None

Link to v1: https://patchwork.freedesktop.org/patch/msgid/20190228210939.83386-6-sean@poorly.run
Link to v2: https://patchwork.freedesktop.org/patch/msgid/20190326204509.96515-5-sean@poorly.run

Cc: Zain Wang <wzz@rock-chips.com>
Cc: Tomasz Figa <tfiga@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 21 +--------------------
 1 file changed, 1 insertion(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 214064d599ee..1c63d9e833bc 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -117,27 +117,8 @@ rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
 	return ERR_PTR(ret);
 }
 
-static void
-rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
-{
-	struct drm_device *dev = old_state->dev;
-
-	drm_atomic_helper_commit_modeset_disables(dev, old_state);
-
-	drm_atomic_helper_commit_modeset_enables(dev, old_state);
-
-	drm_atomic_helper_commit_planes(dev, old_state,
-					DRM_PLANE_COMMIT_ACTIVE_ONLY);
-
-	drm_atomic_helper_commit_hw_done(old_state);
-
-	drm_atomic_helper_wait_for_vblanks(dev, old_state);
-
-	drm_atomic_helper_cleanup_planes(dev, old_state);
-}
-
 static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
-	.atomic_commit_tail = rockchip_atomic_helper_commit_tail_rpm,
+	.atomic_commit_tail = drm_atomic_helper_commit_tail_rpm,
 };
 
 static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
-- 
Sean Paul, Software Engineer, Google / Chromium OS


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 05/10] drm: Add helpers to kick off self refresh mode in drivers
  2019-05-02 19:49 ` [PATCH v3 05/10] drm: Add helpers to kick off self refresh mode in drivers Sean Paul
@ 2019-05-03  7:36   ` Daniel Vetter
  0 siblings, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2019-05-03  7:36 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Sean Paul, Daniel Vetter, Jose Souza, Zain Wang,
	Tomasz Figa, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, David Airlie, Jonathan Corbet,
	linux-doc, linux-kernel

On Thu, May 02, 2019 at 03:49:47PM -0400, Sean Paul wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch adds a new drm helper library to help drivers implement
> self refresh. Drivers choosing to use it will register crtcs and
> will receive callbacks when it's time to enter or exit self refresh
> mode.
> 
> In its current form, it has a timer which will trigger after a
> driver-specified amount of inactivity. When the timer triggers, the
> helpers will submit a new atomic commit to shut the refreshing pipe
> off. On the next atomic commit, the drm core will revert the self
> refresh state and bring everything back up to be actively driven.
> 
> From the driver's perspective, this works like a regular disable/enable
> cycle. The driver need only check the 'self_refresh_active' state in
> crtc_state. It should initiate self refresh mode on the panel and enter
> an off or low-power state.
> 
> Changes in v2:
> - s/psr/self_refresh/ (Daniel)
> - integrated the psr exit into the commit that wakes it up (Jose/Daniel)
> - made the psr state per-crtc (Jose/Daniel)
> Changes in v3:
> - Remove the self_refresh_(active|changed) from connector state (Daniel)
> - Simplify loop in drm_self_refresh_helper_alter_state (Daniel)
> - Improve self_refresh_aware comment (Daniel)
> - s/self_refresh_state/self_refresh_data/ (Daniel)
> 
> Link to v1: https://patchwork.freedesktop.org/patch/msgid/20190228210939.83386-2-sean@poorly.run
> Link to v2: https://patchwork.freedesktop.org/patch/msgid/20190326204509.96515-1-sean@poorly.run
> 
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: Jose Souza <jose.souza@intel.com>
> Cc: Zain Wang <wzz@rock-chips.com>
> Cc: Tomasz Figa <tfiga@chromium.org>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>

lgtm now, thanks a lot for sticking with this! Surprising lots of corner
cases I had to learn about and figure out what to best do with them.

> ---
>  Documentation/gpu/drm-kms-helpers.rst     |   9 +
>  drivers/gpu/drm/Makefile                  |   2 +-
>  drivers/gpu/drm/drm_atomic.c              |   2 +
>  drivers/gpu/drm/drm_atomic_helper.c       |  35 +++-
>  drivers/gpu/drm/drm_atomic_state_helper.c |   4 +
>  drivers/gpu/drm/drm_atomic_uapi.c         |   7 +-
>  drivers/gpu/drm/drm_self_refresh_helper.c | 205 ++++++++++++++++++++++
>  include/drm/drm_atomic.h                  |  15 ++
>  include/drm/drm_connector.h               |  14 ++
>  include/drm/drm_crtc.h                    |  19 ++
>  include/drm/drm_self_refresh_helper.h     |  22 +++
>  11 files changed, 329 insertions(+), 5 deletions(-)
>  create mode 100644 drivers/gpu/drm/drm_self_refresh_helper.c
>  create mode 100644 include/drm/drm_self_refresh_helper.h
> 
> diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
> index 14102ae035dc..d8a13c6b4db3 100644
> --- a/Documentation/gpu/drm-kms-helpers.rst
> +++ b/Documentation/gpu/drm-kms-helpers.rst
> @@ -113,6 +113,15 @@ format Helper Functions Reference
>  .. kernel-doc:: drivers/gpu/drm/drm_format_helper.c
>     :export:
>  
> +Panel Self Refresh Helper Reference
> +===================================
> +
> +.. kernel-doc:: drivers/gpu/drm/drm_self_refresh_helper.c
> +   :doc: overview
> +
> +.. kernel-doc:: drivers/gpu/drm/drm_self_refresh_helper.c
> +   :export:

I think this isn't the best place to insert the self refresh helpers. I'd
put them right below panel helpers, together with the other sink related
stuff. I think fits much better there than between the format and gem
helpers ...

> +
>  Framebuffer CMA Helper Functions Reference
>  ==========================================
>  
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 3d0c75cd687c..c4852604fc1d 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -39,7 +39,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
>  		drm_simple_kms_helper.o drm_modeset_helper.o \
>  		drm_scdc_helper.o drm_gem_framebuffer_helper.o \
>  		drm_atomic_state_helper.o drm_damage_helper.o \
> -		drm_format_helper.o
> +		drm_format_helper.o drm_self_refresh_helper.o
>  
>  drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
>  drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 5eb40130fafb..4449956241f2 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -379,6 +379,7 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p,
>  	drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name);
>  	drm_printf(p, "\tenable=%d\n", state->enable);
>  	drm_printf(p, "\tactive=%d\n", state->active);
> +	drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active);
>  	drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed);
>  	drm_printf(p, "\tmode_changed=%d\n", state->mode_changed);
>  	drm_printf(p, "\tactive_changed=%d\n", state->active_changed);
> @@ -881,6 +882,7 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
>  
>  	drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name);
>  	drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
> +	drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware);
>  
>  	if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
>  		if (state->writeback_job && state->writeback_job->fb)
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index fa5a367507c1..3c26f04cd6b8 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -30,6 +30,7 @@
>  #include <drm/drm_atomic_uapi.h>
>  #include <drm/drm_plane_helper.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_self_refresh_helper.h>
>  #include <drm/drm_writeback.h>
>  #include <drm/drm_damage_helper.h>
>  #include <linux/dma-fence.h>
> @@ -950,10 +951,33 @@ int drm_atomic_helper_check(struct drm_device *dev,
>  	if (state->legacy_cursor_update)
>  		state->async_update = !drm_atomic_helper_async_check(dev, state);
>  
> +	drm_self_refresh_helper_alter_state(state);
> +
>  	return ret;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_check);
>  
> +static bool
> +crtc_needs_disable(struct drm_crtc_state *old_state,
> +		   struct drm_crtc_state *new_state)
> +{
> +	/*
> +	 * No new_state means the crtc is off, so the only criteria is whether
> +	 * it's currently active or in self refresh mode.
> +	 */
> +	if (!new_state)
> +		return drm_atomic_crtc_effectively_active(old_state);
> +
> +	/*
> +	 * We need to run through the crtc_funcs->disable() function if the crtc
> +	 * is currently on, if it's transitioning to self refresh mode, or if
> +	 * it's in self refresh mode and needs to be fully disabled.
> +	 */
> +	return old_state->active ||
> +	       (old_state->self_refresh_active && !new_state->enable) ||
> +	       new_state->self_refresh_active;
> +}
> +
>  static void
>  disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  {
> @@ -974,7 +998,14 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  
>  		old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc);
>  
> -		if (!old_crtc_state->active ||
> +		if (new_conn_state->crtc)
> +			new_crtc_state = drm_atomic_get_new_crtc_state(
> +						old_state,
> +						new_conn_state->crtc);
> +		else
> +			new_crtc_state = NULL;
> +
> +		if (!crtc_needs_disable(old_crtc_state, new_crtc_state) ||
>  		    !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state))
>  			continue;
>  
> @@ -1020,7 +1051,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  		if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
>  			continue;
>  
> -		if (!old_crtc_state->active)
> +		if (!crtc_needs_disable(old_crtc_state, new_crtc_state))
>  			continue;
>  
>  		funcs = crtc->helper_private;
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c
> index ac929f68ff31..ca18008043e5 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -128,6 +128,10 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
>  	state->commit = NULL;
>  	state->event = NULL;
>  	state->pageflip_flags = 0;
> +
> +	/* Self refresh should be canceled when a new update is available */
> +	state->active = drm_atomic_crtc_effectively_active(state);
> +	state->self_refresh_active = false;
>  }
>  EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
>  
> diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> index ea797d4c82ee..a75c633ff0c0 100644
> --- a/drivers/gpu/drm/drm_atomic_uapi.c
> +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> @@ -490,7 +490,7 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
>  	struct drm_mode_config *config = &dev->mode_config;
>  
>  	if (property == config->prop_active)
> -		*val = state->active;
> +		*val = drm_atomic_crtc_effectively_active(state);
>  	else if (property == config->prop_mode_id)
>  		*val = (state->mode_blob) ? state->mode_blob->base.id : 0;
>  	else if (property == config->prop_vrr_enabled)
> @@ -772,7 +772,10 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
>  	if (property == config->prop_crtc_id) {
>  		*val = (state->crtc) ? state->crtc->base.id : 0;
>  	} else if (property == config->dpms_property) {
> -		*val = connector->dpms;
> +		if (state->crtc && state->crtc->state->self_refresh_active)
> +			*val = DRM_MODE_DPMS_ON;
> +		else
> +			*val = connector->dpms;
>  	} else if (property == config->tv_select_subconnector_property) {
>  		*val = state->tv.subconnector;
>  	} else if (property == config->tv_left_margin_property) {
> diff --git a/drivers/gpu/drm/drm_self_refresh_helper.c b/drivers/gpu/drm/drm_self_refresh_helper.c
> new file mode 100644
> index 000000000000..f46e7639d277
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_self_refresh_helper.c
> @@ -0,0 +1,205 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright (C) 2019 Google, Inc.
> + *
> + * Authors:
> + * Sean Paul <seanpaul@chromium.org>
> + */
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_connector.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_device.h>
> +#include <drm/drm_mode_config.h>
> +#include <drm/drm_modeset_lock.h>
> +#include <drm/drm_print.h>
> +#include <drm/drm_self_refresh_helper.h>
> +#include <linux/bitops.h>
> +#include <linux/slab.h>
> +#include <linux/workqueue.h>
> +
> +/**
> + * DOC: overview
> + *
> + * This helper library provides an easy way for drivers to leverage the atomic
> + * framework to implement panel self refresh (SR) support. Drivers are
> + * responsible for registering and unregistering the SR helpers on load/unload.

I think better if you mention that you both need to set up the CRTC (using
the init/cleanup functions), and also the connector (by setting
&drm_connector.self_refresh_aware).
> + *
> + * Once a crtc has enabled SR, the helpers will monitor activity and
> + * call back into the driver to enable/disable SR as appropriate. The best way
> + * to think about this is that it's a DPMS on/off request with a flag set in
> + * state that tells you to disable/enable SR on the panel instead of power-
> + * cycling it.
> + *
> + * Drivers may choose to fully disable their crtc/encoder/bridge hardware, or
> + * they can use the "self_refresh_active" flags in crtc state if they want to
> + * enter low power mode without full disable (in case full disable/enable is too
> + * slow).
> + *
> + * SR will be deactivated if there are any atomic updates affecting the
> + * pipe that is in SR mode. If a crtc is driving multiple connectors, all
> + * connectors must be SR aware and all will enter SR mode.

I think the above text would be more useful if you spice it up with links
to the relevant functions (init/cleanup and alter_state) plus what to look
at, i.e. &drm_crtc_state.self_refresh_active.

> + */
> +
> +struct drm_self_refresh_data {
> +	struct drm_crtc *crtc;
> +	struct delayed_work entry_work;
> +	struct drm_atomic_state *save_state;
> +	unsigned int entry_delay_ms;
> +};
> +
> +static void drm_self_refresh_helper_entry_work(struct work_struct *work)
> +{
> +	struct drm_self_refresh_data *sr_data = container_of(
> +				to_delayed_work(work),
> +				struct drm_self_refresh_data, entry_work);
> +	struct drm_crtc *crtc = sr_data->crtc;
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_modeset_acquire_ctx ctx;
> +	struct drm_atomic_state *state;
> +	struct drm_connector *conn;
> +	struct drm_connector_state *conn_state;
> +	struct drm_crtc_state *crtc_state;
> +	int i, ret;
> +
> +	drm_modeset_acquire_init(&ctx, 0);
> +
> +	state = drm_atomic_state_alloc(dev);
> +	if (!state) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +
> +retry:
> +	state->acquire_ctx = &ctx;
> +
> +	crtc_state = drm_atomic_get_crtc_state(state, crtc);
> +	if (IS_ERR(crtc_state)) {
> +		ret = PTR_ERR(crtc_state);
> +		goto out;
> +	}
> +
> +	if (!crtc_state->enable)
> +		goto out;
> +
> +	ret = drm_atomic_add_affected_connectors(state, crtc);
> +	if (ret)
> +		goto out;
> +
> +	for_each_new_connector_in_state(state, conn, conn_state, i) {
> +		if (!conn_state->self_refresh_aware)
> +			goto out;
> +	}
> +
> +	crtc_state->active = false;
> +	crtc_state->self_refresh_active = true;
> +
> +	ret = drm_atomic_commit(state);
> +	if (ret)
> +		goto out;
> +
> +out:
> +	if (ret == -EDEADLK) {
> +		drm_atomic_state_clear(state);
> +		ret = drm_modeset_backoff(&ctx);
> +		if (!ret)
> +			goto retry;
> +	}
> +
> +	drm_atomic_state_put(state);
> +	drm_modeset_drop_locks(&ctx);
> +	drm_modeset_acquire_fini(&ctx);
> +}
> +
> +/**
> + * drm_self_refresh_helper_alter_state - Alters the atomic state for SR exit
> + * @state: the state currently being checked
> + *
> + * Called at the end of atomic check. This function checks the state for flags
> + * incompatible with self refresh exit and changes them. This is a bit
> + * disingenuous since userspace is expecting one thing and we're giving it
> + * another. However in order to keep self refresh entirely hidden from
> + * userspace, this is required.
> + *
> + * At the end, we queue up the self refresh entry work so we can enter PSR after
> + * the desired delay.
> + */
> +void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state)
> +{
> +	struct drm_crtc *crtc;
> +	struct drm_crtc_state *crtc_state;
> +	int i;
> +
> +	if (state->async_update || !state->allow_modeset) {
> +		for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
> +			if (crtc_state->self_refresh_active) {
> +				state->async_update = false;
> +				state->allow_modeset = true;
> +				break;
> +			}
> +		}
> +	}
> +
> +	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
> +		struct drm_self_refresh_data *sr_data;
> +
> +		/* Don't trigger the entry timer when we're already in SR */
> +		if (crtc_state->self_refresh_active)
> +			continue;
> +
> +		sr_data = crtc->self_refresh_data;
> +		if (!sr_data)
> +			continue;
> +
> +		mod_delayed_work(system_wq, &sr_data->entry_work,
> +				 msecs_to_jiffies(sr_data->entry_delay_ms));
> +	}
> +}
> +EXPORT_SYMBOL(drm_self_refresh_helper_alter_state);
> +
> +/**
> + * drm_self_refresh_helper_register - Registers self refresh helpers for a crtc
> + * @crtc: the crtc which supports self refresh supported displays
> + * @entry_delay_ms: amount of inactivity to wait before entering self refresh
> + */
> +int drm_self_refresh_helper_register(struct drm_crtc *crtc,
> +				     unsigned int entry_delay_ms)
> +{

Bikeshed that I missed in previous rounds: _register/_unregister has
pretty clear meaning of "(un)publish an interface to userspace".
_init/_cleanup are the common ones.

> +	struct drm_self_refresh_data *sr_data = crtc->self_refresh_data;
> +
> +	/* Helper is already registered */
> +	if (WARN_ON(sr_data))
> +		return -EINVAL;
> +
> +	sr_data = kzalloc(sizeof(*sr_data), GFP_KERNEL);
> +	if (!sr_data)
> +		return -ENOMEM;
> +
> +	INIT_DELAYED_WORK(&sr_data->entry_work,
> +			  drm_self_refresh_helper_entry_work);
> +	sr_data->entry_delay_ms = entry_delay_ms;
> +	sr_data->crtc = crtc;
> +
> +	crtc->self_refresh_data = sr_data;
> +	return 0;
> +}
> +EXPORT_SYMBOL(drm_self_refresh_helper_register);
> +
> +/**
> + * drm_self_refresh_helper_unregister - Unregisters self refresh helpers
> + * @crtc: the crtc to unregister
> + */
> +void drm_self_refresh_helper_unregister(struct drm_crtc *crtc)
> +{
> +	struct drm_self_refresh_data *sr_data = crtc->self_refresh_data;
> +
> +	/* Helper is already unregistered */
> +	if (sr_data)
> +		return;
> +
> +	crtc->self_refresh_data = NULL;
> +
> +	cancel_delayed_work_sync(&sr_data->entry_work);
> +	kfree(sr_data);
> +}
> +EXPORT_SYMBOL(drm_self_refresh_helper_unregister);
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 824a5ed4e216..1e9cab1da97a 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -944,4 +944,19 @@ drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state)
>  	       state->connectors_changed;
>  }
>  
> +/**
> + * drm_atomic_crtc_effectively_active - compute whether crtc is actually active
> + * @state: &drm_crtc_state for the CRTC
> + *
> + * When in self refresh mode, the crtc_state->active value will be false, since
> + * the crtc is off. However in some cases we're interested in whether the crtc
> + * is active, or effectively active (ie: it's connected to an active display).
> + * In these cases, use this function instead of just checking active.
> + */
> +static inline bool
> +drm_atomic_crtc_effectively_active(const struct drm_crtc_state *state)
> +{
> +	return state->active || state->self_refresh_active;
> +}
> +
>  #endif /* DRM_ATOMIC_H_ */
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index 02a131202add..9b40eb6f0ef4 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -539,6 +539,20 @@ struct drm_connector_state {
>  	/** @tv: TV connector state */
>  	struct drm_tv_connector_state tv;
>  
> +	/**
> +	 * @self_refresh_aware:
> +	 *
> +	 * This tracks whether a connector is aware of the self refresh state.
> +	 * It should be set to true for those connector implementations which
> +	 * understand the self refresh state. This is needed since the crtc
> +	 * registers the self refresh helpers and it doesn't know if the
> +	 * connectors downstream have implemented self refresh entry/exit.
> +	 *
> +	 * Drivers should set this to true in atomic_check if they know how to
> +	 * handle self_refresh requests.
> +	 */
> +	bool self_refresh_aware;
> +
>  	/**
>  	 * @picture_aspect_ratio: Connector property to control the
>  	 * HDMI infoframe aspect ratio setting.
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 58ad983d7cd6..67e3075a8784 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -53,6 +53,7 @@ struct drm_mode_set;
>  struct drm_file;
>  struct drm_clip_rect;
>  struct drm_printer;
> +struct drm_self_refresh_data;
>  struct device_node;
>  struct dma_fence;
>  struct edid;
> @@ -299,6 +300,17 @@ struct drm_crtc_state {
>  	 */
>  	bool vrr_enabled;
>  
> +	/**
> +	 * @self_refresh_active:
> +	 *
> +	 * Used by the self refresh helpers to denote when a self refresh
> +	 * transition is occuring. This will be set on enable/disable callbacks
> +	 * when self refresh is being enabled or disabled. In some cases, it may
> +	 * not be desirable to fully shut off the crtc during self refresh.
> +	 * CRTC's can inspect this flag and determine the best course of action.
> +	 */
> +	bool self_refresh_active;
> +
>  	/**
>  	 * @event:
>  	 *
> @@ -1087,6 +1099,13 @@ struct drm_crtc {
>  	 * The name of the CRTC's fence timeline.
>  	 */
>  	char timeline_name[32];
> +
> +	/**
> +	 * @self_refresh_data: Holds the state for the self refresh helpers
> +	 *
> +	 * Initialized via drm_self_refresh_helper_register().
> +	 */
> +	struct drm_self_refresh_data *self_refresh_data;
>  };
>  
>  /**
> diff --git a/include/drm/drm_self_refresh_helper.h b/include/drm/drm_self_refresh_helper.h
> new file mode 100644
> index 000000000000..efb2e6e3249f
> --- /dev/null
> +++ b/include/drm/drm_self_refresh_helper.h
> @@ -0,0 +1,22 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright (C) 2019 Google, Inc.
> + *
> + * Authors:
> + * Sean Paul <seanpaul@chromium.org>
> + */
> +#ifndef DRM_SELF_REFRESH_HELPER_H_
> +#define DRM_SELF_REFRESH_HELPER_H_
> +
> +struct drm_atomic_state;
> +struct drm_connector;
> +struct drm_device;
> +struct drm_modeset_acquire_ctx;
> +
> +void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state);
> +
> +int drm_self_refresh_helper_register(struct drm_crtc *crtc,
> +				     unsigned int entry_delay_ms);
> +
> +void drm_self_refresh_helper_unregister(struct drm_crtc *crtc);
> +#endif

With the remaining nits addressed: Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 03/10] drm: Add atomic variants for bridge enable/disable
  2019-05-02 19:49 ` [PATCH v3 03/10] drm: Add atomic variants for bridge enable/disable Sean Paul
@ 2019-05-03  7:45   ` Daniel Vetter
  0 siblings, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2019-05-03  7:45 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Sean Paul, Daniel Vetter, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, David Airlie, linux-kernel

On Thu, May 02, 2019 at 03:49:45PM -0400, Sean Paul wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch adds atomic variants for all of
> pre_enable/enable/disable/post_disable bridge functions. These will be
> called from the appropriate atomic helper functions. If the bridge
> driver doesn't implement the atomic version of the function, we will
> fall back to the vanilla implementation.
> 
> Note that some drivers call drm_bridge_disable directly, and these cases
> are not covered. It's up to the driver to decide whether to implement
> both atomic_disable and disable, or if it's not necessary.
> 
> Changes in v3:
> - Added to the patchset
> 
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c |   8 +-
>  drivers/gpu/drm/drm_bridge.c        | 110 +++++++++++++++++++++++++++
>  include/drm/drm_bridge.h            | 114 ++++++++++++++++++++++++++++
>  3 files changed, 228 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 1f81ca8daad7..9d9e47276839 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -995,7 +995,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  		 * Each encoder has at most one connector (since we always steal
>  		 * it away), so we won't call disable hooks twice.
>  		 */
> -		drm_bridge_disable(encoder->bridge);
> +		drm_atomic_bridge_disable(encoder->bridge, old_state);
>  
>  		/* Right function depends upon target state. */
>  		if (funcs) {
> @@ -1009,7 +1009,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  				funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
>  		}
>  
> -		drm_bridge_post_disable(encoder->bridge);
> +		drm_atomic_bridge_post_disable(encoder->bridge, old_state);
>  	}
>  
>  	for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) {
> @@ -1308,7 +1308,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
>  		 * Each encoder has at most one connector (since we always steal
>  		 * it away), so we won't call enable hooks twice.
>  		 */
> -		drm_bridge_pre_enable(encoder->bridge);
> +		drm_atomic_bridge_pre_enable(encoder->bridge, old_state);
>  
>  		if (funcs) {
>  			if (funcs->atomic_enable)
> @@ -1319,7 +1319,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
>  				funcs->commit(encoder);
>  		}
>  
> -		drm_bridge_enable(encoder->bridge);
> +		drm_atomic_bridge_enable(encoder->bridge, old_state);
>  	}
>  
>  	drm_atomic_helper_commit_writebacks(dev, old_state);
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 138b2711d389..accccb586adf 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -352,6 +352,116 @@ void drm_bridge_enable(struct drm_bridge *bridge)
>  }
>  EXPORT_SYMBOL(drm_bridge_enable);
>  
> +/**
> + * drm_atomic_bridge_disable - disables all bridges in the encoder chain
> + * @bridge: bridge control structure
> + * @state: atomic state being committed
> + *
> + * Calls &drm_bridge_funcs.atomic_disable (falls back on
> + * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain,
> + * starting from the last bridge to the first. These are called before calling
> + * the encoder's prepare op.

Since this is for atomic, where &drm_encoder_helper_funcs.atomic_disable
is the recommened one, would be good to change that. Plus use the
hyperlinked form. Same for all the below.


> + *
> + * Note: the bridge passed should be the one closest to the encoder
> + */
> +void drm_atomic_bridge_disable(struct drm_bridge *bridge,
> +			       struct drm_atomic_state *state)
> +{
> +	if (!bridge)
> +		return;
> +
> +	drm_atomic_bridge_disable(bridge->next, state);
> +
> +	if (bridge->funcs->atomic_disable)
> +		bridge->funcs->atomic_disable(bridge, state);
> +	else if (bridge->funcs->disable)
> +		bridge->funcs->disable(bridge);
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_disable);
> +
> +/**
> + * drm_atomic_bridge_post_disable - cleans up after disabling all bridges in the
> + *				    encoder chain
> + * @bridge: bridge control structure
> + * @state: atomic state being committed
> + *
> + * Calls &drm_bridge_funcs.atomic_post_disable (falls back on
> + * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain,
> + * starting from the first bridge to the last. These are called after completing
> + * the encoder's prepare op.
> + *
> + * Note: the bridge passed should be the one closest to the encoder
> + */
> +void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
> +				    struct drm_atomic_state *state)
> +{
> +	if (!bridge)
> +		return;
> +
> +	if (bridge->funcs->atomic_post_disable)
> +		bridge->funcs->atomic_post_disable(bridge, state);
> +	else if (bridge->funcs->post_disable)
> +		bridge->funcs->post_disable(bridge);
> +
> +	drm_atomic_bridge_post_disable(bridge->next, state);
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_post_disable);
> +
> +/**
> + * drm_bridge_pre_enable - prepares for enabling all bridges in the encoder
> + *			   chain
> + * @bridge: bridge control structure
> + * @state: atomic state being committed
> + *
> + * Calls &drm_bridge_funcs.pre_enable (falls back on

atomic_pre_enable (I think all the others you've adjusted correctly).

> + * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain,
> + * starting from the last bridge to the first. These are called before calling
> + * the encoder's commit op.

&drm_encoder_helper_funcs.atomic_enable
> + *
> + * Note: the bridge passed should be the one closest to the encoder
> + */
> +void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
> +				  struct drm_atomic_state *state)
> +{
> +	if (!bridge)
> +		return;
> +
> +	drm_atomic_bridge_pre_enable(bridge->next, state);
> +
> +	if (bridge->funcs->atomic_pre_enable)
> +		bridge->funcs->atomic_pre_enable(bridge, state);
> +	else if (bridge->funcs->pre_enable)
> +		bridge->funcs->pre_enable(bridge);
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_pre_enable);
> +
> +/**
> + * drm_atomic_bridge_enable - enables all bridges in the encoder chain
> + * @bridge: bridge control structure
> + * @state: atomic state being committed
> + *
> + * Calls &drm_bridge_funcs.atomic_enable (falls back on
> + * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain,
> + * starting from the first bridge to the last. These are called after completing
> + * the encoder's commit op.
> + *
> + * Note: the bridge passed should be the one closest to the encoder
> + */
> +void drm_atomic_bridge_enable(struct drm_bridge *bridge,
> +			      struct drm_atomic_state *state)
> +{
> +	if (!bridge)
> +		return;
> +
> +	if (bridge->funcs->atomic_enable)
> +		bridge->funcs->atomic_enable(bridge, state);
> +	else if (bridge->funcs->enable)
> +		bridge->funcs->enable(bridge);
> +
> +	drm_atomic_bridge_enable(bridge->next, state);
> +}
> +EXPORT_SYMBOL(drm_atomic_bridge_enable);
> +
>  #ifdef CONFIG_OF
>  /**
>   * of_drm_find_bridge - find the bridge corresponding to the device node in
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index d4428913a4e1..86f436895c7b 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -237,6 +237,111 @@ struct drm_bridge_funcs {
>  	 * The enable callback is optional.
>  	 */
>  	void (*enable)(struct drm_bridge *bridge);
> +
> +	/**
> +	 * @atomic_pre_enable:
> +	 *
> +	 * This callback should enable the bridge. It is called right before
> +	 * the preceding element in the display pipe is enabled. If the
> +	 * preceding element is a bridge this means it's called before that
> +	 * bridge's @atomic_pre_enable or @pre_enable function. If the preceding
> +	 * element is a &drm_encoder it's called right before the encoder's
> +	 * &drm_encoder_helper_funcs.atomic_enable,
> +	 * &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or
> +	 * &drm_encoder_helper_funcs.dpms hook.

I woulnd't mention the depracated (for atomic drivers) hooks anymore, i.e.
drop commit, dpms, prepare in all these texts. Also makes it more
readable.

> +	 *
> +	 * The display pipe (i.e. clocks and timing signals) feeding this bridge
> +	 * will not yet be running when this callback is called. The bridge must
> +	 * not enable the display link feeding the next bridge in the chain (if
> +	 * there is one) when this callback is called.
> +	 *
> +	 * Note that this function will only be invoked in the context of an
> +	 * atomic commit. It will not be invoked from &drm_bridge_pre_enable. It
> +	 * would be prudent to also provide an implementation of @pre_enable if
> +	 * you are expecting driver calls into &drm_bridge_pre_enable.
> +	 *
> +	 * The @atomic_pre_enable callback is optional.
> +	 */
> +	void (*atomic_pre_enable)(struct drm_bridge *bridge,
> +				  struct drm_atomic_state *state);
> +
> +	/**
> +	 * @atomic_enable:
> +	 *
> +	 * This callback should enable the bridge. It is called right after
> +	 * the preceding element in the display pipe is enabled. If the
> +	 * preceding element is a bridge this means it's called after that
> +	 * bridge's @atomic_enable or @enable function. If the preceding element
> +	 * is a &drm_encoder it's called right after the encoder's
> +	 * &drm_encoder_helper_funcs.atomic_enable,
> +	 * &drm_encoder_helper_funcs.enable, &drm_encoder_helper_funcs.commit or
> +	 * &drm_encoder_helper_funcs.dpms hook.
> +	 *
> +	 * The bridge can assume that the display pipe (i.e. clocks and timing
> +	 * signals) feeding it is running when this callback is called. This
> +	 * callback must enable the display link feeding the next bridge in the
> +	 * chain if there is one.
> +	 *
> +	 * Note that this function will only be invoked in the context of an
> +	 * atomic commit. It will not be invoked from &drm_bridge_enable. It
> +	 * would be prudent to also provide an implementation of @enable if
> +	 * you are expecting driver calls into &drm_bridge_enable.
> +	 *
> +	 * The enable callback is optional.
> +	 */
> +	void (*atomic_enable)(struct drm_bridge *bridge,
> +			      struct drm_atomic_state *state);
> +	/**
> +	 * @atomic_disable:
> +	 *
> +	 * This callback should disable the bridge. It is called right before
> +	 * the preceding element in the display pipe is disabled. If the
> +	 * preceding element is a bridge this means it's called before that
> +	 * bridge's @atomic_disable or @disable vfunc. If the preceding element
> +	 * is a &drm_encoder it's called right before the
> +	 * &drm_encoder_helper_funcs.atomic_disable,
> +	 * &drm_encoder_helper_funcs.disable, &drm_encoder_helper_funcs.prepare
> +	 * or &drm_encoder_helper_funcs.dpms hook.
> +	 *
> +	 * The bridge can assume that the display pipe (i.e. clocks and timing
> +	 * signals) feeding it is still running when this callback is called.
> +	 *
> +	 * Note that this function will only be invoked in the context of an
> +	 * atomic commit. It will not be invoked from &drm_bridge_disable. It
> +	 * would be prudent to also provide an implementation of @disable if
> +	 * you are expecting driver calls into &drm_bridge_disable.
> +	 *
> +	 * The disable callback is optional.
> +	 */
> +	void (*atomic_disable)(struct drm_bridge *bridge,
> +			       struct drm_atomic_state *state);
> +
> +	/**
> +	 * @atomic_post_disable:
> +	 *
> +	 * This callback should disable the bridge. It is called right after the
> +	 * preceding element in the display pipe is disabled. If the preceding
> +	 * element is a bridge this means it's called after that bridge's
> +	 * @atomic_post_disable or @post_disable function. If the preceding
> +	 * element is a &drm_encoder it's called right after the encoder's
> +	 * &drm_encoder_helper_funcs.atomic_disable,
> +	 * &drm_encoder_helper_funcs.disable, &drm_encoder_helper_funcs.prepare
> +	 * or &drm_encoder_helper_funcs.dpms hook.
> +	 *
> +	 * The bridge must assume that the display pipe (i.e. clocks and timing
> +	 * singals) feeding it is no longer running when this callback is
> +	 * called.
> +	 *
> +	 * Note that this function will only be invoked in the context of an
> +	 * atomic commit. It will not be invoked from &drm_bridge_post_disable.
> +	 * It would be prudent to also provide an implementation of
> +	 * @post_disable if you are expecting driver calls into
> +	 * &drm_bridge_post_disable.
> +	 *
> +	 * The post_disable callback is optional.
> +	 */
> +	void (*atomic_post_disable)(struct drm_bridge *bridge,
> +				    struct drm_atomic_state *state);
>  };
>  
>  /**
> @@ -314,6 +419,15 @@ void drm_bridge_mode_set(struct drm_bridge *bridge,
>  void drm_bridge_pre_enable(struct drm_bridge *bridge);
>  void drm_bridge_enable(struct drm_bridge *bridge);
>  
> +void drm_atomic_bridge_disable(struct drm_bridge *bridge,
> +			       struct drm_atomic_state *state);
> +void drm_atomic_bridge_post_disable(struct drm_bridge *bridge,
> +				    struct drm_atomic_state *state);
> +void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge,
> +				  struct drm_atomic_state *state);
> +void drm_atomic_bridge_enable(struct drm_bridge *bridge,
> +			      struct drm_atomic_state *state);
> +
>  #ifdef CONFIG_DRM_PANEL_BRIDGE
>  struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel,
>  					u32 connector_type);
> -- 
> Sean Paul, Software Engineer, Google / Chromium OS

With the doc nits:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 01/10] drm: Add atomic variants of enable/disable to encoder helper funcs
  2019-05-02 19:49 ` [PATCH v3 01/10] drm: Add atomic variants of enable/disable to encoder helper funcs Sean Paul
@ 2019-05-03  7:51   ` Daniel Vetter
  2019-05-03 12:34     ` Sean Paul
  0 siblings, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2019-05-03  7:51 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Sean Paul, Daniel Vetter, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, David Airlie, linux-kernel

On Thu, May 02, 2019 at 03:49:43PM -0400, Sean Paul wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch adds atomic_enable and atomic_disable callbacks to the
> encoder helpers. This will allow encoders to make informed decisions in
> their start-up/shutdown based on the committed state.
> 
> Aside from the new hooks, this patch also introduces the new signature
> for .atomic_* functions going forward. Instead of passing object state
> (well, encoders don't have atomic state, but let's ignore that), we pass
> the entire atomic state so the driver can inspect more than what's
> happening locally.
> 
> This is particularly important for the upcoming self refresh helpers.
> 
> Changes in v3:
> - Added patch to the set
> 
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c      |  6 +++-
>  include/drm/drm_modeset_helper_vtables.h | 45 ++++++++++++++++++++++++
>  2 files changed, 50 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 553415fe8ede..71cc7d6b0644 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -1001,6 +1001,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  		if (funcs) {
>  			if (new_conn_state->crtc && funcs->prepare)
>  				funcs->prepare(encoder);
> +			else if (funcs->atomic_disable)
> +				funcs->atomic_disable(encoder, old_state);

I'd put the atomic one first. The reason why ->disable here is later is
that ->disable has some really funky meaning in the old legacy crtc
helpers, and hence ->prepare was preferrable: Legacy ->disable also was
supposed to release resources (something we now do in
->atomic_destroy_state). See the huge NOTE: in the @disable kerneldoc.


>  			else if (funcs->disable)
>  				funcs->disable(encoder);
>  			else if (funcs->dpms)
> @@ -1309,7 +1311,9 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev,
>  		drm_bridge_pre_enable(encoder->bridge);
>  
>  		if (funcs) {
> -			if (funcs->enable)
> +			if (funcs->atomic_enable)
> +				funcs->atomic_enable(encoder, old_state);
> +			else if (funcs->enable)
>  				funcs->enable(encoder);
>  			else if (funcs->commit)
>  				funcs->commit(encoder);
> diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> index 8f3602811eb5..de57fb40cb6e 100644
> --- a/include/drm/drm_modeset_helper_vtables.h
> +++ b/include/drm/drm_modeset_helper_vtables.h
> @@ -675,6 +675,51 @@ struct drm_encoder_helper_funcs {
>  	enum drm_connector_status (*detect)(struct drm_encoder *encoder,
>  					    struct drm_connector *connector);
>  
> +	/**
> +	 * @atomic_disable:
> +	 *
> +	 * This callback should be used to disable the encoder. With the atomic
> +	 * drivers it is called before this encoder's CRTC has been shut off
> +	 * using their own &drm_crtc_helper_funcs.atomic_disable hook. If that
> +	 * sequence is too simple drivers can just add their own driver private
> +	 * encoder hooks and call them from CRTC's callback by looping over all
> +	 * encoders connected to it using for_each_encoder_on_crtc().
> +	 *
> +	 * This callback is a variant of @disable that provides the atomic state
> +	 * to the driver. It takes priority over @disable during atomic commits.
> +	 *
> +	 * This hook is used only by atomic helpers. Atomic drivers don't need
> +	 * to implement it if there's no need to disable anything at the encoder
> +	 * level. To ensure that runtime PM handling (using either DPMS or the
> +	 * new "ACTIVE" property) works @atomic_disable must be the inverse of
> +	 * @atomic_enable.
> +	 */

I'd add something like "For atomic drivers also consider @atomic_disable"
to the kerneldoc of @disable (before the NOTE: which is only relevant for
pre-atomic). Same for the enable side.

> +	void (*atomic_disable)(struct drm_encoder *encoder,
> +			       struct drm_atomic_state *state);
> +
> +	/**
> +	 * @atomic_enable:
> +	 *
> +	 * This callback should be used to enable the encoder. It is called
> +	 * after this encoder's CRTC has been enabled using their own
> +	 * &drm_crtc_helper_funcs.atomic_enable hook. If that sequence is
> +	 * too simple drivers can just add their own driver private encoder
> +	 * hooks and call them from CRTC's callback by looping over all encoders
> +	 * connected to it using for_each_encoder_on_crtc().
> +	 *
> +	 * This callback is a variant of @enable that provides the atomic state
> +	 * to the driver. It is called in place of @enable during atomic
> +	 * commits.

needs to be adjusted here for "takes priority".
> +	 *
> +	 * This hook is used only by atomic helpers, for symmetry with @disable.
> +	 * Atomic drivers don't need to implement it if there's no need to
> +	 * enable anything at the encoder level. To ensure that runtime PM
> +	 * handling (using either DPMS or the new "ACTIVE" property) works
> +	 * @enable must be the inverse of @disable for atomic drivers.
> +	 */
> +	void (*atomic_enable)(struct drm_encoder *encoder,
> +			      struct drm_atomic_state *state);
> +

With the nits:

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

>  	/**
>  	 * @disable:
>  	 *
> -- 
> Sean Paul, Software Engineer, Google / Chromium OS
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 02/10] drm: Add drm_atomic_crtc_state_for_encoder helper
  2019-05-02 19:49 ` [PATCH v3 02/10] drm: Add drm_atomic_crtc_state_for_encoder helper Sean Paul
@ 2019-05-03  8:18   ` Daniel Vetter
  2019-05-03 12:47     ` Sean Paul
  0 siblings, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2019-05-03  8:18 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Sean Paul, Daniel Vetter, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, David Airlie, linux-kernel

On Thu, May 02, 2019 at 03:49:44PM -0400, Sean Paul wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> This patch adds a helper to tease out the currently connected crtc for
> an encoder, along with its state. This follows the same pattern as the
> drm_atomic_crtc_*_for_* macros in the atomic helpers. Since the
> relationship of crtc:encoder is 1:n, we don't need a loop since there is
> only one crtc per encoder.

No idea which macros you mean, couldn't find them.
> 
> Instead of splitting this into 3 functions which all do the same thing,
> this is presented as one function. Perhaps that's too ugly and it should
> be split to:
> struct drm_crtc *drm_atomic_crtc_for_encoder(state, encoder);
> struct drm_crtc_state *drm_atomic_new_crtc_state_for_encoder(state, encoder);
> struct drm_crtc_state *drm_atomic_old_crtc_state_for_encoder(state, encoder);
> 
> Suggestions welcome.
> 
> Changes in v3:
> - Added to the set
> 
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c | 48 +++++++++++++++++++++++++++++
>  include/drm/drm_atomic_helper.h     |  6 ++++
>  2 files changed, 54 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 71cc7d6b0644..1f81ca8daad7 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -3591,3 +3591,51 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
>  	return ret;
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
> +
> +/**
> + * drm_atomic_crtc_state_for_encoder - Get crtc and new/old state for an encoder
> + * @state: Atomic state
> + * @encoder: The encoder to fetch the crtc information for
> + * @crtc: If not NULL, receives the currently connected crtc
> + * @old_crtc_state: If not NULL, receives the crtc's old state
> + * @new_crtc_state: If not NULL, receives the crtc's new state
> + *
> + * This function finds the crtc which is currently connected to @encoder and
> + * returns it as well as its old and new state. If there is no crtc currently
> + * connected, the function will clear @crtc, @old_crtc_state, @new_crtc_state.
> + *
> + * All of @crtc, @old_crtc_state, and @new_crtc_state are optional.
> + */
> +void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
> +				       struct drm_encoder *encoder,
> +				       struct drm_crtc **crtc,
> +				       struct drm_crtc_state **old_crtc_state,
> +				       struct drm_crtc_state **new_crtc_state)
> +{
> +	struct drm_crtc *tmp_crtc;
> +	struct drm_crtc_state *tmp_new_crtc_state, *tmp_old_crtc_state;
> +	u32 enc_mask = drm_encoder_mask(encoder);
> +	int i;
> +
> +	for_each_oldnew_crtc_in_state(state, tmp_crtc, tmp_old_crtc_state,
> +				      tmp_new_crtc_state, i) {

So there's two ways to do this:

- Using encoder_mask, which is a helper thing. In that case I'd rename
  this to drm_atomic_helper_crtc_for_encoder.

- By looping over the connectors, and looking at ->best_encoder and
  ->crtc, see drm_encoder_get_crtc in drm_encoder.c. That's the core way
  of doing things. In that case call it drm_atomic_crtc_for_encoder, and
  put it into drm_atomic.c.

There's two ways of doing the 2nd one: looping over connectors in a
drm_atomic_state, or the connector list overall. First requires that the
encoder is already in drm_atomic_state (which I think makes sense).

Even more complications on old/new_crtc_state: Is that the old state for
the old crtc, or the old state for the new crtc (that can switch too).
Same for the new crtc state ...

tldr; I'd create 2 functions:

drm_crtc *drm_atomic_encoder_get_new_crtc(drm_atomic_state *state, encoder)
drm_crtc *drm_atomic_encoder_get_old_crtc(drm_atomic_state *state, encoder)

With the requirement that they'll return NULL if the encder isn't in in
@state, and implemented using looping over connectors in @state.

tldr; this is a lot more tricky than it looks like ...
-Daniel


> +		if (!(tmp_new_crtc_state->encoder_mask & enc_mask))
> +			continue;
> +
> +		if (new_crtc_state)
> +			*new_crtc_state = tmp_new_crtc_state;
> +		if (old_crtc_state)
> +			*old_crtc_state = tmp_old_crtc_state;
> +		if (crtc)
> +			*crtc = tmp_crtc;
> +		return;
> +	}
> +
> +	if (new_crtc_state)
> +		*new_crtc_state = NULL;
> +	if (old_crtc_state)
> +		*old_crtc_state = NULL;
> +	if (crtc)
> +		*crtc = NULL;
> +}
> +EXPORT_SYMBOL(drm_atomic_crtc_state_for_encoder);
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index 58214be3bf3d..2383550a0cc8 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -153,6 +153,12 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
>  				       uint32_t size,
>  				       struct drm_modeset_acquire_ctx *ctx);
>  
> +void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
> +				       struct drm_encoder *encoder,
> +				       struct drm_crtc **crtc,
> +				       struct drm_crtc_state **old_crtc_state,
> +				       struct drm_crtc_state **new_crtc_state);
> +
>  /**
>   * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
>   * @plane: the loop cursor
> -- 
> Sean Paul, Software Engineer, Google / Chromium OS
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state
  2019-05-02 19:49 ` [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state Sean Paul
@ 2019-05-03  8:19   ` Daniel Vetter
  2019-05-11 19:12   ` Laurent Pinchart
  1 sibling, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2019-05-03  8:19 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Sean Paul, Daniel Vetter, Ville Syrjälä,
	Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs,
	Laurent Pinchart, Kieran Bingham, Eric Anholt, Maarten Lankhorst,
	Maxime Ripard, David Airlie, linux-kernel, intel-gfx, nouveau,
	linux-renesas-soc

On Thu, May 02, 2019 at 03:49:46PM -0400, Sean Paul wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> Everyone who implements connector_helper_funcs->atomic_check reaches
> into the connector state to get the atomic state. Instead of continuing
> this pattern, change the callback signature to just give atomic state
> and let the driver determine what it does and does not need from it.
> 
> Eventually all atomic functions should do this, but that's just too much
> busy work for me.
> 
> Changes in v3:
> - Added to the set
> 
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Cc: Ben Skeggs <bskeggs@redhat.com>
> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> Cc: Eric Anholt <eric@anholt.net>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>

Assuming it compiles everywhere and intel-gfx-ci approves too

Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c      |  4 ++--
>  drivers/gpu/drm/i915/intel_atomic.c      |  8 +++++---
>  drivers/gpu/drm/i915/intel_dp_mst.c      |  7 ++++---
>  drivers/gpu/drm/i915/intel_drv.h         |  2 +-
>  drivers/gpu/drm/i915/intel_sdvo.c        |  9 +++++----
>  drivers/gpu/drm/i915/intel_tv.c          |  8 +++++---
>  drivers/gpu/drm/nouveau/dispnv50/disp.c  |  5 +++--
>  drivers/gpu/drm/rcar-du/rcar_lvds.c      | 12 +++++++-----
>  drivers/gpu/drm/vc4/vc4_txp.c            |  7 ++++---
>  include/drm/drm_modeset_helper_vtables.h |  2 +-
>  10 files changed, 37 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 9d9e47276839..fa5a367507c1 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -683,7 +683,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
>  		}
>  
>  		if (funcs->atomic_check)
> -			ret = funcs->atomic_check(connector, new_connector_state);
> +			ret = funcs->atomic_check(connector, state);
>  		if (ret)
>  			return ret;
>  
> @@ -725,7 +725,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
>  			continue;
>  
>  		if (funcs->atomic_check)
> -			ret = funcs->atomic_check(connector, new_connector_state);
> +			ret = funcs->atomic_check(connector, state);
>  		if (ret)
>  			return ret;
>  	}
> diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> index b844e8840c6f..e8a5b82e9242 100644
> --- a/drivers/gpu/drm/i915/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/intel_atomic.c
> @@ -103,12 +103,14 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
>  }
>  
>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> -					 struct drm_connector_state *new_state)
> +					 struct drm_atomic_state *state)
>  {
> +	struct drm_connector_state *new_state =
> +		drm_atomic_get_new_connector_state(state, conn);
>  	struct intel_digital_connector_state *new_conn_state =
>  		to_intel_digital_connector_state(new_state);
>  	struct drm_connector_state *old_state =
> -		drm_atomic_get_old_connector_state(new_state->state, conn);
> +		drm_atomic_get_old_connector_state(state, conn);
>  	struct intel_digital_connector_state *old_conn_state =
>  		to_intel_digital_connector_state(old_state);
>  	struct drm_crtc_state *crtc_state;
> @@ -118,7 +120,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
>  	if (!new_state->crtc)
>  		return 0;
>  
> -	crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> +	crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
>  
>  	/*
>  	 * These properties are handled by fastset, and might not end
> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> index 19d81cef2ab6..89cfec128ba0 100644
> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> @@ -143,9 +143,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
>  
>  static int
>  intel_dp_mst_atomic_check(struct drm_connector *connector,
> -			  struct drm_connector_state *new_conn_state)
> +			  struct drm_atomic_state *state)
>  {
> -	struct drm_atomic_state *state = new_conn_state->state;
> +	struct drm_connector_state *new_conn_state =
> +		drm_atomic_get_new_connector_state(state, connector);
>  	struct drm_connector_state *old_conn_state =
>  		drm_atomic_get_old_connector_state(state, connector);
>  	struct intel_connector *intel_connector =
> @@ -155,7 +156,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
>  	struct drm_dp_mst_topology_mgr *mgr;
>  	int ret;
>  
> -	ret = intel_digital_connector_atomic_check(connector, new_conn_state);
> +	ret = intel_digital_connector_atomic_check(connector, state);
>  	if (ret)
>  		return ret;
>  
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index f8c7b291fdc3..88571b8e8d62 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -2481,7 +2481,7 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
>  						struct drm_property *property,
>  						u64 val);
>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> -					 struct drm_connector_state *new_state);
> +					 struct drm_atomic_state *state);
>  struct drm_connector_state *
>  intel_digital_connector_duplicate_state(struct drm_connector *connector);
>  
> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> index 68f497493d43..72ea164b971c 100644
> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> @@ -2342,9 +2342,10 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
>  };
>  
>  static int intel_sdvo_atomic_check(struct drm_connector *conn,
> -				   struct drm_connector_state *new_conn_state)
> +				   struct drm_atomic_state *state)
>  {
> -	struct drm_atomic_state *state = new_conn_state->state;
> +	struct drm_connector_state *new_conn_state =
> +		drm_atomic_get_new_connector_state(state, conn);
>  	struct drm_connector_state *old_conn_state =
>  		drm_atomic_get_old_connector_state(state, conn);
>  	struct intel_sdvo_connector_state *old_state =
> @@ -2356,13 +2357,13 @@ static int intel_sdvo_atomic_check(struct drm_connector *conn,
>  	    (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
>  	     memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
>  		struct drm_crtc_state *crtc_state =
> -			drm_atomic_get_new_crtc_state(new_conn_state->state,
> +			drm_atomic_get_new_crtc_state(state,
>  						      new_conn_state->crtc);
>  
>  		crtc_state->connectors_changed = true;
>  	}
>  
> -	return intel_digital_connector_atomic_check(conn, new_conn_state);
> +	return intel_digital_connector_atomic_check(conn, state);
>  }
>  
>  static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 3924c4944e1f..a41c5b467c14 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -1817,16 +1817,18 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
>  };
>  
>  static int intel_tv_atomic_check(struct drm_connector *connector,
> -				 struct drm_connector_state *new_state)
> +				 struct drm_atomic_state *state)
>  {
> +	struct drm_connector_state *new_state;
>  	struct drm_crtc_state *new_crtc_state;
>  	struct drm_connector_state *old_state;
>  
> +	new_state = drm_atomic_get_new_connector_state(state, connector);
>  	if (!new_state->crtc)
>  		return 0;
>  
> -	old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
> -	new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> +	old_state = drm_atomic_get_old_connector_state(state, connector);
> +	new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
>  
>  	if (old_state->tv.mode != new_state->tv.mode ||
>  	    old_state->tv.margins.left != new_state->tv.margins.left ||
> diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> index 4b1650f51955..7ba373f493b2 100644
> --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> @@ -948,11 +948,12 @@ nv50_mstc_get_modes(struct drm_connector *connector)
>  
>  static int
>  nv50_mstc_atomic_check(struct drm_connector *connector,
> -		       struct drm_connector_state *new_conn_state)
> +		       struct drm_atomic_state *state)
>  {
> -	struct drm_atomic_state *state = new_conn_state->state;
>  	struct nv50_mstc *mstc = nv50_mstc(connector);
>  	struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr;
> +	struct drm_connector_state *new_conn_state =
> +		drm_atomic_get_new_connector_state(state, connector);
>  	struct drm_connector_state *old_conn_state =
>  		drm_atomic_get_old_connector_state(state, connector);
>  	struct drm_crtc_state *crtc_state;
> diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> index 620b51aab291..5b81ba2a7f27 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> @@ -92,13 +92,15 @@ static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
>  }
>  
>  static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> -					    struct drm_connector_state *state)
> +					    struct drm_atomic_state *state)
>  {
>  	struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
>  	const struct drm_display_mode *panel_mode;
> +	struct drm_connector_state *conn_state;
>  	struct drm_crtc_state *crtc_state;
>  
> -	if (!state->crtc)
> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> +	if (!conn_state->crtc)
>  		return 0;
>  
>  	if (list_empty(&connector->modes)) {
> @@ -110,9 +112,9 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
>  				      struct drm_display_mode, head);
>  
>  	/* We're not allowed to modify the resolution. */
> -	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
> -	if (IS_ERR(crtc_state))
> -		return PTR_ERR(crtc_state);
> +	crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
> +	if (!crtc_state)
> +		return -EINVAL;
>  
>  	if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
>  	    crtc_state->mode.vdisplay != panel_mode->vdisplay)
> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> index c8b89a78f9f4..96f91c1b4b6e 100644
> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> @@ -221,17 +221,18 @@ static const u32 txp_fmts[] = {
>  };
>  
>  static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
> -					struct drm_connector_state *conn_state)
> +					  struct drm_atomic_state *state)
>  {
> +	struct drm_connector_state *conn_state;
>  	struct drm_crtc_state *crtc_state;
>  	struct drm_framebuffer *fb;
>  	int i;
>  
> +	conn_state = drm_atomic_get_new_connector_state(state, conn);
>  	if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
>  		return 0;
>  
> -	crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
> -						   conn_state->crtc);
> +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
>  
>  	fb = conn_state->writeback_job->fb;
>  	if (fb->width != crtc_state->mode.hdisplay ||
> diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> index de57fb40cb6e..adc8b7cf64b5 100644
> --- a/include/drm/drm_modeset_helper_vtables.h
> +++ b/include/drm/drm_modeset_helper_vtables.h
> @@ -1020,7 +1020,7 @@ struct drm_connector_helper_funcs {
>  	 * deadlock.
>  	 */
>  	int (*atomic_check)(struct drm_connector *connector,
> -			    struct drm_connector_state *state);
> +			    struct drm_atomic_state *state);
>  
>  	/**
>  	 * @atomic_commit:
> -- 
> Sean Paul, Software Engineer, Google / Chromium OS
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 01/10] drm: Add atomic variants of enable/disable to encoder helper funcs
  2019-05-03  7:51   ` Daniel Vetter
@ 2019-05-03 12:34     ` Sean Paul
  2019-05-03 14:08       ` Daniel Vetter
  0 siblings, 1 reply; 29+ messages in thread
From: Sean Paul @ 2019-05-03 12:34 UTC (permalink / raw)
  To: Sean Paul, dri-devel, Sean Paul, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, David Airlie, linux-kernel

On Fri, May 03, 2019 at 09:51:30AM +0200, Daniel Vetter wrote:
> On Thu, May 02, 2019 at 03:49:43PM -0400, Sean Paul wrote:
> > From: Sean Paul <seanpaul@chromium.org>
> > 
> > This patch adds atomic_enable and atomic_disable callbacks to the
> > encoder helpers. This will allow encoders to make informed decisions in
> > their start-up/shutdown based on the committed state.
> > 
> > Aside from the new hooks, this patch also introduces the new signature
> > for .atomic_* functions going forward. Instead of passing object state
> > (well, encoders don't have atomic state, but let's ignore that), we pass
> > the entire atomic state so the driver can inspect more than what's
> > happening locally.
> > 
> > This is particularly important for the upcoming self refresh helpers.
> > 
> > Changes in v3:
> > - Added patch to the set
> > 
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > ---
> >  drivers/gpu/drm/drm_atomic_helper.c      |  6 +++-
> >  include/drm/drm_modeset_helper_vtables.h | 45 ++++++++++++++++++++++++
> >  2 files changed, 50 insertions(+), 1 deletion(-)

/snip

> > diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> > index 8f3602811eb5..de57fb40cb6e 100644
> > --- a/include/drm/drm_modeset_helper_vtables.h
> > +++ b/include/drm/drm_modeset_helper_vtables.h
> > @@ -675,6 +675,51 @@ struct drm_encoder_helper_funcs {
> >  	enum drm_connector_status (*detect)(struct drm_encoder *encoder,
> >  					    struct drm_connector *connector);
> >  
> > +	/**
> > +	 * @atomic_disable:
> > +	 *
> > +	 * This callback should be used to disable the encoder. With the atomic
> > +	 * drivers it is called before this encoder's CRTC has been shut off
> > +	 * using their own &drm_crtc_helper_funcs.atomic_disable hook. If that
> > +	 * sequence is too simple drivers can just add their own driver private
> > +	 * encoder hooks and call them from CRTC's callback by looping over all
> > +	 * encoders connected to it using for_each_encoder_on_crtc().
> > +	 *
> > +	 * This callback is a variant of @disable that provides the atomic state
> > +	 * to the driver. It takes priority over @disable during atomic commits.
> > +	 *
> > +	 * This hook is used only by atomic helpers. Atomic drivers don't need
> > +	 * to implement it if there's no need to disable anything at the encoder
> > +	 * level. To ensure that runtime PM handling (using either DPMS or the
> > +	 * new "ACTIVE" property) works @atomic_disable must be the inverse of
> > +	 * @atomic_enable.
> > +	 */
> 
> I'd add something like "For atomic drivers also consider @atomic_disable"
> to the kerneldoc of @disable (before the NOTE: which is only relevant for
> pre-atomic). Same for the enable side.
> 
> > +	void (*atomic_disable)(struct drm_encoder *encoder,
> > +			       struct drm_atomic_state *state);
> > +
> > +	/**
> > +	 * @atomic_enable:
> > +	 *
> > +	 * This callback should be used to enable the encoder. It is called
> > +	 * after this encoder's CRTC has been enabled using their own
> > +	 * &drm_crtc_helper_funcs.atomic_enable hook. If that sequence is
> > +	 * too simple drivers can just add their own driver private encoder
> > +	 * hooks and call them from CRTC's callback by looping over all encoders
> > +	 * connected to it using for_each_encoder_on_crtc().
> > +	 *
> > +	 * This callback is a variant of @enable that provides the atomic state
> > +	 * to the driver. It is called in place of @enable during atomic
> > +	 * commits.
> 
> needs to be adjusted here for "takes priority".

Can you clarify this comment? I'm a little fuzzy on what it means.



> > +	 *
> > +	 * This hook is used only by atomic helpers, for symmetry with @disable.
> > +	 * Atomic drivers don't need to implement it if there's no need to
> > +	 * enable anything at the encoder level. To ensure that runtime PM
> > +	 * handling (using either DPMS or the new "ACTIVE" property) works
> > +	 * @enable must be the inverse of @disable for atomic drivers.
> > +	 */
> > +	void (*atomic_enable)(struct drm_encoder *encoder,
> > +			      struct drm_atomic_state *state);
> > +
> 
> With the nits:
> 
> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Thanks!

Sean

> 
> >  	/**
> >  	 * @disable:
> >  	 *
> > -- 
> > Sean Paul, Software Engineer, Google / Chromium OS
> > 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Sean Paul, Software Engineer, Google / Chromium OS

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 02/10] drm: Add drm_atomic_crtc_state_for_encoder helper
  2019-05-03  8:18   ` Daniel Vetter
@ 2019-05-03 12:47     ` Sean Paul
  2019-05-03 14:06       ` Daniel Vetter
  0 siblings, 1 reply; 29+ messages in thread
From: Sean Paul @ 2019-05-03 12:47 UTC (permalink / raw)
  To: Sean Paul, dri-devel, Sean Paul, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, David Airlie, linux-kernel

On Fri, May 03, 2019 at 10:18:51AM +0200, Daniel Vetter wrote:
> On Thu, May 02, 2019 at 03:49:44PM -0400, Sean Paul wrote:
> > From: Sean Paul <seanpaul@chromium.org>
> > 
> > This patch adds a helper to tease out the currently connected crtc for
> > an encoder, along with its state. This follows the same pattern as the
> > drm_atomic_crtc_*_for_* macros in the atomic helpers. Since the
> > relationship of crtc:encoder is 1:n, we don't need a loop since there is
> > only one crtc per encoder.
> 
> No idea which macros you mean, couldn't find them.

No longer relevant with the changes below, but for completeness, I was trying to
refer to drm_atomic_crtc_state_for_each_plane and friends. I see now that I
wasn't terribly clear :)


> > 
> > Instead of splitting this into 3 functions which all do the same thing,
> > this is presented as one function. Perhaps that's too ugly and it should
> > be split to:
> > struct drm_crtc *drm_atomic_crtc_for_encoder(state, encoder);
> > struct drm_crtc_state *drm_atomic_new_crtc_state_for_encoder(state, encoder);
> > struct drm_crtc_state *drm_atomic_old_crtc_state_for_encoder(state, encoder);
> > 
> > Suggestions welcome.
> > 
> > Changes in v3:
> > - Added to the set
> > 
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > ---
> >  drivers/gpu/drm/drm_atomic_helper.c | 48 +++++++++++++++++++++++++++++
> >  include/drm/drm_atomic_helper.h     |  6 ++++
> >  2 files changed, 54 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > index 71cc7d6b0644..1f81ca8daad7 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -3591,3 +3591,51 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
> >  	return ret;
> >  }
> >  EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
> > +
> > +/**
> > + * drm_atomic_crtc_state_for_encoder - Get crtc and new/old state for an encoder
> > + * @state: Atomic state
> > + * @encoder: The encoder to fetch the crtc information for
> > + * @crtc: If not NULL, receives the currently connected crtc
> > + * @old_crtc_state: If not NULL, receives the crtc's old state
> > + * @new_crtc_state: If not NULL, receives the crtc's new state
> > + *
> > + * This function finds the crtc which is currently connected to @encoder and
> > + * returns it as well as its old and new state. If there is no crtc currently
> > + * connected, the function will clear @crtc, @old_crtc_state, @new_crtc_state.
> > + *
> > + * All of @crtc, @old_crtc_state, and @new_crtc_state are optional.
> > + */
> > +void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
> > +				       struct drm_encoder *encoder,
> > +				       struct drm_crtc **crtc,
> > +				       struct drm_crtc_state **old_crtc_state,
> > +				       struct drm_crtc_state **new_crtc_state)
> > +{
> > +	struct drm_crtc *tmp_crtc;
> > +	struct drm_crtc_state *tmp_new_crtc_state, *tmp_old_crtc_state;
> > +	u32 enc_mask = drm_encoder_mask(encoder);
> > +	int i;
> > +
> > +	for_each_oldnew_crtc_in_state(state, tmp_crtc, tmp_old_crtc_state,
> > +				      tmp_new_crtc_state, i) {
> 
> So there's two ways to do this:
> 
> - Using encoder_mask, which is a helper thing. In that case I'd rename
>   this to drm_atomic_helper_crtc_for_encoder.
> 
> - By looping over the connectors, and looking at ->best_encoder and
>   ->crtc, see drm_encoder_get_crtc in drm_encoder.c. That's the core way
>   of doing things. In that case call it drm_atomic_crtc_for_encoder, and
>   put it into drm_atomic.c.
> 
> There's two ways of doing the 2nd one: looping over connectors in a
> drm_atomic_state, or the connector list overall. First requires that the
> encoder is already in drm_atomic_state (which I think makes sense).

Yeah, I wasn't particularly interested in encoders not in state. I had
considered going the connector route, but since you can have multiple connectors
per encoder, going through crtc seemed a bit more direct. 

> 
> Even more complications on old/new_crtc_state: Is that the old state for
> the old crtc, or the old state for the new crtc (that can switch too).
> Same for the new crtc state ...
> 
> tldr; I'd create 2 functions:
> 
> drm_crtc *drm_atomic_encoder_get_new_crtc(drm_atomic_state *state, encoder)
> drm_crtc *drm_atomic_encoder_get_old_crtc(drm_atomic_state *state, encoder)
> 
> With the requirement that they'll return NULL if the encder isn't in in
> @state, and implemented using looping over connectors in @state.

It seems like we could just tweak this function a bit to get the new or old crtc
for an encoder. Any particular reason for going through connector instead? Is it
to avoid the encoder_mask which is a helper thing? In that case, perhaps this
should use connector links and live in drm_atomic.c?

Thanks for the review!

Sean

> 
> tldr; this is a lot more tricky than it looks like ...
> -Daniel
> 
> 
> > +		if (!(tmp_new_crtc_state->encoder_mask & enc_mask))
> > +			continue;
> > +
> > +		if (new_crtc_state)
> > +			*new_crtc_state = tmp_new_crtc_state;
> > +		if (old_crtc_state)
> > +			*old_crtc_state = tmp_old_crtc_state;
> > +		if (crtc)
> > +			*crtc = tmp_crtc;
> > +		return;
> > +	}
> > +
> > +	if (new_crtc_state)
> > +		*new_crtc_state = NULL;
> > +	if (old_crtc_state)
> > +		*old_crtc_state = NULL;
> > +	if (crtc)
> > +		*crtc = NULL;
> > +}
> > +EXPORT_SYMBOL(drm_atomic_crtc_state_for_encoder);
> > diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> > index 58214be3bf3d..2383550a0cc8 100644
> > --- a/include/drm/drm_atomic_helper.h
> > +++ b/include/drm/drm_atomic_helper.h
> > @@ -153,6 +153,12 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
> >  				       uint32_t size,
> >  				       struct drm_modeset_acquire_ctx *ctx);
> >  
> > +void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
> > +				       struct drm_encoder *encoder,
> > +				       struct drm_crtc **crtc,
> > +				       struct drm_crtc_state **old_crtc_state,
> > +				       struct drm_crtc_state **new_crtc_state);
> > +
> >  /**
> >   * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
> >   * @plane: the loop cursor
> > -- 
> > Sean Paul, Software Engineer, Google / Chromium OS
> > 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> http://blog.ffwll.ch

-- 
Sean Paul, Software Engineer, Google / Chromium OS

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 02/10] drm: Add drm_atomic_crtc_state_for_encoder helper
  2019-05-03 12:47     ` Sean Paul
@ 2019-05-03 14:06       ` Daniel Vetter
  2019-05-05 21:15         ` Daniel Vetter
  0 siblings, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2019-05-03 14:06 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Sean Paul, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, David Airlie,
	Linux Kernel Mailing List

On Fri, May 3, 2019 at 2:47 PM Sean Paul <sean@poorly.run> wrote:
> On Fri, May 03, 2019 at 10:18:51AM +0200, Daniel Vetter wrote:
> > On Thu, May 02, 2019 at 03:49:44PM -0400, Sean Paul wrote:
> > > From: Sean Paul <seanpaul@chromium.org>
> > >
> > > This patch adds a helper to tease out the currently connected crtc for
> > > an encoder, along with its state. This follows the same pattern as the
> > > drm_atomic_crtc_*_for_* macros in the atomic helpers. Since the
> > > relationship of crtc:encoder is 1:n, we don't need a loop since there is
> > > only one crtc per encoder.
> >
> > No idea which macros you mean, couldn't find them.
>
> No longer relevant with the changes below, but for completeness, I was trying to
> refer to drm_atomic_crtc_state_for_each_plane and friends. I see now that I
> wasn't terribly clear :)
>
>
> > >
> > > Instead of splitting this into 3 functions which all do the same thing,
> > > this is presented as one function. Perhaps that's too ugly and it should
> > > be split to:
> > > struct drm_crtc *drm_atomic_crtc_for_encoder(state, encoder);
> > > struct drm_crtc_state *drm_atomic_new_crtc_state_for_encoder(state, encoder);
> > > struct drm_crtc_state *drm_atomic_old_crtc_state_for_encoder(state, encoder);
> > >
> > > Suggestions welcome.
> > >
> > > Changes in v3:
> > > - Added to the set
> > >
> > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > > ---
> > >  drivers/gpu/drm/drm_atomic_helper.c | 48 +++++++++++++++++++++++++++++
> > >  include/drm/drm_atomic_helper.h     |  6 ++++
> > >  2 files changed, 54 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > index 71cc7d6b0644..1f81ca8daad7 100644
> > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > @@ -3591,3 +3591,51 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
> > >     return ret;
> > >  }
> > >  EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
> > > +
> > > +/**
> > > + * drm_atomic_crtc_state_for_encoder - Get crtc and new/old state for an encoder
> > > + * @state: Atomic state
> > > + * @encoder: The encoder to fetch the crtc information for
> > > + * @crtc: If not NULL, receives the currently connected crtc
> > > + * @old_crtc_state: If not NULL, receives the crtc's old state
> > > + * @new_crtc_state: If not NULL, receives the crtc's new state
> > > + *
> > > + * This function finds the crtc which is currently connected to @encoder and
> > > + * returns it as well as its old and new state. If there is no crtc currently
> > > + * connected, the function will clear @crtc, @old_crtc_state, @new_crtc_state.
> > > + *
> > > + * All of @crtc, @old_crtc_state, and @new_crtc_state are optional.
> > > + */
> > > +void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
> > > +                                  struct drm_encoder *encoder,
> > > +                                  struct drm_crtc **crtc,
> > > +                                  struct drm_crtc_state **old_crtc_state,
> > > +                                  struct drm_crtc_state **new_crtc_state)
> > > +{
> > > +   struct drm_crtc *tmp_crtc;
> > > +   struct drm_crtc_state *tmp_new_crtc_state, *tmp_old_crtc_state;
> > > +   u32 enc_mask = drm_encoder_mask(encoder);
> > > +   int i;
> > > +
> > > +   for_each_oldnew_crtc_in_state(state, tmp_crtc, tmp_old_crtc_state,
> > > +                                 tmp_new_crtc_state, i) {
> >
> > So there's two ways to do this:
> >
> > - Using encoder_mask, which is a helper thing. In that case I'd rename
> >   this to drm_atomic_helper_crtc_for_encoder.
> >
> > - By looping over the connectors, and looking at ->best_encoder and
> >   ->crtc, see drm_encoder_get_crtc in drm_encoder.c. That's the core way
> >   of doing things. In that case call it drm_atomic_crtc_for_encoder, and
> >   put it into drm_atomic.c.
> >
> > There's two ways of doing the 2nd one: looping over connectors in a
> > drm_atomic_state, or the connector list overall. First requires that the
> > encoder is already in drm_atomic_state (which I think makes sense).
>
> Yeah, I wasn't particularly interested in encoders not in state. I had
> considered going the connector route, but since you can have multiple connectors
> per encoder, going through crtc seemed a bit more direct.

You can have multiple possible connectors for a given encoder, and
multiple possible encoders for a given connector. In both cases the
driver picks for you. But for active encoders and connectors the
relationship is 1:1. That's what the helpers exploit by looping over
connectors to get at encoders.

> > Even more complications on old/new_crtc_state: Is that the old state for
> > the old crtc, or the old state for the new crtc (that can switch too).
> > Same for the new crtc state ...
> >
> > tldr; I'd create 2 functions:
> >
> > drm_crtc *drm_atomic_encoder_get_new_crtc(drm_atomic_state *state, encoder)
> > drm_crtc *drm_atomic_encoder_get_old_crtc(drm_atomic_state *state, encoder)
> >
> > With the requirement that they'll return NULL if the encder isn't in in
> > @state, and implemented using looping over connectors in @state.
>
> It seems like we could just tweak this function a bit to get the new or old crtc
> for an encoder. Any particular reason for going through connector instead? Is it
> to avoid the encoder_mask which is a helper thing? In that case, perhaps this
> should use connector links and live in drm_atomic.c?

Well as explained, there's 3 ways you can achieve the same really. I
do think the "loop over connectors in drm_atomic_state, WARN() if we
haven't found the encoder you want the crtc for" is probably the most
solid aproach since it picks up a core atomic concept. But the others
(looping the connector list, or looping encoder_mask) all work too.

Aside: plane/encoder_mask was added to go from crtc to
planes/encoders, not really to go the other way round.

Another solution would be to pass the connector_state to all atomic
encoder hooks, then you could just look at connector_state->crtc. Plus
you can get at all the other interesting bits and pieces of
information. In a way this is fallout from us keeping encoders as a
meaningful concept for easier transition of legacy drivers, while
still keeping them entirely irrelevant for the actual userspace api
semantics.

So maybe we want drm_atomic_encoder_get_old/new_connector here. Or
maybe we even want the full set of functions, i.e.
drm_atomic_encoder_get_old/new_connector/crtc.

In all cases I think only returning the object, not it's state is
simplest, since then you avoid the confusion of old/new state for
old/new obj.
-Daniel


> Thanks for the review!
>
> Sean
>
> >
> > tldr; this is a lot more tricky than it looks like ...
> > -Daniel
> >
> >
> > > +           if (!(tmp_new_crtc_state->encoder_mask & enc_mask))
> > > +                   continue;
> > > +
> > > +           if (new_crtc_state)
> > > +                   *new_crtc_state = tmp_new_crtc_state;
> > > +           if (old_crtc_state)
> > > +                   *old_crtc_state = tmp_old_crtc_state;
> > > +           if (crtc)
> > > +                   *crtc = tmp_crtc;
> > > +           return;
> > > +   }
> > > +
> > > +   if (new_crtc_state)
> > > +           *new_crtc_state = NULL;
> > > +   if (old_crtc_state)
> > > +           *old_crtc_state = NULL;
> > > +   if (crtc)
> > > +           *crtc = NULL;
> > > +}
> > > +EXPORT_SYMBOL(drm_atomic_crtc_state_for_encoder);
> > > diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> > > index 58214be3bf3d..2383550a0cc8 100644
> > > --- a/include/drm/drm_atomic_helper.h
> > > +++ b/include/drm/drm_atomic_helper.h
> > > @@ -153,6 +153,12 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
> > >                                    uint32_t size,
> > >                                    struct drm_modeset_acquire_ctx *ctx);
> > >
> > > +void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
> > > +                                  struct drm_encoder *encoder,
> > > +                                  struct drm_crtc **crtc,
> > > +                                  struct drm_crtc_state **old_crtc_state,
> > > +                                  struct drm_crtc_state **new_crtc_state);
> > > +
> > >  /**
> > >   * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
> > >   * @plane: the loop cursor
> > > --
> > > Sean Paul, Software Engineer, Google / Chromium OS
> > >
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch
>
> --
> Sean Paul, Software Engineer, Google / Chromium OS
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 01/10] drm: Add atomic variants of enable/disable to encoder helper funcs
  2019-05-03 12:34     ` Sean Paul
@ 2019-05-03 14:08       ` Daniel Vetter
  0 siblings, 0 replies; 29+ messages in thread
From: Daniel Vetter @ 2019-05-03 14:08 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Sean Paul, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, David Airlie,
	Linux Kernel Mailing List

On Fri, May 3, 2019 at 2:34 PM Sean Paul <sean@poorly.run> wrote:
>
> On Fri, May 03, 2019 at 09:51:30AM +0200, Daniel Vetter wrote:
> > On Thu, May 02, 2019 at 03:49:43PM -0400, Sean Paul wrote:
> > > From: Sean Paul <seanpaul@chromium.org>
> > >
> > > This patch adds atomic_enable and atomic_disable callbacks to the
> > > encoder helpers. This will allow encoders to make informed decisions in
> > > their start-up/shutdown based on the committed state.
> > >
> > > Aside from the new hooks, this patch also introduces the new signature
> > > for .atomic_* functions going forward. Instead of passing object state
> > > (well, encoders don't have atomic state, but let's ignore that), we pass
> > > the entire atomic state so the driver can inspect more than what's
> > > happening locally.
> > >
> > > This is particularly important for the upcoming self refresh helpers.
> > >
> > > Changes in v3:
> > > - Added patch to the set
> > >
> > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > > ---
> > >  drivers/gpu/drm/drm_atomic_helper.c      |  6 +++-
> > >  include/drm/drm_modeset_helper_vtables.h | 45 ++++++++++++++++++++++++
> > >  2 files changed, 50 insertions(+), 1 deletion(-)
>
> /snip
>
> > > diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> > > index 8f3602811eb5..de57fb40cb6e 100644
> > > --- a/include/drm/drm_modeset_helper_vtables.h
> > > +++ b/include/drm/drm_modeset_helper_vtables.h
> > > @@ -675,6 +675,51 @@ struct drm_encoder_helper_funcs {
> > >     enum drm_connector_status (*detect)(struct drm_encoder *encoder,
> > >                                         struct drm_connector *connector);
> > >
> > > +   /**
> > > +    * @atomic_disable:
> > > +    *
> > > +    * This callback should be used to disable the encoder. With the atomic
> > > +    * drivers it is called before this encoder's CRTC has been shut off
> > > +    * using their own &drm_crtc_helper_funcs.atomic_disable hook. If that
> > > +    * sequence is too simple drivers can just add their own driver private
> > > +    * encoder hooks and call them from CRTC's callback by looping over all
> > > +    * encoders connected to it using for_each_encoder_on_crtc().
> > > +    *
> > > +    * This callback is a variant of @disable that provides the atomic state
> > > +    * to the driver. It takes priority over @disable during atomic commits.
> > > +    *
> > > +    * This hook is used only by atomic helpers. Atomic drivers don't need
> > > +    * to implement it if there's no need to disable anything at the encoder
> > > +    * level. To ensure that runtime PM handling (using either DPMS or the
> > > +    * new "ACTIVE" property) works @atomic_disable must be the inverse of
> > > +    * @atomic_enable.
> > > +    */
> >
> > I'd add something like "For atomic drivers also consider @atomic_disable"
> > to the kerneldoc of @disable (before the NOTE: which is only relevant for
> > pre-atomic). Same for the enable side.
> >
> > > +   void (*atomic_disable)(struct drm_encoder *encoder,
> > > +                          struct drm_atomic_state *state);
> > > +
> > > +   /**
> > > +    * @atomic_enable:
> > > +    *
> > > +    * This callback should be used to enable the encoder. It is called
> > > +    * after this encoder's CRTC has been enabled using their own
> > > +    * &drm_crtc_helper_funcs.atomic_enable hook. If that sequence is
> > > +    * too simple drivers can just add their own driver private encoder
> > > +    * hooks and call them from CRTC's callback by looping over all encoders
> > > +    * connected to it using for_each_encoder_on_crtc().
> > > +    *
> > > +    * This callback is a variant of @enable that provides the atomic state
> > > +    * to the driver. It is called in place of @enable during atomic
> > > +    * commits.
> >
> > needs to be adjusted here for "takes priority".
>
> Can you clarify this comment? I'm a little fuzzy on what it means.

Further up I suggest that @atomic_disable should take priority over
all the others (plus explain why @disable is lower than @prepare,
because of the special semantics this has in legacy crtc helpers).
Once you do that you also need to adjust the wording in the kerneldoc
here (same wording as in @atomic_enable sounds good to me), i.e.
explain that @atomic_disable takes priority over all other hooks.
-Daniel

>
>
>
> > > +    *
> > > +    * This hook is used only by atomic helpers, for symmetry with @disable.
> > > +    * Atomic drivers don't need to implement it if there's no need to
> > > +    * enable anything at the encoder level. To ensure that runtime PM
> > > +    * handling (using either DPMS or the new "ACTIVE" property) works
> > > +    * @enable must be the inverse of @disable for atomic drivers.
> > > +    */
> > > +   void (*atomic_enable)(struct drm_encoder *encoder,
> > > +                         struct drm_atomic_state *state);
> > > +
> >
> > With the nits:
> >
> > Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
>
> Thanks!
>
> Sean
>
> >
> > >     /**
> > >      * @disable:
> > >      *
> > > --
> > > Sean Paul, Software Engineer, Google / Chromium OS
> > >
> >
> > --
> > Daniel Vetter
> > Software Engineer, Intel Corporation
> > http://blog.ffwll.ch
>
> --
> Sean Paul, Software Engineer, Google / Chromium OS
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 02/10] drm: Add drm_atomic_crtc_state_for_encoder helper
  2019-05-03 14:06       ` Daniel Vetter
@ 2019-05-05 21:15         ` Daniel Vetter
  2019-05-05 22:01           ` Laurent Pinchart
  0 siblings, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2019-05-05 21:15 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Sean Paul, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, David Airlie,
	Linux Kernel Mailing List, Laurent Pinchart

On Fri, May 03, 2019 at 04:06:28PM +0200, Daniel Vetter wrote:
> On Fri, May 3, 2019 at 2:47 PM Sean Paul <sean@poorly.run> wrote:
> > On Fri, May 03, 2019 at 10:18:51AM +0200, Daniel Vetter wrote:
> > > On Thu, May 02, 2019 at 03:49:44PM -0400, Sean Paul wrote:
> > > > From: Sean Paul <seanpaul@chromium.org>
> > > >
> > > > This patch adds a helper to tease out the currently connected crtc for
> > > > an encoder, along with its state. This follows the same pattern as the
> > > > drm_atomic_crtc_*_for_* macros in the atomic helpers. Since the
> > > > relationship of crtc:encoder is 1:n, we don't need a loop since there is
> > > > only one crtc per encoder.
> > >
> > > No idea which macros you mean, couldn't find them.
> >
> > No longer relevant with the changes below, but for completeness, I was trying to
> > refer to drm_atomic_crtc_state_for_each_plane and friends. I see now that I
> > wasn't terribly clear :)
> >
> >
> > > >
> > > > Instead of splitting this into 3 functions which all do the same thing,
> > > > this is presented as one function. Perhaps that's too ugly and it should
> > > > be split to:
> > > > struct drm_crtc *drm_atomic_crtc_for_encoder(state, encoder);
> > > > struct drm_crtc_state *drm_atomic_new_crtc_state_for_encoder(state, encoder);
> > > > struct drm_crtc_state *drm_atomic_old_crtc_state_for_encoder(state, encoder);
> > > >
> > > > Suggestions welcome.
> > > >
> > > > Changes in v3:
> > > > - Added to the set
> > > >
> > > > Cc: Daniel Vetter <daniel@ffwll.ch>
> > > > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > > > ---
> > > >  drivers/gpu/drm/drm_atomic_helper.c | 48 +++++++++++++++++++++++++++++
> > > >  include/drm/drm_atomic_helper.h     |  6 ++++
> > > >  2 files changed, 54 insertions(+)
> > > >
> > > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > > index 71cc7d6b0644..1f81ca8daad7 100644
> > > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > > @@ -3591,3 +3591,51 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
> > > >     return ret;
> > > >  }
> > > >  EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
> > > > +
> > > > +/**
> > > > + * drm_atomic_crtc_state_for_encoder - Get crtc and new/old state for an encoder
> > > > + * @state: Atomic state
> > > > + * @encoder: The encoder to fetch the crtc information for
> > > > + * @crtc: If not NULL, receives the currently connected crtc
> > > > + * @old_crtc_state: If not NULL, receives the crtc's old state
> > > > + * @new_crtc_state: If not NULL, receives the crtc's new state
> > > > + *
> > > > + * This function finds the crtc which is currently connected to @encoder and
> > > > + * returns it as well as its old and new state. If there is no crtc currently
> > > > + * connected, the function will clear @crtc, @old_crtc_state, @new_crtc_state.
> > > > + *
> > > > + * All of @crtc, @old_crtc_state, and @new_crtc_state are optional.
> > > > + */
> > > > +void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
> > > > +                                  struct drm_encoder *encoder,
> > > > +                                  struct drm_crtc **crtc,
> > > > +                                  struct drm_crtc_state **old_crtc_state,
> > > > +                                  struct drm_crtc_state **new_crtc_state)
> > > > +{
> > > > +   struct drm_crtc *tmp_crtc;
> > > > +   struct drm_crtc_state *tmp_new_crtc_state, *tmp_old_crtc_state;
> > > > +   u32 enc_mask = drm_encoder_mask(encoder);
> > > > +   int i;
> > > > +
> > > > +   for_each_oldnew_crtc_in_state(state, tmp_crtc, tmp_old_crtc_state,
> > > > +                                 tmp_new_crtc_state, i) {
> > >
> > > So there's two ways to do this:
> > >
> > > - Using encoder_mask, which is a helper thing. In that case I'd rename
> > >   this to drm_atomic_helper_crtc_for_encoder.
> > >
> > > - By looping over the connectors, and looking at ->best_encoder and
> > >   ->crtc, see drm_encoder_get_crtc in drm_encoder.c. That's the core way
> > >   of doing things. In that case call it drm_atomic_crtc_for_encoder, and
> > >   put it into drm_atomic.c.
> > >
> > > There's two ways of doing the 2nd one: looping over connectors in a
> > > drm_atomic_state, or the connector list overall. First requires that the
> > > encoder is already in drm_atomic_state (which I think makes sense).
> >
> > Yeah, I wasn't particularly interested in encoders not in state. I had
> > considered going the connector route, but since you can have multiple connectors
> > per encoder, going through crtc seemed a bit more direct.
> 
> You can have multiple possible connectors for a given encoder, and
> multiple possible encoders for a given connector. In both cases the
> driver picks for you. But for active encoders and connectors the
> relationship is 1:1. That's what the helpers exploit by looping over
> connectors to get at encoders.
> 
> > > Even more complications on old/new_crtc_state: Is that the old state for
> > > the old crtc, or the old state for the new crtc (that can switch too).
> > > Same for the new crtc state ...
> > >
> > > tldr; I'd create 2 functions:
> > >
> > > drm_crtc *drm_atomic_encoder_get_new_crtc(drm_atomic_state *state, encoder)
> > > drm_crtc *drm_atomic_encoder_get_old_crtc(drm_atomic_state *state, encoder)
> > >
> > > With the requirement that they'll return NULL if the encder isn't in in
> > > @state, and implemented using looping over connectors in @state.
> >
> > It seems like we could just tweak this function a bit to get the new or old crtc
> > for an encoder. Any particular reason for going through connector instead? Is it
> > to avoid the encoder_mask which is a helper thing? In that case, perhaps this
> > should use connector links and live in drm_atomic.c?
> 
> Well as explained, there's 3 ways you can achieve the same really. I
> do think the "loop over connectors in drm_atomic_state, WARN() if we
> haven't found the encoder you want the crtc for" is probably the most
> solid aproach since it picks up a core atomic concept. But the others
> (looping the connector list, or looping encoder_mask) all work too.
> 
> Aside: plane/encoder_mask was added to go from crtc to
> planes/encoders, not really to go the other way round.
> 
> Another solution would be to pass the connector_state to all atomic
> encoder hooks, then you could just look at connector_state->crtc. Plus
> you can get at all the other interesting bits and pieces of
> information. In a way this is fallout from us keeping encoders as a
> meaningful concept for easier transition of legacy drivers, while
> still keeping them entirely irrelevant for the actual userspace api
> semantics.
> 
> So maybe we want drm_atomic_encoder_get_old/new_connector here. Or
> maybe we even want the full set of functions, i.e.
> drm_atomic_encoder_get_old/new_connector/crtc.

Laurent just asked me on irc how to get from a bridge to connector
information. Bridge knows its encoder (it's static), so a encode2connector
function would already have a 2nd user with this.

I.e. I'd say +1 on that approach, and then you can get at the connector
state and whatever else you feel like from there?

Adding Laurent.
-Daniel

> 
> In all cases I think only returning the object, not it's state is
> simplest, since then you avoid the confusion of old/new state for
> old/new obj.
> -Daniel
> 
> 
> > Thanks for the review!
> >
> > Sean
> >
> > >
> > > tldr; this is a lot more tricky than it looks like ...
> > > -Daniel
> > >
> > >
> > > > +           if (!(tmp_new_crtc_state->encoder_mask & enc_mask))
> > > > +                   continue;
> > > > +
> > > > +           if (new_crtc_state)
> > > > +                   *new_crtc_state = tmp_new_crtc_state;
> > > > +           if (old_crtc_state)
> > > > +                   *old_crtc_state = tmp_old_crtc_state;
> > > > +           if (crtc)
> > > > +                   *crtc = tmp_crtc;
> > > > +           return;
> > > > +   }
> > > > +
> > > > +   if (new_crtc_state)
> > > > +           *new_crtc_state = NULL;
> > > > +   if (old_crtc_state)
> > > > +           *old_crtc_state = NULL;
> > > > +   if (crtc)
> > > > +           *crtc = NULL;
> > > > +}
> > > > +EXPORT_SYMBOL(drm_atomic_crtc_state_for_encoder);
> > > > diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> > > > index 58214be3bf3d..2383550a0cc8 100644
> > > > --- a/include/drm/drm_atomic_helper.h
> > > > +++ b/include/drm/drm_atomic_helper.h
> > > > @@ -153,6 +153,12 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
> > > >                                    uint32_t size,
> > > >                                    struct drm_modeset_acquire_ctx *ctx);
> > > >
> > > > +void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
> > > > +                                  struct drm_encoder *encoder,
> > > > +                                  struct drm_crtc **crtc,
> > > > +                                  struct drm_crtc_state **old_crtc_state,
> > > > +                                  struct drm_crtc_state **new_crtc_state);
> > > > +
> > > >  /**
> > > >   * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
> > > >   * @plane: the loop cursor
> > > > --
> > > > Sean Paul, Software Engineer, Google / Chromium OS
> > > >
> > >
> > > --
> > > Daniel Vetter
> > > Software Engineer, Intel Corporation
> > > http://blog.ffwll.ch
> >
> > --
> > Sean Paul, Software Engineer, Google / Chromium OS
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel
> 
> 
> 
> -- 
> Daniel Vetter
> Software Engineer, Intel Corporation
> +41 (0) 79 365 57 48 - http://blog.ffwll.ch

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 02/10] drm: Add drm_atomic_crtc_state_for_encoder helper
  2019-05-05 21:15         ` Daniel Vetter
@ 2019-05-05 22:01           ` Laurent Pinchart
  0 siblings, 0 replies; 29+ messages in thread
From: Laurent Pinchart @ 2019-05-05 22:01 UTC (permalink / raw)
  To: Sean Paul, dri-devel, Sean Paul, Ville Syrjälä,
	Maarten Lankhorst, Maxime Ripard, David Airlie,
	Linux Kernel Mailing List

Hello,

On Sun, May 05, 2019 at 11:15:36PM +0200, Daniel Vetter wrote:
> On Fri, May 03, 2019 at 04:06:28PM +0200, Daniel Vetter wrote:
> > On Fri, May 3, 2019 at 2:47 PM Sean Paul <sean@poorly.run> wrote:
> >> On Fri, May 03, 2019 at 10:18:51AM +0200, Daniel Vetter wrote:
> >>> On Thu, May 02, 2019 at 03:49:44PM -0400, Sean Paul wrote:
> >>>> From: Sean Paul <seanpaul@chromium.org>
> >>>>
> >>>> This patch adds a helper to tease out the currently connected crtc for
> >>>> an encoder, along with its state. This follows the same pattern as the
> >>>> drm_atomic_crtc_*_for_* macros in the atomic helpers. Since the
> >>>> relationship of crtc:encoder is 1:n, we don't need a loop since there is
> >>>> only one crtc per encoder.
> >>>
> >>> No idea which macros you mean, couldn't find them.
> >>
> >> No longer relevant with the changes below, but for completeness, I was trying to
> >> refer to drm_atomic_crtc_state_for_each_plane and friends. I see now that I
> >> wasn't terribly clear :)
> >>
> >>>> Instead of splitting this into 3 functions which all do the same thing,
> >>>> this is presented as one function. Perhaps that's too ugly and it should
> >>>> be split to:
> >>>> struct drm_crtc *drm_atomic_crtc_for_encoder(state, encoder);
> >>>> struct drm_crtc_state *drm_atomic_new_crtc_state_for_encoder(state, encoder);
> >>>> struct drm_crtc_state *drm_atomic_old_crtc_state_for_encoder(state, encoder);
> >>>>
> >>>> Suggestions welcome.
> >>>>
> >>>> Changes in v3:
> >>>> - Added to the set
> >>>>
> >>>> Cc: Daniel Vetter <daniel@ffwll.ch>
> >>>> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> >>>> ---
> >>>>  drivers/gpu/drm/drm_atomic_helper.c | 48 +++++++++++++++++++++++++++++
> >>>>  include/drm/drm_atomic_helper.h     |  6 ++++
> >>>>  2 files changed, 54 insertions(+)
> >>>>
> >>>> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> >>>> index 71cc7d6b0644..1f81ca8daad7 100644
> >>>> --- a/drivers/gpu/drm/drm_atomic_helper.c
> >>>> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> >>>> @@ -3591,3 +3591,51 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
> >>>>     return ret;
> >>>>  }
> >>>>  EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
> >>>> +
> >>>> +/**
> >>>> + * drm_atomic_crtc_state_for_encoder - Get crtc and new/old state for an encoder
> >>>> + * @state: Atomic state
> >>>> + * @encoder: The encoder to fetch the crtc information for
> >>>> + * @crtc: If not NULL, receives the currently connected crtc
> >>>> + * @old_crtc_state: If not NULL, receives the crtc's old state
> >>>> + * @new_crtc_state: If not NULL, receives the crtc's new state
> >>>> + *
> >>>> + * This function finds the crtc which is currently connected to @encoder and
> >>>> + * returns it as well as its old and new state. If there is no crtc currently
> >>>> + * connected, the function will clear @crtc, @old_crtc_state, @new_crtc_state.
> >>>> + *
> >>>> + * All of @crtc, @old_crtc_state, and @new_crtc_state are optional.
> >>>> + */
> >>>> +void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
> >>>> +                                  struct drm_encoder *encoder,
> >>>> +                                  struct drm_crtc **crtc,
> >>>> +                                  struct drm_crtc_state **old_crtc_state,
> >>>> +                                  struct drm_crtc_state **new_crtc_state)
> >>>> +{
> >>>> +   struct drm_crtc *tmp_crtc;
> >>>> +   struct drm_crtc_state *tmp_new_crtc_state, *tmp_old_crtc_state;
> >>>> +   u32 enc_mask = drm_encoder_mask(encoder);
> >>>> +   int i;
> >>>> +
> >>>> +   for_each_oldnew_crtc_in_state(state, tmp_crtc, tmp_old_crtc_state,
> >>>> +                                 tmp_new_crtc_state, i) {
> >>>
> >>> So there's two ways to do this:
> >>>
> >>> - Using encoder_mask, which is a helper thing. In that case I'd rename
> >>>   this to drm_atomic_helper_crtc_for_encoder.
> >>>
> >>> - By looping over the connectors, and looking at ->best_encoder and
> >>>   ->crtc, see drm_encoder_get_crtc in drm_encoder.c. That's the core way
> >>>   of doing things. In that case call it drm_atomic_crtc_for_encoder, and
> >>>   put it into drm_atomic.c.
> >>>
> >>> There's two ways of doing the 2nd one: looping over connectors in a
> >>> drm_atomic_state, or the connector list overall. First requires that the
> >>> encoder is already in drm_atomic_state (which I think makes sense).
> >>
> >> Yeah, I wasn't particularly interested in encoders not in state. I had
> >> considered going the connector route, but since you can have multiple connectors
> >> per encoder, going through crtc seemed a bit more direct.
> > 
> > You can have multiple possible connectors for a given encoder, and
> > multiple possible encoders for a given connector. In both cases the
> > driver picks for you. But for active encoders and connectors the
> > relationship is 1:1. That's what the helpers exploit by looping over
> > connectors to get at encoders.
> > 
> >>> Even more complications on old/new_crtc_state: Is that the old state for
> >>> the old crtc, or the old state for the new crtc (that can switch too).
> >>> Same for the new crtc state ...
> >>>
> >>> tldr; I'd create 2 functions:
> >>>
> >>> drm_crtc *drm_atomic_encoder_get_new_crtc(drm_atomic_state *state, encoder)
> >>> drm_crtc *drm_atomic_encoder_get_old_crtc(drm_atomic_state *state, encoder)
> >>>
> >>> With the requirement that they'll return NULL if the encder isn't in in
> >>> @state, and implemented using looping over connectors in @state.
> >>
> >> It seems like we could just tweak this function a bit to get the new or old crtc
> >> for an encoder. Any particular reason for going through connector instead? Is it
> >> to avoid the encoder_mask which is a helper thing? In that case, perhaps this
> >> should use connector links and live in drm_atomic.c?
> > 
> > Well as explained, there's 3 ways you can achieve the same really. I
> > do think the "loop over connectors in drm_atomic_state, WARN() if we
> > haven't found the encoder you want the crtc for" is probably the most
> > solid aproach since it picks up a core atomic concept. But the others
> > (looping the connector list, or looping encoder_mask) all work too.
> > 
> > Aside: plane/encoder_mask was added to go from crtc to
> > planes/encoders, not really to go the other way round.
> > 
> > Another solution would be to pass the connector_state to all atomic
> > encoder hooks, then you could just look at connector_state->crtc. Plus
> > you can get at all the other interesting bits and pieces of
> > information. In a way this is fallout from us keeping encoders as a
> > meaningful concept for easier transition of legacy drivers, while
> > still keeping them entirely irrelevant for the actual userspace api
> > semantics.
> > 
> > So maybe we want drm_atomic_encoder_get_old/new_connector here. Or
> > maybe we even want the full set of functions, i.e.
> > drm_atomic_encoder_get_old/new_connector/crtc.
> 
> Laurent just asked me on irc how to get from a bridge to connector
> information. Bridge knows its encoder (it's static), so a encode2connector
> function would already have a 2nd user with this.
> 
> I.e. I'd say +1 on that approach, and then you can get at the connector
> state and whatever else you feel like from there?
> 
> Adding Laurent.

Thank you. I'll experiment with this, but please don't wait for me to
post a v4.

> > In all cases I think only returning the object, not it's state is
> > simplest, since then you avoid the confusion of old/new state for
> > old/new obj.
> >
> >>> tldr; this is a lot more tricky than it looks like ...
> >>>
> >>>> +           if (!(tmp_new_crtc_state->encoder_mask & enc_mask))
> >>>> +                   continue;
> >>>> +
> >>>> +           if (new_crtc_state)
> >>>> +                   *new_crtc_state = tmp_new_crtc_state;
> >>>> +           if (old_crtc_state)
> >>>> +                   *old_crtc_state = tmp_old_crtc_state;
> >>>> +           if (crtc)
> >>>> +                   *crtc = tmp_crtc;
> >>>> +           return;
> >>>> +   }
> >>>> +
> >>>> +   if (new_crtc_state)
> >>>> +           *new_crtc_state = NULL;
> >>>> +   if (old_crtc_state)
> >>>> +           *old_crtc_state = NULL;
> >>>> +   if (crtc)
> >>>> +           *crtc = NULL;
> >>>> +}
> >>>> +EXPORT_SYMBOL(drm_atomic_crtc_state_for_encoder);
> >>>> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> >>>> index 58214be3bf3d..2383550a0cc8 100644
> >>>> --- a/include/drm/drm_atomic_helper.h
> >>>> +++ b/include/drm/drm_atomic_helper.h
> >>>> @@ -153,6 +153,12 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
> >>>>                                    uint32_t size,
> >>>>                                    struct drm_modeset_acquire_ctx *ctx);
> >>>>
> >>>> +void drm_atomic_crtc_state_for_encoder(struct drm_atomic_state *state,
> >>>> +                                  struct drm_encoder *encoder,
> >>>> +                                  struct drm_crtc **crtc,
> >>>> +                                  struct drm_crtc_state **old_crtc_state,
> >>>> +                                  struct drm_crtc_state **new_crtc_state);
> >>>> +
> >>>>  /**
> >>>>   * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
> >>>>   * @plane: the loop cursor

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state
  2019-05-02 19:49 ` [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state Sean Paul
  2019-05-03  8:19   ` Daniel Vetter
@ 2019-05-11 19:12   ` Laurent Pinchart
  2019-05-13 14:38     ` Sean Paul
  2019-05-13 14:47     ` Daniel Vetter
  1 sibling, 2 replies; 29+ messages in thread
From: Laurent Pinchart @ 2019-05-11 19:12 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Sean Paul, Daniel Vetter, Ville Syrjälä,
	Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs,
	Kieran Bingham, Eric Anholt, Maarten Lankhorst, Maxime Ripard,
	David Airlie, linux-kernel, intel-gfx, nouveau,
	linux-renesas-soc

Hi Sean,

Thank you for the patch.

On Thu, May 02, 2019 at 03:49:46PM -0400, Sean Paul wrote:
> From: Sean Paul <seanpaul@chromium.org>
> 
> Everyone who implements connector_helper_funcs->atomic_check reaches
> into the connector state to get the atomic state. Instead of continuing
> this pattern, change the callback signature to just give atomic state
> and let the driver determine what it does and does not need from it.
> 
> Eventually all atomic functions should do this, but that's just too much
> busy work for me.

Given that drivers also access the connector state, isn't this slightly
more inefficient ?

> Changes in v3:
> - Added to the set
> 
> Cc: Daniel Vetter <daniel@ffwll.ch>
> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Cc: Ben Skeggs <bskeggs@redhat.com>
> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> Cc: Eric Anholt <eric@anholt.net>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> ---
>  drivers/gpu/drm/drm_atomic_helper.c      |  4 ++--
>  drivers/gpu/drm/i915/intel_atomic.c      |  8 +++++---
>  drivers/gpu/drm/i915/intel_dp_mst.c      |  7 ++++---
>  drivers/gpu/drm/i915/intel_drv.h         |  2 +-
>  drivers/gpu/drm/i915/intel_sdvo.c        |  9 +++++----
>  drivers/gpu/drm/i915/intel_tv.c          |  8 +++++---
>  drivers/gpu/drm/nouveau/dispnv50/disp.c  |  5 +++--
>  drivers/gpu/drm/rcar-du/rcar_lvds.c      | 12 +++++++-----
>  drivers/gpu/drm/vc4/vc4_txp.c            |  7 ++++---
>  include/drm/drm_modeset_helper_vtables.h |  2 +-
>  10 files changed, 37 insertions(+), 27 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 9d9e47276839..fa5a367507c1 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -683,7 +683,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
>  		}
>  
>  		if (funcs->atomic_check)
> -			ret = funcs->atomic_check(connector, new_connector_state);
> +			ret = funcs->atomic_check(connector, state);
>  		if (ret)
>  			return ret;
>  
> @@ -725,7 +725,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
>  			continue;
>  
>  		if (funcs->atomic_check)
> -			ret = funcs->atomic_check(connector, new_connector_state);
> +			ret = funcs->atomic_check(connector, state);
>  		if (ret)
>  			return ret;
>  	}
> diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> index b844e8840c6f..e8a5b82e9242 100644
> --- a/drivers/gpu/drm/i915/intel_atomic.c
> +++ b/drivers/gpu/drm/i915/intel_atomic.c
> @@ -103,12 +103,14 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
>  }
>  
>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> -					 struct drm_connector_state *new_state)
> +					 struct drm_atomic_state *state)
>  {
> +	struct drm_connector_state *new_state =
> +		drm_atomic_get_new_connector_state(state, conn);
>  	struct intel_digital_connector_state *new_conn_state =
>  		to_intel_digital_connector_state(new_state);
>  	struct drm_connector_state *old_state =
> -		drm_atomic_get_old_connector_state(new_state->state, conn);
> +		drm_atomic_get_old_connector_state(state, conn);
>  	struct intel_digital_connector_state *old_conn_state =
>  		to_intel_digital_connector_state(old_state);
>  	struct drm_crtc_state *crtc_state;
> @@ -118,7 +120,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
>  	if (!new_state->crtc)
>  		return 0;
>  
> -	crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> +	crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
>  
>  	/*
>  	 * These properties are handled by fastset, and might not end
> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> index 19d81cef2ab6..89cfec128ba0 100644
> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> @@ -143,9 +143,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
>  
>  static int
>  intel_dp_mst_atomic_check(struct drm_connector *connector,
> -			  struct drm_connector_state *new_conn_state)
> +			  struct drm_atomic_state *state)
>  {
> -	struct drm_atomic_state *state = new_conn_state->state;
> +	struct drm_connector_state *new_conn_state =
> +		drm_atomic_get_new_connector_state(state, connector);
>  	struct drm_connector_state *old_conn_state =
>  		drm_atomic_get_old_connector_state(state, connector);
>  	struct intel_connector *intel_connector =
> @@ -155,7 +156,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
>  	struct drm_dp_mst_topology_mgr *mgr;
>  	int ret;
>  
> -	ret = intel_digital_connector_atomic_check(connector, new_conn_state);
> +	ret = intel_digital_connector_atomic_check(connector, state);
>  	if (ret)
>  		return ret;
>  
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index f8c7b291fdc3..88571b8e8d62 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -2481,7 +2481,7 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
>  						struct drm_property *property,
>  						u64 val);
>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> -					 struct drm_connector_state *new_state);
> +					 struct drm_atomic_state *state);
>  struct drm_connector_state *
>  intel_digital_connector_duplicate_state(struct drm_connector *connector);
>  
> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> index 68f497493d43..72ea164b971c 100644
> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> @@ -2342,9 +2342,10 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
>  };
>  
>  static int intel_sdvo_atomic_check(struct drm_connector *conn,
> -				   struct drm_connector_state *new_conn_state)
> +				   struct drm_atomic_state *state)
>  {
> -	struct drm_atomic_state *state = new_conn_state->state;
> +	struct drm_connector_state *new_conn_state =
> +		drm_atomic_get_new_connector_state(state, conn);
>  	struct drm_connector_state *old_conn_state =
>  		drm_atomic_get_old_connector_state(state, conn);
>  	struct intel_sdvo_connector_state *old_state =
> @@ -2356,13 +2357,13 @@ static int intel_sdvo_atomic_check(struct drm_connector *conn,
>  	    (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
>  	     memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
>  		struct drm_crtc_state *crtc_state =
> -			drm_atomic_get_new_crtc_state(new_conn_state->state,
> +			drm_atomic_get_new_crtc_state(state,
>  						      new_conn_state->crtc);
>  
>  		crtc_state->connectors_changed = true;
>  	}
>  
> -	return intel_digital_connector_atomic_check(conn, new_conn_state);
> +	return intel_digital_connector_atomic_check(conn, state);
>  }
>  
>  static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> index 3924c4944e1f..a41c5b467c14 100644
> --- a/drivers/gpu/drm/i915/intel_tv.c
> +++ b/drivers/gpu/drm/i915/intel_tv.c
> @@ -1817,16 +1817,18 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
>  };
>  
>  static int intel_tv_atomic_check(struct drm_connector *connector,
> -				 struct drm_connector_state *new_state)
> +				 struct drm_atomic_state *state)
>  {
> +	struct drm_connector_state *new_state;
>  	struct drm_crtc_state *new_crtc_state;
>  	struct drm_connector_state *old_state;
>  
> +	new_state = drm_atomic_get_new_connector_state(state, connector);
>  	if (!new_state->crtc)
>  		return 0;
>  
> -	old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
> -	new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> +	old_state = drm_atomic_get_old_connector_state(state, connector);
> +	new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
>  
>  	if (old_state->tv.mode != new_state->tv.mode ||
>  	    old_state->tv.margins.left != new_state->tv.margins.left ||
> diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> index 4b1650f51955..7ba373f493b2 100644
> --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> @@ -948,11 +948,12 @@ nv50_mstc_get_modes(struct drm_connector *connector)
>  
>  static int
>  nv50_mstc_atomic_check(struct drm_connector *connector,
> -		       struct drm_connector_state *new_conn_state)
> +		       struct drm_atomic_state *state)
>  {
> -	struct drm_atomic_state *state = new_conn_state->state;
>  	struct nv50_mstc *mstc = nv50_mstc(connector);
>  	struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr;
> +	struct drm_connector_state *new_conn_state =
> +		drm_atomic_get_new_connector_state(state, connector);
>  	struct drm_connector_state *old_conn_state =
>  		drm_atomic_get_old_connector_state(state, connector);
>  	struct drm_crtc_state *crtc_state;
> diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> index 620b51aab291..5b81ba2a7f27 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> @@ -92,13 +92,15 @@ static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
>  }
>  
>  static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> -					    struct drm_connector_state *state)
> +					    struct drm_atomic_state *state)
>  {
>  	struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
>  	const struct drm_display_mode *panel_mode;
> +	struct drm_connector_state *conn_state;
>  	struct drm_crtc_state *crtc_state;
>  
> -	if (!state->crtc)
> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> +	if (!conn_state->crtc)
>  		return 0;
>  
>  	if (list_empty(&connector->modes)) {
> @@ -110,9 +112,9 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
>  				      struct drm_display_mode, head);
>  
>  	/* We're not allowed to modify the resolution. */
> -	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
> -	if (IS_ERR(crtc_state))
> -		return PTR_ERR(crtc_state);
> +	crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
> +	if (!crtc_state)
> +		return -EINVAL;
>  
>  	if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
>  	    crtc_state->mode.vdisplay != panel_mode->vdisplay)
> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> index c8b89a78f9f4..96f91c1b4b6e 100644
> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> @@ -221,17 +221,18 @@ static const u32 txp_fmts[] = {
>  };
>  
>  static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
> -					struct drm_connector_state *conn_state)
> +					  struct drm_atomic_state *state)
>  {
> +	struct drm_connector_state *conn_state;
>  	struct drm_crtc_state *crtc_state;
>  	struct drm_framebuffer *fb;
>  	int i;
>  
> +	conn_state = drm_atomic_get_new_connector_state(state, conn);
>  	if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
>  		return 0;
>  
> -	crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
> -						   conn_state->crtc);
> +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
>  
>  	fb = conn_state->writeback_job->fb;
>  	if (fb->width != crtc_state->mode.hdisplay ||
> diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> index de57fb40cb6e..adc8b7cf64b5 100644
> --- a/include/drm/drm_modeset_helper_vtables.h
> +++ b/include/drm/drm_modeset_helper_vtables.h
> @@ -1020,7 +1020,7 @@ struct drm_connector_helper_funcs {
>  	 * deadlock.
>  	 */
>  	int (*atomic_check)(struct drm_connector *connector,
> -			    struct drm_connector_state *state);
> +			    struct drm_atomic_state *state);
>  
>  	/**
>  	 * @atomic_commit:

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state
  2019-05-11 19:12   ` Laurent Pinchart
@ 2019-05-13 14:38     ` Sean Paul
  2019-05-16 12:00       ` Laurent Pinchart
  2019-05-13 14:47     ` Daniel Vetter
  1 sibling, 1 reply; 29+ messages in thread
From: Sean Paul @ 2019-05-13 14:38 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: dri-devel, Sean Paul, Daniel Vetter, Ville Syrjälä,
	Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs,
	Kieran Bingham, Eric Anholt, Maarten Lankhorst, Maxime Ripard,
	David Airlie, LKML, Intel Graphics Development, nouveau,
	linux-renesas-soc

On Sat, May 11, 2019 at 3:12 PM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Sean,
>
> Thank you for the patch.
>

Hey Laurent,
Thanks for looking!


> On Thu, May 02, 2019 at 03:49:46PM -0400, Sean Paul wrote:
> > From: Sean Paul <seanpaul@chromium.org>
> >
> > Everyone who implements connector_helper_funcs->atomic_check reaches
> > into the connector state to get the atomic state. Instead of continuing
> > this pattern, change the callback signature to just give atomic state
> > and let the driver determine what it does and does not need from it.
> >
> > Eventually all atomic functions should do this, but that's just too much
> > busy work for me.
>
> Given that drivers also access the connector state, isn't this slightly
> more inefficient ?
>

Inefficient in terms of what?

Agree that in isolation this patch might seem unnecessary, but it ties
in with the encoder and bridge CLs which accept drm_atomic_state in
their hooks. In general the idea is to convert all atomic functions to
take overall atomic state instead of just their object state. Reality
has proven to be more complicated and we need more access than what
the current implementation provides.

Sean

> > Changes in v3:
> > - Added to the set
> >
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Cc: Jani Nikula <jani.nikula@linux.intel.com>
> > Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> > Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > Cc: Ben Skeggs <bskeggs@redhat.com>
> > Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> > Cc: Eric Anholt <eric@anholt.net>
> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > ---
> >  drivers/gpu/drm/drm_atomic_helper.c      |  4 ++--
> >  drivers/gpu/drm/i915/intel_atomic.c      |  8 +++++---
> >  drivers/gpu/drm/i915/intel_dp_mst.c      |  7 ++++---
> >  drivers/gpu/drm/i915/intel_drv.h         |  2 +-
> >  drivers/gpu/drm/i915/intel_sdvo.c        |  9 +++++----
> >  drivers/gpu/drm/i915/intel_tv.c          |  8 +++++---
> >  drivers/gpu/drm/nouveau/dispnv50/disp.c  |  5 +++--
> >  drivers/gpu/drm/rcar-du/rcar_lvds.c      | 12 +++++++-----
> >  drivers/gpu/drm/vc4/vc4_txp.c            |  7 ++++---
> >  include/drm/drm_modeset_helper_vtables.h |  2 +-
> >  10 files changed, 37 insertions(+), 27 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > index 9d9e47276839..fa5a367507c1 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -683,7 +683,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> >               }
> >
> >               if (funcs->atomic_check)
> > -                     ret = funcs->atomic_check(connector, new_connector_state);
> > +                     ret = funcs->atomic_check(connector, state);
> >               if (ret)
> >                       return ret;
> >
> > @@ -725,7 +725,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> >                       continue;
> >
> >               if (funcs->atomic_check)
> > -                     ret = funcs->atomic_check(connector, new_connector_state);
> > +                     ret = funcs->atomic_check(connector, state);
> >               if (ret)
> >                       return ret;
> >       }
> > diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> > index b844e8840c6f..e8a5b82e9242 100644
> > --- a/drivers/gpu/drm/i915/intel_atomic.c
> > +++ b/drivers/gpu/drm/i915/intel_atomic.c
> > @@ -103,12 +103,14 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> >  }
> >
> >  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> > -                                      struct drm_connector_state *new_state)
> > +                                      struct drm_atomic_state *state)
> >  {
> > +     struct drm_connector_state *new_state =
> > +             drm_atomic_get_new_connector_state(state, conn);
> >       struct intel_digital_connector_state *new_conn_state =
> >               to_intel_digital_connector_state(new_state);
> >       struct drm_connector_state *old_state =
> > -             drm_atomic_get_old_connector_state(new_state->state, conn);
> > +             drm_atomic_get_old_connector_state(state, conn);
> >       struct intel_digital_connector_state *old_conn_state =
> >               to_intel_digital_connector_state(old_state);
> >       struct drm_crtc_state *crtc_state;
> > @@ -118,7 +120,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
> >       if (!new_state->crtc)
> >               return 0;
> >
> > -     crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> > +     crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> >
> >       /*
> >        * These properties are handled by fastset, and might not end
> > diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> > index 19d81cef2ab6..89cfec128ba0 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> > @@ -143,9 +143,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
> >
> >  static int
> >  intel_dp_mst_atomic_check(struct drm_connector *connector,
> > -                       struct drm_connector_state *new_conn_state)
> > +                       struct drm_atomic_state *state)
> >  {
> > -     struct drm_atomic_state *state = new_conn_state->state;
> > +     struct drm_connector_state *new_conn_state =
> > +             drm_atomic_get_new_connector_state(state, connector);
> >       struct drm_connector_state *old_conn_state =
> >               drm_atomic_get_old_connector_state(state, connector);
> >       struct intel_connector *intel_connector =
> > @@ -155,7 +156,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
> >       struct drm_dp_mst_topology_mgr *mgr;
> >       int ret;
> >
> > -     ret = intel_digital_connector_atomic_check(connector, new_conn_state);
> > +     ret = intel_digital_connector_atomic_check(connector, state);
> >       if (ret)
> >               return ret;
> >
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index f8c7b291fdc3..88571b8e8d62 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -2481,7 +2481,7 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> >                                               struct drm_property *property,
> >                                               u64 val);
> >  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> > -                                      struct drm_connector_state *new_state);
> > +                                      struct drm_atomic_state *state);
> >  struct drm_connector_state *
> >  intel_digital_connector_duplicate_state(struct drm_connector *connector);
> >
> > diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> > index 68f497493d43..72ea164b971c 100644
> > --- a/drivers/gpu/drm/i915/intel_sdvo.c
> > +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> > @@ -2342,9 +2342,10 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
> >  };
> >
> >  static int intel_sdvo_atomic_check(struct drm_connector *conn,
> > -                                struct drm_connector_state *new_conn_state)
> > +                                struct drm_atomic_state *state)
> >  {
> > -     struct drm_atomic_state *state = new_conn_state->state;
> > +     struct drm_connector_state *new_conn_state =
> > +             drm_atomic_get_new_connector_state(state, conn);
> >       struct drm_connector_state *old_conn_state =
> >               drm_atomic_get_old_connector_state(state, conn);
> >       struct intel_sdvo_connector_state *old_state =
> > @@ -2356,13 +2357,13 @@ static int intel_sdvo_atomic_check(struct drm_connector *conn,
> >           (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
> >            memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
> >               struct drm_crtc_state *crtc_state =
> > -                     drm_atomic_get_new_crtc_state(new_conn_state->state,
> > +                     drm_atomic_get_new_crtc_state(state,
> >                                                     new_conn_state->crtc);
> >
> >               crtc_state->connectors_changed = true;
> >       }
> >
> > -     return intel_digital_connector_atomic_check(conn, new_conn_state);
> > +     return intel_digital_connector_atomic_check(conn, state);
> >  }
> >
> >  static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
> > diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> > index 3924c4944e1f..a41c5b467c14 100644
> > --- a/drivers/gpu/drm/i915/intel_tv.c
> > +++ b/drivers/gpu/drm/i915/intel_tv.c
> > @@ -1817,16 +1817,18 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
> >  };
> >
> >  static int intel_tv_atomic_check(struct drm_connector *connector,
> > -                              struct drm_connector_state *new_state)
> > +                              struct drm_atomic_state *state)
> >  {
> > +     struct drm_connector_state *new_state;
> >       struct drm_crtc_state *new_crtc_state;
> >       struct drm_connector_state *old_state;
> >
> > +     new_state = drm_atomic_get_new_connector_state(state, connector);
> >       if (!new_state->crtc)
> >               return 0;
> >
> > -     old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
> > -     new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> > +     old_state = drm_atomic_get_old_connector_state(state, connector);
> > +     new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> >
> >       if (old_state->tv.mode != new_state->tv.mode ||
> >           old_state->tv.margins.left != new_state->tv.margins.left ||
> > diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > index 4b1650f51955..7ba373f493b2 100644
> > --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > @@ -948,11 +948,12 @@ nv50_mstc_get_modes(struct drm_connector *connector)
> >
> >  static int
> >  nv50_mstc_atomic_check(struct drm_connector *connector,
> > -                    struct drm_connector_state *new_conn_state)
> > +                    struct drm_atomic_state *state)
> >  {
> > -     struct drm_atomic_state *state = new_conn_state->state;
> >       struct nv50_mstc *mstc = nv50_mstc(connector);
> >       struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr;
> > +     struct drm_connector_state *new_conn_state =
> > +             drm_atomic_get_new_connector_state(state, connector);
> >       struct drm_connector_state *old_conn_state =
> >               drm_atomic_get_old_connector_state(state, connector);
> >       struct drm_crtc_state *crtc_state;
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > index 620b51aab291..5b81ba2a7f27 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > @@ -92,13 +92,15 @@ static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
> >  }
> >
> >  static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> > -                                         struct drm_connector_state *state)
> > +                                         struct drm_atomic_state *state)
> >  {
> >       struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
> >       const struct drm_display_mode *panel_mode;
> > +     struct drm_connector_state *conn_state;
> >       struct drm_crtc_state *crtc_state;
> >
> > -     if (!state->crtc)
> > +     conn_state = drm_atomic_get_new_connector_state(state, connector);
> > +     if (!conn_state->crtc)
> >               return 0;
> >
> >       if (list_empty(&connector->modes)) {
> > @@ -110,9 +112,9 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> >                                     struct drm_display_mode, head);
> >
> >       /* We're not allowed to modify the resolution. */
> > -     crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
> > -     if (IS_ERR(crtc_state))
> > -             return PTR_ERR(crtc_state);
> > +     crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
> > +     if (!crtc_state)
> > +             return -EINVAL;
> >
> >       if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
> >           crtc_state->mode.vdisplay != panel_mode->vdisplay)
> > diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> > index c8b89a78f9f4..96f91c1b4b6e 100644
> > --- a/drivers/gpu/drm/vc4/vc4_txp.c
> > +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> > @@ -221,17 +221,18 @@ static const u32 txp_fmts[] = {
> >  };
> >
> >  static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
> > -                                     struct drm_connector_state *conn_state)
> > +                                       struct drm_atomic_state *state)
> >  {
> > +     struct drm_connector_state *conn_state;
> >       struct drm_crtc_state *crtc_state;
> >       struct drm_framebuffer *fb;
> >       int i;
> >
> > +     conn_state = drm_atomic_get_new_connector_state(state, conn);
> >       if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
> >               return 0;
> >
> > -     crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
> > -                                                conn_state->crtc);
> > +     crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> >
> >       fb = conn_state->writeback_job->fb;
> >       if (fb->width != crtc_state->mode.hdisplay ||
> > diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> > index de57fb40cb6e..adc8b7cf64b5 100644
> > --- a/include/drm/drm_modeset_helper_vtables.h
> > +++ b/include/drm/drm_modeset_helper_vtables.h
> > @@ -1020,7 +1020,7 @@ struct drm_connector_helper_funcs {
> >        * deadlock.
> >        */
> >       int (*atomic_check)(struct drm_connector *connector,
> > -                         struct drm_connector_state *state);
> > +                         struct drm_atomic_state *state);
> >
> >       /**
> >        * @atomic_commit:
>
> --
> Regards,
>
> Laurent Pinchart

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state
  2019-05-11 19:12   ` Laurent Pinchart
  2019-05-13 14:38     ` Sean Paul
@ 2019-05-13 14:47     ` Daniel Vetter
  2019-05-16 12:02       ` Laurent Pinchart
  1 sibling, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2019-05-13 14:47 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Sean Paul, dri-devel, Sean Paul, Daniel Vetter,
	Ville Syrjälä,
	Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs,
	Kieran Bingham, Eric Anholt, Maarten Lankhorst, Maxime Ripard,
	David Airlie, linux-kernel, intel-gfx, nouveau,
	linux-renesas-soc

On Sat, May 11, 2019 at 10:12:02PM +0300, Laurent Pinchart wrote:
> Hi Sean,
> 
> Thank you for the patch.
> 
> On Thu, May 02, 2019 at 03:49:46PM -0400, Sean Paul wrote:
> > From: Sean Paul <seanpaul@chromium.org>
> > 
> > Everyone who implements connector_helper_funcs->atomic_check reaches
> > into the connector state to get the atomic state. Instead of continuing
> > this pattern, change the callback signature to just give atomic state
> > and let the driver determine what it does and does not need from it.
> > 
> > Eventually all atomic functions should do this, but that's just too much
> > busy work for me.
> 
> Given that drivers also access the connector state, isn't this slightly
> more inefficient ?

It's atomic code, we're trying to optimize for clean code at the expense
of a bit of runtime overhead due to more pointer chasing. And I agree with
the general push, the pile of old/new_state pointers of various objects
we're passing around is confusing. Passing the overall drm_atomic_state
seems much more reasonable, and with that we can get everything else. Plus
it's much more obvious whether you have the old/new state (since that's
explicit when you look it up from the drm_atomic_state).

If we ever see this show up in profile, and it starts mattering, first
thing we need is a hashtable I think (atm it's list walking, which is just
terrible). But thus far no one cares.
-Daniel

> 
> > Changes in v3:
> > - Added to the set
> > 
> > Cc: Daniel Vetter <daniel@ffwll.ch>
> > Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > Cc: Jani Nikula <jani.nikula@linux.intel.com>
> > Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> > Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > Cc: Ben Skeggs <bskeggs@redhat.com>
> > Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> > Cc: Eric Anholt <eric@anholt.net>
> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > ---
> >  drivers/gpu/drm/drm_atomic_helper.c      |  4 ++--
> >  drivers/gpu/drm/i915/intel_atomic.c      |  8 +++++---
> >  drivers/gpu/drm/i915/intel_dp_mst.c      |  7 ++++---
> >  drivers/gpu/drm/i915/intel_drv.h         |  2 +-
> >  drivers/gpu/drm/i915/intel_sdvo.c        |  9 +++++----
> >  drivers/gpu/drm/i915/intel_tv.c          |  8 +++++---
> >  drivers/gpu/drm/nouveau/dispnv50/disp.c  |  5 +++--
> >  drivers/gpu/drm/rcar-du/rcar_lvds.c      | 12 +++++++-----
> >  drivers/gpu/drm/vc4/vc4_txp.c            |  7 ++++---
> >  include/drm/drm_modeset_helper_vtables.h |  2 +-
> >  10 files changed, 37 insertions(+), 27 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > index 9d9e47276839..fa5a367507c1 100644
> > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > @@ -683,7 +683,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> >  		}
> >  
> >  		if (funcs->atomic_check)
> > -			ret = funcs->atomic_check(connector, new_connector_state);
> > +			ret = funcs->atomic_check(connector, state);
> >  		if (ret)
> >  			return ret;
> >  
> > @@ -725,7 +725,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> >  			continue;
> >  
> >  		if (funcs->atomic_check)
> > -			ret = funcs->atomic_check(connector, new_connector_state);
> > +			ret = funcs->atomic_check(connector, state);
> >  		if (ret)
> >  			return ret;
> >  	}
> > diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> > index b844e8840c6f..e8a5b82e9242 100644
> > --- a/drivers/gpu/drm/i915/intel_atomic.c
> > +++ b/drivers/gpu/drm/i915/intel_atomic.c
> > @@ -103,12 +103,14 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> >  }
> >  
> >  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> > -					 struct drm_connector_state *new_state)
> > +					 struct drm_atomic_state *state)
> >  {
> > +	struct drm_connector_state *new_state =
> > +		drm_atomic_get_new_connector_state(state, conn);
> >  	struct intel_digital_connector_state *new_conn_state =
> >  		to_intel_digital_connector_state(new_state);
> >  	struct drm_connector_state *old_state =
> > -		drm_atomic_get_old_connector_state(new_state->state, conn);
> > +		drm_atomic_get_old_connector_state(state, conn);
> >  	struct intel_digital_connector_state *old_conn_state =
> >  		to_intel_digital_connector_state(old_state);
> >  	struct drm_crtc_state *crtc_state;
> > @@ -118,7 +120,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
> >  	if (!new_state->crtc)
> >  		return 0;
> >  
> > -	crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> > +	crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> >  
> >  	/*
> >  	 * These properties are handled by fastset, and might not end
> > diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> > index 19d81cef2ab6..89cfec128ba0 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> > @@ -143,9 +143,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
> >  
> >  static int
> >  intel_dp_mst_atomic_check(struct drm_connector *connector,
> > -			  struct drm_connector_state *new_conn_state)
> > +			  struct drm_atomic_state *state)
> >  {
> > -	struct drm_atomic_state *state = new_conn_state->state;
> > +	struct drm_connector_state *new_conn_state =
> > +		drm_atomic_get_new_connector_state(state, connector);
> >  	struct drm_connector_state *old_conn_state =
> >  		drm_atomic_get_old_connector_state(state, connector);
> >  	struct intel_connector *intel_connector =
> > @@ -155,7 +156,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
> >  	struct drm_dp_mst_topology_mgr *mgr;
> >  	int ret;
> >  
> > -	ret = intel_digital_connector_atomic_check(connector, new_conn_state);
> > +	ret = intel_digital_connector_atomic_check(connector, state);
> >  	if (ret)
> >  		return ret;
> >  
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index f8c7b291fdc3..88571b8e8d62 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -2481,7 +2481,7 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> >  						struct drm_property *property,
> >  						u64 val);
> >  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> > -					 struct drm_connector_state *new_state);
> > +					 struct drm_atomic_state *state);
> >  struct drm_connector_state *
> >  intel_digital_connector_duplicate_state(struct drm_connector *connector);
> >  
> > diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> > index 68f497493d43..72ea164b971c 100644
> > --- a/drivers/gpu/drm/i915/intel_sdvo.c
> > +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> > @@ -2342,9 +2342,10 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
> >  };
> >  
> >  static int intel_sdvo_atomic_check(struct drm_connector *conn,
> > -				   struct drm_connector_state *new_conn_state)
> > +				   struct drm_atomic_state *state)
> >  {
> > -	struct drm_atomic_state *state = new_conn_state->state;
> > +	struct drm_connector_state *new_conn_state =
> > +		drm_atomic_get_new_connector_state(state, conn);
> >  	struct drm_connector_state *old_conn_state =
> >  		drm_atomic_get_old_connector_state(state, conn);
> >  	struct intel_sdvo_connector_state *old_state =
> > @@ -2356,13 +2357,13 @@ static int intel_sdvo_atomic_check(struct drm_connector *conn,
> >  	    (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
> >  	     memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
> >  		struct drm_crtc_state *crtc_state =
> > -			drm_atomic_get_new_crtc_state(new_conn_state->state,
> > +			drm_atomic_get_new_crtc_state(state,
> >  						      new_conn_state->crtc);
> >  
> >  		crtc_state->connectors_changed = true;
> >  	}
> >  
> > -	return intel_digital_connector_atomic_check(conn, new_conn_state);
> > +	return intel_digital_connector_atomic_check(conn, state);
> >  }
> >  
> >  static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
> > diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> > index 3924c4944e1f..a41c5b467c14 100644
> > --- a/drivers/gpu/drm/i915/intel_tv.c
> > +++ b/drivers/gpu/drm/i915/intel_tv.c
> > @@ -1817,16 +1817,18 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
> >  };
> >  
> >  static int intel_tv_atomic_check(struct drm_connector *connector,
> > -				 struct drm_connector_state *new_state)
> > +				 struct drm_atomic_state *state)
> >  {
> > +	struct drm_connector_state *new_state;
> >  	struct drm_crtc_state *new_crtc_state;
> >  	struct drm_connector_state *old_state;
> >  
> > +	new_state = drm_atomic_get_new_connector_state(state, connector);
> >  	if (!new_state->crtc)
> >  		return 0;
> >  
> > -	old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
> > -	new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> > +	old_state = drm_atomic_get_old_connector_state(state, connector);
> > +	new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> >  
> >  	if (old_state->tv.mode != new_state->tv.mode ||
> >  	    old_state->tv.margins.left != new_state->tv.margins.left ||
> > diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > index 4b1650f51955..7ba373f493b2 100644
> > --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > @@ -948,11 +948,12 @@ nv50_mstc_get_modes(struct drm_connector *connector)
> >  
> >  static int
> >  nv50_mstc_atomic_check(struct drm_connector *connector,
> > -		       struct drm_connector_state *new_conn_state)
> > +		       struct drm_atomic_state *state)
> >  {
> > -	struct drm_atomic_state *state = new_conn_state->state;
> >  	struct nv50_mstc *mstc = nv50_mstc(connector);
> >  	struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr;
> > +	struct drm_connector_state *new_conn_state =
> > +		drm_atomic_get_new_connector_state(state, connector);
> >  	struct drm_connector_state *old_conn_state =
> >  		drm_atomic_get_old_connector_state(state, connector);
> >  	struct drm_crtc_state *crtc_state;
> > diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > index 620b51aab291..5b81ba2a7f27 100644
> > --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > @@ -92,13 +92,15 @@ static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
> >  }
> >  
> >  static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> > -					    struct drm_connector_state *state)
> > +					    struct drm_atomic_state *state)
> >  {
> >  	struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
> >  	const struct drm_display_mode *panel_mode;
> > +	struct drm_connector_state *conn_state;
> >  	struct drm_crtc_state *crtc_state;
> >  
> > -	if (!state->crtc)
> > +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> > +	if (!conn_state->crtc)
> >  		return 0;
> >  
> >  	if (list_empty(&connector->modes)) {
> > @@ -110,9 +112,9 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> >  				      struct drm_display_mode, head);
> >  
> >  	/* We're not allowed to modify the resolution. */
> > -	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
> > -	if (IS_ERR(crtc_state))
> > -		return PTR_ERR(crtc_state);
> > +	crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
> > +	if (!crtc_state)
> > +		return -EINVAL;
> >  
> >  	if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
> >  	    crtc_state->mode.vdisplay != panel_mode->vdisplay)
> > diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> > index c8b89a78f9f4..96f91c1b4b6e 100644
> > --- a/drivers/gpu/drm/vc4/vc4_txp.c
> > +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> > @@ -221,17 +221,18 @@ static const u32 txp_fmts[] = {
> >  };
> >  
> >  static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
> > -					struct drm_connector_state *conn_state)
> > +					  struct drm_atomic_state *state)
> >  {
> > +	struct drm_connector_state *conn_state;
> >  	struct drm_crtc_state *crtc_state;
> >  	struct drm_framebuffer *fb;
> >  	int i;
> >  
> > +	conn_state = drm_atomic_get_new_connector_state(state, conn);
> >  	if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
> >  		return 0;
> >  
> > -	crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
> > -						   conn_state->crtc);
> > +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> >  
> >  	fb = conn_state->writeback_job->fb;
> >  	if (fb->width != crtc_state->mode.hdisplay ||
> > diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> > index de57fb40cb6e..adc8b7cf64b5 100644
> > --- a/include/drm/drm_modeset_helper_vtables.h
> > +++ b/include/drm/drm_modeset_helper_vtables.h
> > @@ -1020,7 +1020,7 @@ struct drm_connector_helper_funcs {
> >  	 * deadlock.
> >  	 */
> >  	int (*atomic_check)(struct drm_connector *connector,
> > -			    struct drm_connector_state *state);
> > +			    struct drm_atomic_state *state);
> >  
> >  	/**
> >  	 * @atomic_commit:
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state
  2019-05-13 14:38     ` Sean Paul
@ 2019-05-16 12:00       ` Laurent Pinchart
  2019-05-16 14:21         ` Sean Paul
  0 siblings, 1 reply; 29+ messages in thread
From: Laurent Pinchart @ 2019-05-16 12:00 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Sean Paul, Daniel Vetter, Ville Syrjälä,
	Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs,
	Kieran Bingham, Eric Anholt, Maarten Lankhorst, Maxime Ripard,
	David Airlie, LKML, Intel Graphics Development, nouveau,
	linux-renesas-soc

Hi Sean,

On Mon, May 13, 2019 at 10:38:58AM -0400, Sean Paul wrote:
> On Sat, May 11, 2019 at 3:12 PM Laurent Pinchart wrote:
> > On Thu, May 02, 2019 at 03:49:46PM -0400, Sean Paul wrote:
> >> From: Sean Paul <seanpaul@chromium.org>
> >>
> >> Everyone who implements connector_helper_funcs->atomic_check reaches
> >> into the connector state to get the atomic state. Instead of continuing
> >> this pattern, change the callback signature to just give atomic state
> >> and let the driver determine what it does and does not need from it.
> >>
> >> Eventually all atomic functions should do this, but that's just too much
> >> busy work for me.
> >
> > Given that drivers also access the connector state, isn't this slightly
> > more inefficient ?
> 
> Inefficient in terms of what?

In terms of the operation having to lookup the connector state, when the
caller has it and can easily pass it. As Daniel commented, this may be
the price to pay for a cleaner API, but I wonder how much overhead all
the state tracking is costing.

> Agree that in isolation this patch might seem unnecessary, but it ties
> in with the encoder and bridge CLs which accept drm_atomic_state in

CLs ?

> their hooks. In general the idea is to convert all atomic functions to
> take overall atomic state instead of just their object state. Reality
> has proven to be more complicated and we need more access than what
> the current implementation provides.
> 
> Sean
> 
> >> Changes in v3:
> >> - Added to the set
> >>
> >> Cc: Daniel Vetter <daniel@ffwll.ch>
> >> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> >> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> >> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> >> Cc: Ben Skeggs <bskeggs@redhat.com>
> >> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >> Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> >> Cc: Eric Anholt <eric@anholt.net>
> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> >> ---
> >>  drivers/gpu/drm/drm_atomic_helper.c      |  4 ++--
> >>  drivers/gpu/drm/i915/intel_atomic.c      |  8 +++++---
> >>  drivers/gpu/drm/i915/intel_dp_mst.c      |  7 ++++---
> >>  drivers/gpu/drm/i915/intel_drv.h         |  2 +-
> >>  drivers/gpu/drm/i915/intel_sdvo.c        |  9 +++++----
> >>  drivers/gpu/drm/i915/intel_tv.c          |  8 +++++---
> >>  drivers/gpu/drm/nouveau/dispnv50/disp.c  |  5 +++--
> >>  drivers/gpu/drm/rcar-du/rcar_lvds.c      | 12 +++++++-----
> >>  drivers/gpu/drm/vc4/vc4_txp.c            |  7 ++++---
> >>  include/drm/drm_modeset_helper_vtables.h |  2 +-
> >>  10 files changed, 37 insertions(+), 27 deletions(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> >> index 9d9e47276839..fa5a367507c1 100644
> >> --- a/drivers/gpu/drm/drm_atomic_helper.c
> >> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> >> @@ -683,7 +683,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> >>               }
> >>
> >>               if (funcs->atomic_check)
> >> -                     ret = funcs->atomic_check(connector, new_connector_state);
> >> +                     ret = funcs->atomic_check(connector, state);
> >>               if (ret)
> >>                       return ret;
> >>
> >> @@ -725,7 +725,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> >>                       continue;
> >>
> >>               if (funcs->atomic_check)
> >> -                     ret = funcs->atomic_check(connector, new_connector_state);
> >> +                     ret = funcs->atomic_check(connector, state);
> >>               if (ret)
> >>                       return ret;
> >>       }
> >> diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> >> index b844e8840c6f..e8a5b82e9242 100644
> >> --- a/drivers/gpu/drm/i915/intel_atomic.c
> >> +++ b/drivers/gpu/drm/i915/intel_atomic.c
> >> @@ -103,12 +103,14 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> >>  }
> >>
> >>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> >> -                                      struct drm_connector_state *new_state)
> >> +                                      struct drm_atomic_state *state)
> >>  {
> >> +     struct drm_connector_state *new_state =
> >> +             drm_atomic_get_new_connector_state(state, conn);
> >>       struct intel_digital_connector_state *new_conn_state =
> >>               to_intel_digital_connector_state(new_state);
> >>       struct drm_connector_state *old_state =
> >> -             drm_atomic_get_old_connector_state(new_state->state, conn);
> >> +             drm_atomic_get_old_connector_state(state, conn);
> >>       struct intel_digital_connector_state *old_conn_state =
> >>               to_intel_digital_connector_state(old_state);
> >>       struct drm_crtc_state *crtc_state;
> >> @@ -118,7 +120,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
> >>       if (!new_state->crtc)
> >>               return 0;
> >>
> >> -     crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> >> +     crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> >>
> >>       /*
> >>        * These properties are handled by fastset, and might not end
> >> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> >> index 19d81cef2ab6..89cfec128ba0 100644
> >> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> >> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> >> @@ -143,9 +143,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
> >>
> >>  static int
> >>  intel_dp_mst_atomic_check(struct drm_connector *connector,
> >> -                       struct drm_connector_state *new_conn_state)
> >> +                       struct drm_atomic_state *state)
> >>  {
> >> -     struct drm_atomic_state *state = new_conn_state->state;
> >> +     struct drm_connector_state *new_conn_state =
> >> +             drm_atomic_get_new_connector_state(state, connector);
> >>       struct drm_connector_state *old_conn_state =
> >>               drm_atomic_get_old_connector_state(state, connector);
> >>       struct intel_connector *intel_connector =
> >> @@ -155,7 +156,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
> >>       struct drm_dp_mst_topology_mgr *mgr;
> >>       int ret;
> >>
> >> -     ret = intel_digital_connector_atomic_check(connector, new_conn_state);
> >> +     ret = intel_digital_connector_atomic_check(connector, state);
> >>       if (ret)
> >>               return ret;
> >>
> >> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> >> index f8c7b291fdc3..88571b8e8d62 100644
> >> --- a/drivers/gpu/drm/i915/intel_drv.h
> >> +++ b/drivers/gpu/drm/i915/intel_drv.h
> >> @@ -2481,7 +2481,7 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> >>                                               struct drm_property *property,
> >>                                               u64 val);
> >>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> >> -                                      struct drm_connector_state *new_state);
> >> +                                      struct drm_atomic_state *state);
> >>  struct drm_connector_state *
> >>  intel_digital_connector_duplicate_state(struct drm_connector *connector);
> >>
> >> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> >> index 68f497493d43..72ea164b971c 100644
> >> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> >> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> >> @@ -2342,9 +2342,10 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
> >>  };
> >>
> >>  static int intel_sdvo_atomic_check(struct drm_connector *conn,
> >> -                                struct drm_connector_state *new_conn_state)
> >> +                                struct drm_atomic_state *state)
> >>  {
> >> -     struct drm_atomic_state *state = new_conn_state->state;
> >> +     struct drm_connector_state *new_conn_state =
> >> +             drm_atomic_get_new_connector_state(state, conn);
> >>       struct drm_connector_state *old_conn_state =
> >>               drm_atomic_get_old_connector_state(state, conn);
> >>       struct intel_sdvo_connector_state *old_state =
> >> @@ -2356,13 +2357,13 @@ static int intel_sdvo_atomic_check(struct drm_connector *conn,
> >>           (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
> >>            memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
> >>               struct drm_crtc_state *crtc_state =
> >> -                     drm_atomic_get_new_crtc_state(new_conn_state->state,
> >> +                     drm_atomic_get_new_crtc_state(state,
> >>                                                     new_conn_state->crtc);
> >>
> >>               crtc_state->connectors_changed = true;
> >>       }
> >>
> >> -     return intel_digital_connector_atomic_check(conn, new_conn_state);
> >> +     return intel_digital_connector_atomic_check(conn, state);
> >>  }
> >>
> >>  static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
> >> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> >> index 3924c4944e1f..a41c5b467c14 100644
> >> --- a/drivers/gpu/drm/i915/intel_tv.c
> >> +++ b/drivers/gpu/drm/i915/intel_tv.c
> >> @@ -1817,16 +1817,18 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
> >>  };
> >>
> >>  static int intel_tv_atomic_check(struct drm_connector *connector,
> >> -                              struct drm_connector_state *new_state)
> >> +                              struct drm_atomic_state *state)
> >>  {
> >> +     struct drm_connector_state *new_state;
> >>       struct drm_crtc_state *new_crtc_state;
> >>       struct drm_connector_state *old_state;
> >>
> >> +     new_state = drm_atomic_get_new_connector_state(state, connector);
> >>       if (!new_state->crtc)
> >>               return 0;
> >>
> >> -     old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
> >> -     new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> >> +     old_state = drm_atomic_get_old_connector_state(state, connector);
> >> +     new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> >>
> >>       if (old_state->tv.mode != new_state->tv.mode ||
> >>           old_state->tv.margins.left != new_state->tv.margins.left ||
> >> diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> >> index 4b1650f51955..7ba373f493b2 100644
> >> --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> >> +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> >> @@ -948,11 +948,12 @@ nv50_mstc_get_modes(struct drm_connector *connector)
> >>
> >>  static int
> >>  nv50_mstc_atomic_check(struct drm_connector *connector,
> >> -                    struct drm_connector_state *new_conn_state)
> >> +                    struct drm_atomic_state *state)
> >>  {
> >> -     struct drm_atomic_state *state = new_conn_state->state;
> >>       struct nv50_mstc *mstc = nv50_mstc(connector);
> >>       struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr;
> >> +     struct drm_connector_state *new_conn_state =
> >> +             drm_atomic_get_new_connector_state(state, connector);
> >>       struct drm_connector_state *old_conn_state =
> >>               drm_atomic_get_old_connector_state(state, connector);
> >>       struct drm_crtc_state *crtc_state;
> >> diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> >> index 620b51aab291..5b81ba2a7f27 100644
> >> --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> >> +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> >> @@ -92,13 +92,15 @@ static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
> >>  }
> >>
> >>  static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> >> -                                         struct drm_connector_state *state)
> >> +                                         struct drm_atomic_state *state)
> >>  {
> >>       struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
> >>       const struct drm_display_mode *panel_mode;
> >> +     struct drm_connector_state *conn_state;
> >>       struct drm_crtc_state *crtc_state;
> >>
> >> -     if (!state->crtc)
> >> +     conn_state = drm_atomic_get_new_connector_state(state, connector);
> >> +     if (!conn_state->crtc)
> >>               return 0;
> >>
> >>       if (list_empty(&connector->modes)) {
> >> @@ -110,9 +112,9 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> >>                                     struct drm_display_mode, head);
> >>
> >>       /* We're not allowed to modify the resolution. */
> >> -     crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
> >> -     if (IS_ERR(crtc_state))
> >> -             return PTR_ERR(crtc_state);
> >> +     crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
> >> +     if (!crtc_state)
> >> +             return -EINVAL;
> >>
> >>       if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
> >>           crtc_state->mode.vdisplay != panel_mode->vdisplay)
> >> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> >> index c8b89a78f9f4..96f91c1b4b6e 100644
> >> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> >> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> >> @@ -221,17 +221,18 @@ static const u32 txp_fmts[] = {
> >>  };
> >>
> >>  static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
> >> -                                     struct drm_connector_state *conn_state)
> >> +                                       struct drm_atomic_state *state)
> >>  {
> >> +     struct drm_connector_state *conn_state;
> >>       struct drm_crtc_state *crtc_state;
> >>       struct drm_framebuffer *fb;
> >>       int i;
> >>
> >> +     conn_state = drm_atomic_get_new_connector_state(state, conn);
> >>       if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
> >>               return 0;
> >>
> >> -     crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
> >> -                                                conn_state->crtc);
> >> +     crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> >>
> >>       fb = conn_state->writeback_job->fb;
> >>       if (fb->width != crtc_state->mode.hdisplay ||
> >> diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> >> index de57fb40cb6e..adc8b7cf64b5 100644
> >> --- a/include/drm/drm_modeset_helper_vtables.h
> >> +++ b/include/drm/drm_modeset_helper_vtables.h
> >> @@ -1020,7 +1020,7 @@ struct drm_connector_helper_funcs {
> >>        * deadlock.
> >>        */
> >>       int (*atomic_check)(struct drm_connector *connector,
> >> -                         struct drm_connector_state *state);
> >> +                         struct drm_atomic_state *state);
> >>
> >>       /**
> >>        * @atomic_commit:

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state
  2019-05-13 14:47     ` Daniel Vetter
@ 2019-05-16 12:02       ` Laurent Pinchart
  2019-05-16 12:07         ` Daniel Vetter
  0 siblings, 1 reply; 29+ messages in thread
From: Laurent Pinchart @ 2019-05-16 12:02 UTC (permalink / raw)
  To: Sean Paul, dri-devel, Sean Paul, Ville Syrjälä,
	Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs,
	Kieran Bingham, Eric Anholt, Maarten Lankhorst, Maxime Ripard,
	David Airlie, linux-kernel, intel-gfx, nouveau,
	linux-renesas-soc

Hi Daniel,

On Mon, May 13, 2019 at 04:47:47PM +0200, Daniel Vetter wrote:
> On Sat, May 11, 2019 at 10:12:02PM +0300, Laurent Pinchart wrote:
> > On Thu, May 02, 2019 at 03:49:46PM -0400, Sean Paul wrote:
> >> From: Sean Paul <seanpaul@chromium.org>
> >> 
> >> Everyone who implements connector_helper_funcs->atomic_check reaches
> >> into the connector state to get the atomic state. Instead of continuing
> >> this pattern, change the callback signature to just give atomic state
> >> and let the driver determine what it does and does not need from it.
> >> 
> >> Eventually all atomic functions should do this, but that's just too much
> >> busy work for me.
> > 
> > Given that drivers also access the connector state, isn't this slightly
> > more inefficient ?
> 
> It's atomic code, we're trying to optimize for clean code at the expense
> of a bit of runtime overhead due to more pointer chasing. And I agree with
> the general push, the pile of old/new_state pointers of various objects
> we're passing around is confusing. Passing the overall drm_atomic_state
> seems much more reasonable, and with that we can get everything else. Plus
> it's much more obvious whether you have the old/new state (since that's
> explicit when you look it up from the drm_atomic_state).

Yes, I agree it's cleaner. I just hope the atomic state tracking cost
can be kept under control :-)

By the way, this is likely not going to happen as it would be way too
intrusive, but it would be nice to rename drm_atomic_state to
drm_atomic_transaction (or something similar). It doesn't model a state,
but a change between an old state to a new state. This confused me in
the past, and I'm sure it can still be confusing to newcomers.

> If we ever see this show up in profile, and it starts mattering, first
> thing we need is a hashtable I think (atm it's list walking, which is just
> terrible). But thus far no one cares.
> 
> >> Changes in v3:
> >> - Added to the set
> >> 
> >> Cc: Daniel Vetter <daniel@ffwll.ch>
> >> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> >> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> >> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> >> Cc: Ben Skeggs <bskeggs@redhat.com>
> >> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >> Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> >> Cc: Eric Anholt <eric@anholt.net>
> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> >> ---
> >>  drivers/gpu/drm/drm_atomic_helper.c      |  4 ++--
> >>  drivers/gpu/drm/i915/intel_atomic.c      |  8 +++++---
> >>  drivers/gpu/drm/i915/intel_dp_mst.c      |  7 ++++---
> >>  drivers/gpu/drm/i915/intel_drv.h         |  2 +-
> >>  drivers/gpu/drm/i915/intel_sdvo.c        |  9 +++++----
> >>  drivers/gpu/drm/i915/intel_tv.c          |  8 +++++---
> >>  drivers/gpu/drm/nouveau/dispnv50/disp.c  |  5 +++--
> >>  drivers/gpu/drm/rcar-du/rcar_lvds.c      | 12 +++++++-----
> >>  drivers/gpu/drm/vc4/vc4_txp.c            |  7 ++++---
> >>  include/drm/drm_modeset_helper_vtables.h |  2 +-
> >>  10 files changed, 37 insertions(+), 27 deletions(-)
> >> 
> >> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> >> index 9d9e47276839..fa5a367507c1 100644
> >> --- a/drivers/gpu/drm/drm_atomic_helper.c
> >> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> >> @@ -683,7 +683,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> >>  		}
> >>  
> >>  		if (funcs->atomic_check)
> >> -			ret = funcs->atomic_check(connector, new_connector_state);
> >> +			ret = funcs->atomic_check(connector, state);
> >>  		if (ret)
> >>  			return ret;
> >>  
> >> @@ -725,7 +725,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> >>  			continue;
> >>  
> >>  		if (funcs->atomic_check)
> >> -			ret = funcs->atomic_check(connector, new_connector_state);
> >> +			ret = funcs->atomic_check(connector, state);
> >>  		if (ret)
> >>  			return ret;
> >>  	}
> >> diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> >> index b844e8840c6f..e8a5b82e9242 100644
> >> --- a/drivers/gpu/drm/i915/intel_atomic.c
> >> +++ b/drivers/gpu/drm/i915/intel_atomic.c
> >> @@ -103,12 +103,14 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> >>  }
> >>  
> >>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> >> -					 struct drm_connector_state *new_state)
> >> +					 struct drm_atomic_state *state)
> >>  {
> >> +	struct drm_connector_state *new_state =
> >> +		drm_atomic_get_new_connector_state(state, conn);
> >>  	struct intel_digital_connector_state *new_conn_state =
> >>  		to_intel_digital_connector_state(new_state);
> >>  	struct drm_connector_state *old_state =
> >> -		drm_atomic_get_old_connector_state(new_state->state, conn);
> >> +		drm_atomic_get_old_connector_state(state, conn);
> >>  	struct intel_digital_connector_state *old_conn_state =
> >>  		to_intel_digital_connector_state(old_state);
> >>  	struct drm_crtc_state *crtc_state;
> >> @@ -118,7 +120,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
> >>  	if (!new_state->crtc)
> >>  		return 0;
> >>  
> >> -	crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> >> +	crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> >>  
> >>  	/*
> >>  	 * These properties are handled by fastset, and might not end
> >> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> >> index 19d81cef2ab6..89cfec128ba0 100644
> >> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> >> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> >> @@ -143,9 +143,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
> >>  
> >>  static int
> >>  intel_dp_mst_atomic_check(struct drm_connector *connector,
> >> -			  struct drm_connector_state *new_conn_state)
> >> +			  struct drm_atomic_state *state)
> >>  {
> >> -	struct drm_atomic_state *state = new_conn_state->state;
> >> +	struct drm_connector_state *new_conn_state =
> >> +		drm_atomic_get_new_connector_state(state, connector);
> >>  	struct drm_connector_state *old_conn_state =
> >>  		drm_atomic_get_old_connector_state(state, connector);
> >>  	struct intel_connector *intel_connector =
> >> @@ -155,7 +156,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
> >>  	struct drm_dp_mst_topology_mgr *mgr;
> >>  	int ret;
> >>  
> >> -	ret = intel_digital_connector_atomic_check(connector, new_conn_state);
> >> +	ret = intel_digital_connector_atomic_check(connector, state);
> >>  	if (ret)
> >>  		return ret;
> >>  
> >> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> >> index f8c7b291fdc3..88571b8e8d62 100644
> >> --- a/drivers/gpu/drm/i915/intel_drv.h
> >> +++ b/drivers/gpu/drm/i915/intel_drv.h
> >> @@ -2481,7 +2481,7 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> >>  						struct drm_property *property,
> >>  						u64 val);
> >>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> >> -					 struct drm_connector_state *new_state);
> >> +					 struct drm_atomic_state *state);
> >>  struct drm_connector_state *
> >>  intel_digital_connector_duplicate_state(struct drm_connector *connector);
> >>  
> >> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> >> index 68f497493d43..72ea164b971c 100644
> >> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> >> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> >> @@ -2342,9 +2342,10 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
> >>  };
> >>  
> >>  static int intel_sdvo_atomic_check(struct drm_connector *conn,
> >> -				   struct drm_connector_state *new_conn_state)
> >> +				   struct drm_atomic_state *state)
> >>  {
> >> -	struct drm_atomic_state *state = new_conn_state->state;
> >> +	struct drm_connector_state *new_conn_state =
> >> +		drm_atomic_get_new_connector_state(state, conn);
> >>  	struct drm_connector_state *old_conn_state =
> >>  		drm_atomic_get_old_connector_state(state, conn);
> >>  	struct intel_sdvo_connector_state *old_state =
> >> @@ -2356,13 +2357,13 @@ static int intel_sdvo_atomic_check(struct drm_connector *conn,
> >>  	    (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
> >>  	     memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
> >>  		struct drm_crtc_state *crtc_state =
> >> -			drm_atomic_get_new_crtc_state(new_conn_state->state,
> >> +			drm_atomic_get_new_crtc_state(state,
> >>  						      new_conn_state->crtc);
> >>  
> >>  		crtc_state->connectors_changed = true;
> >>  	}
> >>  
> >> -	return intel_digital_connector_atomic_check(conn, new_conn_state);
> >> +	return intel_digital_connector_atomic_check(conn, state);
> >>  }
> >>  
> >>  static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
> >> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> >> index 3924c4944e1f..a41c5b467c14 100644
> >> --- a/drivers/gpu/drm/i915/intel_tv.c
> >> +++ b/drivers/gpu/drm/i915/intel_tv.c
> >> @@ -1817,16 +1817,18 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
> >>  };
> >>  
> >>  static int intel_tv_atomic_check(struct drm_connector *connector,
> >> -				 struct drm_connector_state *new_state)
> >> +				 struct drm_atomic_state *state)
> >>  {
> >> +	struct drm_connector_state *new_state;
> >>  	struct drm_crtc_state *new_crtc_state;
> >>  	struct drm_connector_state *old_state;
> >>  
> >> +	new_state = drm_atomic_get_new_connector_state(state, connector);
> >>  	if (!new_state->crtc)
> >>  		return 0;
> >>  
> >> -	old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
> >> -	new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> >> +	old_state = drm_atomic_get_old_connector_state(state, connector);
> >> +	new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> >>  
> >>  	if (old_state->tv.mode != new_state->tv.mode ||
> >>  	    old_state->tv.margins.left != new_state->tv.margins.left ||
> >> diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> >> index 4b1650f51955..7ba373f493b2 100644
> >> --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> >> +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> >> @@ -948,11 +948,12 @@ nv50_mstc_get_modes(struct drm_connector *connector)
> >>  
> >>  static int
> >>  nv50_mstc_atomic_check(struct drm_connector *connector,
> >> -		       struct drm_connector_state *new_conn_state)
> >> +		       struct drm_atomic_state *state)
> >>  {
> >> -	struct drm_atomic_state *state = new_conn_state->state;
> >>  	struct nv50_mstc *mstc = nv50_mstc(connector);
> >>  	struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr;
> >> +	struct drm_connector_state *new_conn_state =
> >> +		drm_atomic_get_new_connector_state(state, connector);
> >>  	struct drm_connector_state *old_conn_state =
> >>  		drm_atomic_get_old_connector_state(state, connector);
> >>  	struct drm_crtc_state *crtc_state;
> >> diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> >> index 620b51aab291..5b81ba2a7f27 100644
> >> --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> >> +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> >> @@ -92,13 +92,15 @@ static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
> >>  }
> >>  
> >>  static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> >> -					    struct drm_connector_state *state)
> >> +					    struct drm_atomic_state *state)
> >>  {
> >>  	struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
> >>  	const struct drm_display_mode *panel_mode;
> >> +	struct drm_connector_state *conn_state;
> >>  	struct drm_crtc_state *crtc_state;
> >>  
> >> -	if (!state->crtc)
> >> +	conn_state = drm_atomic_get_new_connector_state(state, connector);
> >> +	if (!conn_state->crtc)
> >>  		return 0;
> >>  
> >>  	if (list_empty(&connector->modes)) {
> >> @@ -110,9 +112,9 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> >>  				      struct drm_display_mode, head);
> >>  
> >>  	/* We're not allowed to modify the resolution. */
> >> -	crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
> >> -	if (IS_ERR(crtc_state))
> >> -		return PTR_ERR(crtc_state);
> >> +	crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
> >> +	if (!crtc_state)
> >> +		return -EINVAL;
> >>  
> >>  	if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
> >>  	    crtc_state->mode.vdisplay != panel_mode->vdisplay)
> >> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> >> index c8b89a78f9f4..96f91c1b4b6e 100644
> >> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> >> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> >> @@ -221,17 +221,18 @@ static const u32 txp_fmts[] = {
> >>  };
> >>  
> >>  static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
> >> -					struct drm_connector_state *conn_state)
> >> +					  struct drm_atomic_state *state)
> >>  {
> >> +	struct drm_connector_state *conn_state;
> >>  	struct drm_crtc_state *crtc_state;
> >>  	struct drm_framebuffer *fb;
> >>  	int i;
> >>  
> >> +	conn_state = drm_atomic_get_new_connector_state(state, conn);
> >>  	if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
> >>  		return 0;
> >>  
> >> -	crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
> >> -						   conn_state->crtc);
> >> +	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> >>  
> >>  	fb = conn_state->writeback_job->fb;
> >>  	if (fb->width != crtc_state->mode.hdisplay ||
> >> diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> >> index de57fb40cb6e..adc8b7cf64b5 100644
> >> --- a/include/drm/drm_modeset_helper_vtables.h
> >> +++ b/include/drm/drm_modeset_helper_vtables.h
> >> @@ -1020,7 +1020,7 @@ struct drm_connector_helper_funcs {
> >>  	 * deadlock.
> >>  	 */
> >>  	int (*atomic_check)(struct drm_connector *connector,
> >> -			    struct drm_connector_state *state);
> >> +			    struct drm_atomic_state *state);
> >>  
> >>  	/**
> >>  	 * @atomic_commit:

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state
  2019-05-16 12:02       ` Laurent Pinchart
@ 2019-05-16 12:07         ` Daniel Vetter
  2019-05-16 13:28           ` Ville Syrjälä
  0 siblings, 1 reply; 29+ messages in thread
From: Daniel Vetter @ 2019-05-16 12:07 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Sean Paul, dri-devel, Sean Paul, Ville Syrjälä,
	Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs,
	Kieran Bingham, Eric Anholt, Maarten Lankhorst, Maxime Ripard,
	David Airlie, Linux Kernel Mailing List, intel-gfx, Nouveau Dev,
	open list:DRM DRIVERS FOR RENESAS

On Thu, May 16, 2019 at 2:02 PM Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>
> Hi Daniel,
>
> On Mon, May 13, 2019 at 04:47:47PM +0200, Daniel Vetter wrote:
> > On Sat, May 11, 2019 at 10:12:02PM +0300, Laurent Pinchart wrote:
> > > On Thu, May 02, 2019 at 03:49:46PM -0400, Sean Paul wrote:
> > >> From: Sean Paul <seanpaul@chromium.org>
> > >>
> > >> Everyone who implements connector_helper_funcs->atomic_check reaches
> > >> into the connector state to get the atomic state. Instead of continuing
> > >> this pattern, change the callback signature to just give atomic state
> > >> and let the driver determine what it does and does not need from it.
> > >>
> > >> Eventually all atomic functions should do this, but that's just too much
> > >> busy work for me.
> > >
> > > Given that drivers also access the connector state, isn't this slightly
> > > more inefficient ?
> >
> > It's atomic code, we're trying to optimize for clean code at the expense
> > of a bit of runtime overhead due to more pointer chasing. And I agree with
> > the general push, the pile of old/new_state pointers of various objects
> > we're passing around is confusing. Passing the overall drm_atomic_state
> > seems much more reasonable, and with that we can get everything else. Plus
> > it's much more obvious whether you have the old/new state (since that's
> > explicit when you look it up from the drm_atomic_state).
>
> Yes, I agree it's cleaner. I just hope the atomic state tracking cost
> can be kept under control :-)
>
> By the way, this is likely not going to happen as it would be way too
> intrusive, but it would be nice to rename drm_atomic_state to
> drm_atomic_transaction (or something similar). It doesn't model a state,
> but a change between an old state to a new state. This confused me in
> the past, and I'm sure it can still be confusing to newcomers.

Why are you the first to suggest this, this is awesome!
drm_atomic_state is indeed not a state, but a transaction representing
how we go from the old to the new state.

I think this is awesome enough that we should actually try to make it
happen. Tree-wide cocci + bribing Dave on St. Patrick's day with lots
of beer might be enough :-)
-Daniel

> > If we ever see this show up in profile, and it starts mattering, first
> > thing we need is a hashtable I think (atm it's list walking, which is just
> > terrible). But thus far no one cares.
> >
> > >> Changes in v3:
> > >> - Added to the set
> > >>
> > >> Cc: Daniel Vetter <daniel@ffwll.ch>
> > >> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > >> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> > >> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> > >> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > >> Cc: Ben Skeggs <bskeggs@redhat.com>
> > >> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >> Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> > >> Cc: Eric Anholt <eric@anholt.net>
> > >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > >> ---
> > >>  drivers/gpu/drm/drm_atomic_helper.c      |  4 ++--
> > >>  drivers/gpu/drm/i915/intel_atomic.c      |  8 +++++---
> > >>  drivers/gpu/drm/i915/intel_dp_mst.c      |  7 ++++---
> > >>  drivers/gpu/drm/i915/intel_drv.h         |  2 +-
> > >>  drivers/gpu/drm/i915/intel_sdvo.c        |  9 +++++----
> > >>  drivers/gpu/drm/i915/intel_tv.c          |  8 +++++---
> > >>  drivers/gpu/drm/nouveau/dispnv50/disp.c  |  5 +++--
> > >>  drivers/gpu/drm/rcar-du/rcar_lvds.c      | 12 +++++++-----
> > >>  drivers/gpu/drm/vc4/vc4_txp.c            |  7 ++++---
> > >>  include/drm/drm_modeset_helper_vtables.h |  2 +-
> > >>  10 files changed, 37 insertions(+), 27 deletions(-)
> > >>
> > >> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > >> index 9d9e47276839..fa5a367507c1 100644
> > >> --- a/drivers/gpu/drm/drm_atomic_helper.c
> > >> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > >> @@ -683,7 +683,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > >>            }
> > >>
> > >>            if (funcs->atomic_check)
> > >> -                  ret = funcs->atomic_check(connector, new_connector_state);
> > >> +                  ret = funcs->atomic_check(connector, state);
> > >>            if (ret)
> > >>                    return ret;
> > >>
> > >> @@ -725,7 +725,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > >>                    continue;
> > >>
> > >>            if (funcs->atomic_check)
> > >> -                  ret = funcs->atomic_check(connector, new_connector_state);
> > >> +                  ret = funcs->atomic_check(connector, state);
> > >>            if (ret)
> > >>                    return ret;
> > >>    }
> > >> diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> > >> index b844e8840c6f..e8a5b82e9242 100644
> > >> --- a/drivers/gpu/drm/i915/intel_atomic.c
> > >> +++ b/drivers/gpu/drm/i915/intel_atomic.c
> > >> @@ -103,12 +103,14 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> > >>  }
> > >>
> > >>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> > >> -                                   struct drm_connector_state *new_state)
> > >> +                                   struct drm_atomic_state *state)
> > >>  {
> > >> +  struct drm_connector_state *new_state =
> > >> +          drm_atomic_get_new_connector_state(state, conn);
> > >>    struct intel_digital_connector_state *new_conn_state =
> > >>            to_intel_digital_connector_state(new_state);
> > >>    struct drm_connector_state *old_state =
> > >> -          drm_atomic_get_old_connector_state(new_state->state, conn);
> > >> +          drm_atomic_get_old_connector_state(state, conn);
> > >>    struct intel_digital_connector_state *old_conn_state =
> > >>            to_intel_digital_connector_state(old_state);
> > >>    struct drm_crtc_state *crtc_state;
> > >> @@ -118,7 +120,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
> > >>    if (!new_state->crtc)
> > >>            return 0;
> > >>
> > >> -  crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> > >> +  crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> > >>
> > >>    /*
> > >>     * These properties are handled by fastset, and might not end
> > >> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> > >> index 19d81cef2ab6..89cfec128ba0 100644
> > >> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> > >> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> > >> @@ -143,9 +143,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
> > >>
> > >>  static int
> > >>  intel_dp_mst_atomic_check(struct drm_connector *connector,
> > >> -                    struct drm_connector_state *new_conn_state)
> > >> +                    struct drm_atomic_state *state)
> > >>  {
> > >> -  struct drm_atomic_state *state = new_conn_state->state;
> > >> +  struct drm_connector_state *new_conn_state =
> > >> +          drm_atomic_get_new_connector_state(state, connector);
> > >>    struct drm_connector_state *old_conn_state =
> > >>            drm_atomic_get_old_connector_state(state, connector);
> > >>    struct intel_connector *intel_connector =
> > >> @@ -155,7 +156,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
> > >>    struct drm_dp_mst_topology_mgr *mgr;
> > >>    int ret;
> > >>
> > >> -  ret = intel_digital_connector_atomic_check(connector, new_conn_state);
> > >> +  ret = intel_digital_connector_atomic_check(connector, state);
> > >>    if (ret)
> > >>            return ret;
> > >>
> > >> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > >> index f8c7b291fdc3..88571b8e8d62 100644
> > >> --- a/drivers/gpu/drm/i915/intel_drv.h
> > >> +++ b/drivers/gpu/drm/i915/intel_drv.h
> > >> @@ -2481,7 +2481,7 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> > >>                                            struct drm_property *property,
> > >>                                            u64 val);
> > >>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> > >> -                                   struct drm_connector_state *new_state);
> > >> +                                   struct drm_atomic_state *state);
> > >>  struct drm_connector_state *
> > >>  intel_digital_connector_duplicate_state(struct drm_connector *connector);
> > >>
> > >> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> > >> index 68f497493d43..72ea164b971c 100644
> > >> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> > >> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> > >> @@ -2342,9 +2342,10 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
> > >>  };
> > >>
> > >>  static int intel_sdvo_atomic_check(struct drm_connector *conn,
> > >> -                             struct drm_connector_state *new_conn_state)
> > >> +                             struct drm_atomic_state *state)
> > >>  {
> > >> -  struct drm_atomic_state *state = new_conn_state->state;
> > >> +  struct drm_connector_state *new_conn_state =
> > >> +          drm_atomic_get_new_connector_state(state, conn);
> > >>    struct drm_connector_state *old_conn_state =
> > >>            drm_atomic_get_old_connector_state(state, conn);
> > >>    struct intel_sdvo_connector_state *old_state =
> > >> @@ -2356,13 +2357,13 @@ static int intel_sdvo_atomic_check(struct drm_connector *conn,
> > >>        (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
> > >>         memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
> > >>            struct drm_crtc_state *crtc_state =
> > >> -                  drm_atomic_get_new_crtc_state(new_conn_state->state,
> > >> +                  drm_atomic_get_new_crtc_state(state,
> > >>                                                  new_conn_state->crtc);
> > >>
> > >>            crtc_state->connectors_changed = true;
> > >>    }
> > >>
> > >> -  return intel_digital_connector_atomic_check(conn, new_conn_state);
> > >> +  return intel_digital_connector_atomic_check(conn, state);
> > >>  }
> > >>
> > >>  static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
> > >> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> > >> index 3924c4944e1f..a41c5b467c14 100644
> > >> --- a/drivers/gpu/drm/i915/intel_tv.c
> > >> +++ b/drivers/gpu/drm/i915/intel_tv.c
> > >> @@ -1817,16 +1817,18 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
> > >>  };
> > >>
> > >>  static int intel_tv_atomic_check(struct drm_connector *connector,
> > >> -                           struct drm_connector_state *new_state)
> > >> +                           struct drm_atomic_state *state)
> > >>  {
> > >> +  struct drm_connector_state *new_state;
> > >>    struct drm_crtc_state *new_crtc_state;
> > >>    struct drm_connector_state *old_state;
> > >>
> > >> +  new_state = drm_atomic_get_new_connector_state(state, connector);
> > >>    if (!new_state->crtc)
> > >>            return 0;
> > >>
> > >> -  old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
> > >> -  new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> > >> +  old_state = drm_atomic_get_old_connector_state(state, connector);
> > >> +  new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> > >>
> > >>    if (old_state->tv.mode != new_state->tv.mode ||
> > >>        old_state->tv.margins.left != new_state->tv.margins.left ||
> > >> diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > >> index 4b1650f51955..7ba373f493b2 100644
> > >> --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > >> +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > >> @@ -948,11 +948,12 @@ nv50_mstc_get_modes(struct drm_connector *connector)
> > >>
> > >>  static int
> > >>  nv50_mstc_atomic_check(struct drm_connector *connector,
> > >> -                 struct drm_connector_state *new_conn_state)
> > >> +                 struct drm_atomic_state *state)
> > >>  {
> > >> -  struct drm_atomic_state *state = new_conn_state->state;
> > >>    struct nv50_mstc *mstc = nv50_mstc(connector);
> > >>    struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr;
> > >> +  struct drm_connector_state *new_conn_state =
> > >> +          drm_atomic_get_new_connector_state(state, connector);
> > >>    struct drm_connector_state *old_conn_state =
> > >>            drm_atomic_get_old_connector_state(state, connector);
> > >>    struct drm_crtc_state *crtc_state;
> > >> diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > >> index 620b51aab291..5b81ba2a7f27 100644
> > >> --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > >> +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > >> @@ -92,13 +92,15 @@ static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
> > >>  }
> > >>
> > >>  static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> > >> -                                      struct drm_connector_state *state)
> > >> +                                      struct drm_atomic_state *state)
> > >>  {
> > >>    struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
> > >>    const struct drm_display_mode *panel_mode;
> > >> +  struct drm_connector_state *conn_state;
> > >>    struct drm_crtc_state *crtc_state;
> > >>
> > >> -  if (!state->crtc)
> > >> +  conn_state = drm_atomic_get_new_connector_state(state, connector);
> > >> +  if (!conn_state->crtc)
> > >>            return 0;
> > >>
> > >>    if (list_empty(&connector->modes)) {
> > >> @@ -110,9 +112,9 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> > >>                                  struct drm_display_mode, head);
> > >>
> > >>    /* We're not allowed to modify the resolution. */
> > >> -  crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
> > >> -  if (IS_ERR(crtc_state))
> > >> -          return PTR_ERR(crtc_state);
> > >> +  crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
> > >> +  if (!crtc_state)
> > >> +          return -EINVAL;
> > >>
> > >>    if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
> > >>        crtc_state->mode.vdisplay != panel_mode->vdisplay)
> > >> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> > >> index c8b89a78f9f4..96f91c1b4b6e 100644
> > >> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> > >> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> > >> @@ -221,17 +221,18 @@ static const u32 txp_fmts[] = {
> > >>  };
> > >>
> > >>  static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
> > >> -                                  struct drm_connector_state *conn_state)
> > >> +                                    struct drm_atomic_state *state)
> > >>  {
> > >> +  struct drm_connector_state *conn_state;
> > >>    struct drm_crtc_state *crtc_state;
> > >>    struct drm_framebuffer *fb;
> > >>    int i;
> > >>
> > >> +  conn_state = drm_atomic_get_new_connector_state(state, conn);
> > >>    if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
> > >>            return 0;
> > >>
> > >> -  crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
> > >> -                                             conn_state->crtc);
> > >> +  crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> > >>
> > >>    fb = conn_state->writeback_job->fb;
> > >>    if (fb->width != crtc_state->mode.hdisplay ||
> > >> diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> > >> index de57fb40cb6e..adc8b7cf64b5 100644
> > >> --- a/include/drm/drm_modeset_helper_vtables.h
> > >> +++ b/include/drm/drm_modeset_helper_vtables.h
> > >> @@ -1020,7 +1020,7 @@ struct drm_connector_helper_funcs {
> > >>     * deadlock.
> > >>     */
> > >>    int (*atomic_check)(struct drm_connector *connector,
> > >> -                      struct drm_connector_state *state);
> > >> +                      struct drm_atomic_state *state);
> > >>
> > >>    /**
> > >>     * @atomic_commit:
>
> --
> Regards,
>
> Laurent Pinchart
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel



-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state
  2019-05-16 12:07         ` Daniel Vetter
@ 2019-05-16 13:28           ` Ville Syrjälä
  0 siblings, 0 replies; 29+ messages in thread
From: Ville Syrjälä @ 2019-05-16 13:28 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: Laurent Pinchart, Sean Paul, dri-devel, Sean Paul, Jani Nikula,
	Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs, Kieran Bingham,
	Eric Anholt, Maarten Lankhorst, Maxime Ripard, David Airlie,
	Linux Kernel Mailing List, intel-gfx, Nouveau Dev,
	open list:DRM DRIVERS FOR RENESAS

On Thu, May 16, 2019 at 02:07:34PM +0200, Daniel Vetter wrote:
> On Thu, May 16, 2019 at 2:02 PM Laurent Pinchart
> <laurent.pinchart@ideasonboard.com> wrote:
> >
> > Hi Daniel,
> >
> > On Mon, May 13, 2019 at 04:47:47PM +0200, Daniel Vetter wrote:
> > > On Sat, May 11, 2019 at 10:12:02PM +0300, Laurent Pinchart wrote:
> > > > On Thu, May 02, 2019 at 03:49:46PM -0400, Sean Paul wrote:
> > > >> From: Sean Paul <seanpaul@chromium.org>
> > > >>
> > > >> Everyone who implements connector_helper_funcs->atomic_check reaches
> > > >> into the connector state to get the atomic state. Instead of continuing
> > > >> this pattern, change the callback signature to just give atomic state
> > > >> and let the driver determine what it does and does not need from it.
> > > >>
> > > >> Eventually all atomic functions should do this, but that's just too much
> > > >> busy work for me.
> > > >
> > > > Given that drivers also access the connector state, isn't this slightly
> > > > more inefficient ?
> > >
> > > It's atomic code, we're trying to optimize for clean code at the expense
> > > of a bit of runtime overhead due to more pointer chasing. And I agree with
> > > the general push, the pile of old/new_state pointers of various objects
> > > we're passing around is confusing. Passing the overall drm_atomic_state
> > > seems much more reasonable, and with that we can get everything else. Plus
> > > it's much more obvious whether you have the old/new state (since that's
> > > explicit when you look it up from the drm_atomic_state).
> >
> > Yes, I agree it's cleaner. I just hope the atomic state tracking cost
> > can be kept under control :-)
> >
> > By the way, this is likely not going to happen as it would be way too
> > intrusive, but it would be nice to rename drm_atomic_state to
> > drm_atomic_transaction (or something similar). It doesn't model a state,
> > but a change between an old state to a new state. This confused me in
> > the past, and I'm sure it can still be confusing to newcomers.
> 
> Why are you the first to suggest this, this is awesome!

Can't quite tell if that's irony or not. Anyways, this has been
suggested before but no volunteers stepped forward.

> drm_atomic_state is indeed not a state, but a transaction representing
> how we go from the old to the new state.

On a semi-related topic, I've occasionally pondered about moving
mode_changed & co. from the obj states to the top level
state/transaction (maybe stored as a bitmask). But that would
definitely not be a trivial sed job.

-- 
Ville Syrjälä
Intel

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state
  2019-05-16 12:00       ` Laurent Pinchart
@ 2019-05-16 14:21         ` Sean Paul
  0 siblings, 0 replies; 29+ messages in thread
From: Sean Paul @ 2019-05-16 14:21 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Sean Paul, dri-devel, Sean Paul, Daniel Vetter,
	Ville Syrjälä,
	Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Ben Skeggs,
	Kieran Bingham, Eric Anholt, Maarten Lankhorst, Maxime Ripard,
	David Airlie, LKML, Intel Graphics Development, nouveau,
	linux-renesas-soc

On Thu, May 16, 2019 at 03:00:01PM +0300, Laurent Pinchart wrote:
> Hi Sean,
> 
> On Mon, May 13, 2019 at 10:38:58AM -0400, Sean Paul wrote:
> > On Sat, May 11, 2019 at 3:12 PM Laurent Pinchart wrote:
> > > On Thu, May 02, 2019 at 03:49:46PM -0400, Sean Paul wrote:
> > >> From: Sean Paul <seanpaul@chromium.org>
> > >>
> > >> Everyone who implements connector_helper_funcs->atomic_check reaches
> > >> into the connector state to get the atomic state. Instead of continuing
> > >> this pattern, change the callback signature to just give atomic state
> > >> and let the driver determine what it does and does not need from it.
> > >>
> > >> Eventually all atomic functions should do this, but that's just too much
> > >> busy work for me.
> > >
> > > Given that drivers also access the connector state, isn't this slightly
> > > more inefficient ?
> > 
> > Inefficient in terms of what?
> 
> In terms of the operation having to lookup the connector state, when the
> caller has it and can easily pass it. As Daniel commented, this may be
> the price to pay for a cleaner API, but I wonder how much overhead all
> the state tracking is costing.
> 

It'd be interesting to quantify, but iirc the last time we benchmarked
atomic check commits they were virtually free (~thousands/s).

> > Agree that in isolation this patch might seem unnecessary, but it ties
> > in with the encoder and bridge CLs which accept drm_atomic_state in
> 
> CLs ?

Googleism for patches, I usually catch these before sending... guess I missed
one.

Sean

> 
> > their hooks. In general the idea is to convert all atomic functions to
> > take overall atomic state instead of just their object state. Reality
> > has proven to be more complicated and we need more access than what
> > the current implementation provides.
> > 
> > Sean
> > 
> > >> Changes in v3:
> > >> - Added to the set
> > >>
> > >> Cc: Daniel Vetter <daniel@ffwll.ch>
> > >> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > >> Cc: Jani Nikula <jani.nikula@linux.intel.com>
> > >> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> > >> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> > >> Cc: Ben Skeggs <bskeggs@redhat.com>
> > >> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >> Cc: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
> > >> Cc: Eric Anholt <eric@anholt.net>
> > >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > >> ---
> > >>  drivers/gpu/drm/drm_atomic_helper.c      |  4 ++--
> > >>  drivers/gpu/drm/i915/intel_atomic.c      |  8 +++++---
> > >>  drivers/gpu/drm/i915/intel_dp_mst.c      |  7 ++++---
> > >>  drivers/gpu/drm/i915/intel_drv.h         |  2 +-
> > >>  drivers/gpu/drm/i915/intel_sdvo.c        |  9 +++++----
> > >>  drivers/gpu/drm/i915/intel_tv.c          |  8 +++++---
> > >>  drivers/gpu/drm/nouveau/dispnv50/disp.c  |  5 +++--
> > >>  drivers/gpu/drm/rcar-du/rcar_lvds.c      | 12 +++++++-----
> > >>  drivers/gpu/drm/vc4/vc4_txp.c            |  7 ++++---
> > >>  include/drm/drm_modeset_helper_vtables.h |  2 +-
> > >>  10 files changed, 37 insertions(+), 27 deletions(-)
> > >>
> > >> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > >> index 9d9e47276839..fa5a367507c1 100644
> > >> --- a/drivers/gpu/drm/drm_atomic_helper.c
> > >> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > >> @@ -683,7 +683,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > >>               }
> > >>
> > >>               if (funcs->atomic_check)
> > >> -                     ret = funcs->atomic_check(connector, new_connector_state);
> > >> +                     ret = funcs->atomic_check(connector, state);
> > >>               if (ret)
> > >>                       return ret;
> > >>
> > >> @@ -725,7 +725,7 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > >>                       continue;
> > >>
> > >>               if (funcs->atomic_check)
> > >> -                     ret = funcs->atomic_check(connector, new_connector_state);
> > >> +                     ret = funcs->atomic_check(connector, state);
> > >>               if (ret)
> > >>                       return ret;
> > >>       }
> > >> diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
> > >> index b844e8840c6f..e8a5b82e9242 100644
> > >> --- a/drivers/gpu/drm/i915/intel_atomic.c
> > >> +++ b/drivers/gpu/drm/i915/intel_atomic.c
> > >> @@ -103,12 +103,14 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> > >>  }
> > >>
> > >>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> > >> -                                      struct drm_connector_state *new_state)
> > >> +                                      struct drm_atomic_state *state)
> > >>  {
> > >> +     struct drm_connector_state *new_state =
> > >> +             drm_atomic_get_new_connector_state(state, conn);
> > >>       struct intel_digital_connector_state *new_conn_state =
> > >>               to_intel_digital_connector_state(new_state);
> > >>       struct drm_connector_state *old_state =
> > >> -             drm_atomic_get_old_connector_state(new_state->state, conn);
> > >> +             drm_atomic_get_old_connector_state(state, conn);
> > >>       struct intel_digital_connector_state *old_conn_state =
> > >>               to_intel_digital_connector_state(old_state);
> > >>       struct drm_crtc_state *crtc_state;
> > >> @@ -118,7 +120,7 @@ int intel_digital_connector_atomic_check(struct drm_connector *conn,
> > >>       if (!new_state->crtc)
> > >>               return 0;
> > >>
> > >> -     crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> > >> +     crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> > >>
> > >>       /*
> > >>        * These properties are handled by fastset, and might not end
> > >> diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
> > >> index 19d81cef2ab6..89cfec128ba0 100644
> > >> --- a/drivers/gpu/drm/i915/intel_dp_mst.c
> > >> +++ b/drivers/gpu/drm/i915/intel_dp_mst.c
> > >> @@ -143,9 +143,10 @@ static int intel_dp_mst_compute_config(struct intel_encoder *encoder,
> > >>
> > >>  static int
> > >>  intel_dp_mst_atomic_check(struct drm_connector *connector,
> > >> -                       struct drm_connector_state *new_conn_state)
> > >> +                       struct drm_atomic_state *state)
> > >>  {
> > >> -     struct drm_atomic_state *state = new_conn_state->state;
> > >> +     struct drm_connector_state *new_conn_state =
> > >> +             drm_atomic_get_new_connector_state(state, connector);
> > >>       struct drm_connector_state *old_conn_state =
> > >>               drm_atomic_get_old_connector_state(state, connector);
> > >>       struct intel_connector *intel_connector =
> > >> @@ -155,7 +156,7 @@ intel_dp_mst_atomic_check(struct drm_connector *connector,
> > >>       struct drm_dp_mst_topology_mgr *mgr;
> > >>       int ret;
> > >>
> > >> -     ret = intel_digital_connector_atomic_check(connector, new_conn_state);
> > >> +     ret = intel_digital_connector_atomic_check(connector, state);
> > >>       if (ret)
> > >>               return ret;
> > >>
> > >> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > >> index f8c7b291fdc3..88571b8e8d62 100644
> > >> --- a/drivers/gpu/drm/i915/intel_drv.h
> > >> +++ b/drivers/gpu/drm/i915/intel_drv.h
> > >> @@ -2481,7 +2481,7 @@ int intel_digital_connector_atomic_set_property(struct drm_connector *connector,
> > >>                                               struct drm_property *property,
> > >>                                               u64 val);
> > >>  int intel_digital_connector_atomic_check(struct drm_connector *conn,
> > >> -                                      struct drm_connector_state *new_state);
> > >> +                                      struct drm_atomic_state *state);
> > >>  struct drm_connector_state *
> > >>  intel_digital_connector_duplicate_state(struct drm_connector *connector);
> > >>
> > >> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
> > >> index 68f497493d43..72ea164b971c 100644
> > >> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> > >> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> > >> @@ -2342,9 +2342,10 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
> > >>  };
> > >>
> > >>  static int intel_sdvo_atomic_check(struct drm_connector *conn,
> > >> -                                struct drm_connector_state *new_conn_state)
> > >> +                                struct drm_atomic_state *state)
> > >>  {
> > >> -     struct drm_atomic_state *state = new_conn_state->state;
> > >> +     struct drm_connector_state *new_conn_state =
> > >> +             drm_atomic_get_new_connector_state(state, conn);
> > >>       struct drm_connector_state *old_conn_state =
> > >>               drm_atomic_get_old_connector_state(state, conn);
> > >>       struct intel_sdvo_connector_state *old_state =
> > >> @@ -2356,13 +2357,13 @@ static int intel_sdvo_atomic_check(struct drm_connector *conn,
> > >>           (memcmp(&old_state->tv, &new_state->tv, sizeof(old_state->tv)) ||
> > >>            memcmp(&old_conn_state->tv, &new_conn_state->tv, sizeof(old_conn_state->tv)))) {
> > >>               struct drm_crtc_state *crtc_state =
> > >> -                     drm_atomic_get_new_crtc_state(new_conn_state->state,
> > >> +                     drm_atomic_get_new_crtc_state(state,
> > >>                                                     new_conn_state->crtc);
> > >>
> > >>               crtc_state->connectors_changed = true;
> > >>       }
> > >>
> > >> -     return intel_digital_connector_atomic_check(conn, new_conn_state);
> > >> +     return intel_digital_connector_atomic_check(conn, state);
> > >>  }
> > >>
> > >>  static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
> > >> diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
> > >> index 3924c4944e1f..a41c5b467c14 100644
> > >> --- a/drivers/gpu/drm/i915/intel_tv.c
> > >> +++ b/drivers/gpu/drm/i915/intel_tv.c
> > >> @@ -1817,16 +1817,18 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
> > >>  };
> > >>
> > >>  static int intel_tv_atomic_check(struct drm_connector *connector,
> > >> -                              struct drm_connector_state *new_state)
> > >> +                              struct drm_atomic_state *state)
> > >>  {
> > >> +     struct drm_connector_state *new_state;
> > >>       struct drm_crtc_state *new_crtc_state;
> > >>       struct drm_connector_state *old_state;
> > >>
> > >> +     new_state = drm_atomic_get_new_connector_state(state, connector);
> > >>       if (!new_state->crtc)
> > >>               return 0;
> > >>
> > >> -     old_state = drm_atomic_get_old_connector_state(new_state->state, connector);
> > >> -     new_crtc_state = drm_atomic_get_new_crtc_state(new_state->state, new_state->crtc);
> > >> +     old_state = drm_atomic_get_old_connector_state(state, connector);
> > >> +     new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
> > >>
> > >>       if (old_state->tv.mode != new_state->tv.mode ||
> > >>           old_state->tv.margins.left != new_state->tv.margins.left ||
> > >> diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > >> index 4b1650f51955..7ba373f493b2 100644
> > >> --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > >> +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> > >> @@ -948,11 +948,12 @@ nv50_mstc_get_modes(struct drm_connector *connector)
> > >>
> > >>  static int
> > >>  nv50_mstc_atomic_check(struct drm_connector *connector,
> > >> -                    struct drm_connector_state *new_conn_state)
> > >> +                    struct drm_atomic_state *state)
> > >>  {
> > >> -     struct drm_atomic_state *state = new_conn_state->state;
> > >>       struct nv50_mstc *mstc = nv50_mstc(connector);
> > >>       struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr;
> > >> +     struct drm_connector_state *new_conn_state =
> > >> +             drm_atomic_get_new_connector_state(state, connector);
> > >>       struct drm_connector_state *old_conn_state =
> > >>               drm_atomic_get_old_connector_state(state, connector);
> > >>       struct drm_crtc_state *crtc_state;
> > >> diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > >> index 620b51aab291..5b81ba2a7f27 100644
> > >> --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > >> +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c
> > >> @@ -92,13 +92,15 @@ static int rcar_lvds_connector_get_modes(struct drm_connector *connector)
> > >>  }
> > >>
> > >>  static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> > >> -                                         struct drm_connector_state *state)
> > >> +                                         struct drm_atomic_state *state)
> > >>  {
> > >>       struct rcar_lvds *lvds = connector_to_rcar_lvds(connector);
> > >>       const struct drm_display_mode *panel_mode;
> > >> +     struct drm_connector_state *conn_state;
> > >>       struct drm_crtc_state *crtc_state;
> > >>
> > >> -     if (!state->crtc)
> > >> +     conn_state = drm_atomic_get_new_connector_state(state, connector);
> > >> +     if (!conn_state->crtc)
> > >>               return 0;
> > >>
> > >>       if (list_empty(&connector->modes)) {
> > >> @@ -110,9 +112,9 @@ static int rcar_lvds_connector_atomic_check(struct drm_connector *connector,
> > >>                                     struct drm_display_mode, head);
> > >>
> > >>       /* We're not allowed to modify the resolution. */
> > >> -     crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
> > >> -     if (IS_ERR(crtc_state))
> > >> -             return PTR_ERR(crtc_state);
> > >> +     crtc_state = drm_atomic_get_crtc_state(state, conn_state->crtc);
> > >> +     if (!crtc_state)
> > >> +             return -EINVAL;
> > >>
> > >>       if (crtc_state->mode.hdisplay != panel_mode->hdisplay ||
> > >>           crtc_state->mode.vdisplay != panel_mode->vdisplay)
> > >> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> > >> index c8b89a78f9f4..96f91c1b4b6e 100644
> > >> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> > >> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> > >> @@ -221,17 +221,18 @@ static const u32 txp_fmts[] = {
> > >>  };
> > >>
> > >>  static int vc4_txp_connector_atomic_check(struct drm_connector *conn,
> > >> -                                     struct drm_connector_state *conn_state)
> > >> +                                       struct drm_atomic_state *state)
> > >>  {
> > >> +     struct drm_connector_state *conn_state;
> > >>       struct drm_crtc_state *crtc_state;
> > >>       struct drm_framebuffer *fb;
> > >>       int i;
> > >>
> > >> +     conn_state = drm_atomic_get_new_connector_state(state, conn);
> > >>       if (!conn_state->writeback_job || !conn_state->writeback_job->fb)
> > >>               return 0;
> > >>
> > >> -     crtc_state = drm_atomic_get_new_crtc_state(conn_state->state,
> > >> -                                                conn_state->crtc);
> > >> +     crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> > >>
> > >>       fb = conn_state->writeback_job->fb;
> > >>       if (fb->width != crtc_state->mode.hdisplay ||
> > >> diff --git a/include/drm/drm_modeset_helper_vtables.h b/include/drm/drm_modeset_helper_vtables.h
> > >> index de57fb40cb6e..adc8b7cf64b5 100644
> > >> --- a/include/drm/drm_modeset_helper_vtables.h
> > >> +++ b/include/drm/drm_modeset_helper_vtables.h
> > >> @@ -1020,7 +1020,7 @@ struct drm_connector_helper_funcs {
> > >>        * deadlock.
> > >>        */
> > >>       int (*atomic_check)(struct drm_connector *connector,
> > >> -                         struct drm_connector_state *state);
> > >> +                         struct drm_atomic_state *state);
> > >>
> > >>       /**
> > >>        * @atomic_commit:
> 
> -- 
> Regards,
> 
> Laurent Pinchart

-- 
Sean Paul, Software Engineer, Google / Chromium OS

^ permalink raw reply	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2019-05-16 14:21 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20190502194956.218441-1-sean@poorly.run>
2019-05-02 19:49 ` [PATCH v3 01/10] drm: Add atomic variants of enable/disable to encoder helper funcs Sean Paul
2019-05-03  7:51   ` Daniel Vetter
2019-05-03 12:34     ` Sean Paul
2019-05-03 14:08       ` Daniel Vetter
2019-05-02 19:49 ` [PATCH v3 02/10] drm: Add drm_atomic_crtc_state_for_encoder helper Sean Paul
2019-05-03  8:18   ` Daniel Vetter
2019-05-03 12:47     ` Sean Paul
2019-05-03 14:06       ` Daniel Vetter
2019-05-05 21:15         ` Daniel Vetter
2019-05-05 22:01           ` Laurent Pinchart
2019-05-02 19:49 ` [PATCH v3 03/10] drm: Add atomic variants for bridge enable/disable Sean Paul
2019-05-03  7:45   ` Daniel Vetter
2019-05-02 19:49 ` [PATCH v3 04/10] drm: Convert connector_helper_funcs->atomic_check to accept drm_atomic_state Sean Paul
2019-05-03  8:19   ` Daniel Vetter
2019-05-11 19:12   ` Laurent Pinchart
2019-05-13 14:38     ` Sean Paul
2019-05-16 12:00       ` Laurent Pinchart
2019-05-16 14:21         ` Sean Paul
2019-05-13 14:47     ` Daniel Vetter
2019-05-16 12:02       ` Laurent Pinchart
2019-05-16 12:07         ` Daniel Vetter
2019-05-16 13:28           ` Ville Syrjälä
2019-05-02 19:49 ` [PATCH v3 05/10] drm: Add helpers to kick off self refresh mode in drivers Sean Paul
2019-05-03  7:36   ` Daniel Vetter
2019-05-02 19:49 ` [PATCH v3 06/10] drm/rockchip: Use dirtyfb helper Sean Paul
2019-05-02 19:49 ` [PATCH v3 07/10] drm/rockchip: Check for fast link training before enabling psr Sean Paul
2019-05-02 19:49 ` [PATCH v3 08/10] drm/rockchip: Use the helpers for PSR Sean Paul
2019-05-02 19:49 ` [PATCH v3 09/10] drm/rockchip: Don't fully disable vop on self refresh Sean Paul
2019-05-02 19:49 ` [PATCH v3 10/10] drm/rockchip: Use drm_atomic_helper_commit_tail_rpm Sean Paul

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).