aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Paul <seanpaul@chromium.org>2019-06-12 10:50:19 -0400
committerSean Paul <seanpaul@chromium.org>2019-06-13 14:31:10 -0400
commit1452c25b0e60278820f3d2155c65f1bfcce5ee79 (patch)
tree1f070c0600b87f5a608f4373d38b8aaa73d02d15
parent6f3b62781bbd2670756a4847113d410a827a2593 (diff)
drm: Add helpers to kick off self refresh mode in drivers
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) Changes in v4: - Move docbook location below panel (Daniel) - Improve docbook with references and more detailed explanation (Daniel) - Instead of register/unregister, use init/cleanup (Daniel) Changes in v5: - Resolved conflict in drm_atomic_helper.c #include block - Resolved conflict in rst with HDCP helper docs Changes in v6: - Fix include ordering, clean up forward declarations (Sam) 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 Link to v3: https://patchwork.freedesktop.org/patch/msgid/20190502194956.218441-6-sean@poorly.run Link to v4: https://patchwork.freedesktop.org/patch/msgid/20190508160920.144739-6-sean@poorly.run Link to v5: https://patchwork.freedesktop.org/patch/msgid/20190611160844.257498-6-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> Cc: Sam Ravnborg <sam@ravnborg.org> Tested-by: Heiko Stuebner <heiko@sntech.de> Reviewed-by: Daniel Vetter <daniel@ffwll.ch> Signed-off-by: Sean Paul <seanpaul@chromium.org> Link: https://patchwork.freedesktop.org/patch/msgid/20190612145026.191846-1-sean@poorly.run
-rw-r--r--Documentation/gpu/drm-kms-helpers.rst9
-rw-r--r--drivers/gpu/drm/Makefile2
-rw-r--r--drivers/gpu/drm/drm_atomic.c2
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c35
-rw-r--r--drivers/gpu/drm/drm_atomic_state_helper.c4
-rw-r--r--drivers/gpu/drm/drm_atomic_uapi.c7
-rw-r--r--drivers/gpu/drm/drm_self_refresh_helper.c216
-rw-r--r--include/drm/drm_atomic.h15
-rw-r--r--include/drm/drm_connector.h14
-rw-r--r--include/drm/drm_crtc.h19
-rw-r--r--include/drm/drm_self_refresh_helper.h20
11 files changed, 338 insertions, 5 deletions
diff --git a/Documentation/gpu/drm-kms-helpers.rst b/Documentation/gpu/drm-kms-helpers.rst
index 0fe726a6ee67..b327bbc11182 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -181,6 +181,15 @@ Panel Helper Reference
181.. kernel-doc:: drivers/gpu/drm/drm_panel_orientation_quirks.c 181.. kernel-doc:: drivers/gpu/drm/drm_panel_orientation_quirks.c
182 :export: 182 :export:
183 183
184Panel Self Refresh Helper Reference
185===================================
186
187.. kernel-doc:: drivers/gpu/drm/drm_self_refresh_helper.c
188 :doc: overview
189
190.. kernel-doc:: drivers/gpu/drm/drm_self_refresh_helper.c
191 :export:
192
184HDCP Helper Functions Reference 193HDCP Helper Functions Reference
185=============================== 194===============================
186 195
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index d36feb4a6233..9d630a28a788 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -43,7 +43,7 @@ drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper
43 drm_simple_kms_helper.o drm_modeset_helper.o \ 43 drm_simple_kms_helper.o drm_modeset_helper.o \
44 drm_scdc_helper.o drm_gem_framebuffer_helper.o \ 44 drm_scdc_helper.o drm_gem_framebuffer_helper.o \
45 drm_atomic_state_helper.o drm_damage_helper.o \ 45 drm_atomic_state_helper.o drm_damage_helper.o \
46 drm_format_helper.o 46 drm_format_helper.o drm_self_refresh_helper.o
47 47
48drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o 48drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o
49drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o 49drm_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 a4e779deab0f..419381abbdd1 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -384,6 +384,7 @@ static void drm_atomic_crtc_print_state(struct drm_printer *p,
384 drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name); 384 drm_printf(p, "crtc[%u]: %s\n", crtc->base.id, crtc->name);
385 drm_printf(p, "\tenable=%d\n", state->enable); 385 drm_printf(p, "\tenable=%d\n", state->enable);
386 drm_printf(p, "\tactive=%d\n", state->active); 386 drm_printf(p, "\tactive=%d\n", state->active);
387 drm_printf(p, "\tself_refresh_active=%d\n", state->self_refresh_active);
387 drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed); 388 drm_printf(p, "\tplanes_changed=%d\n", state->planes_changed);
388 drm_printf(p, "\tmode_changed=%d\n", state->mode_changed); 389 drm_printf(p, "\tmode_changed=%d\n", state->mode_changed);
389 drm_printf(p, "\tactive_changed=%d\n", state->active_changed); 390 drm_printf(p, "\tactive_changed=%d\n", state->active_changed);
@@ -999,6 +1000,7 @@ static void drm_atomic_connector_print_state(struct drm_printer *p,
999 1000
1000 drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name); 1001 drm_printf(p, "connector[%u]: %s\n", connector->base.id, connector->name);
1001 drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)"); 1002 drm_printf(p, "\tcrtc=%s\n", state->crtc ? state->crtc->name : "(null)");
1003 drm_printf(p, "\tself_refresh_aware=%d\n", state->self_refresh_aware);
1002 1004
1003 if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) 1005 if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
1004 if (state->writeback_job && state->writeback_job->fb) 1006 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 e58be6996069..d9ea7e51ffdc 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -34,6 +34,7 @@
34#include <drm/drm_device.h> 34#include <drm/drm_device.h>
35#include <drm/drm_plane_helper.h> 35#include <drm/drm_plane_helper.h>
36#include <drm/drm_print.h> 36#include <drm/drm_print.h>
37#include <drm/drm_self_refresh_helper.h>
37#include <drm/drm_vblank.h> 38#include <drm/drm_vblank.h>
38#include <drm/drm_writeback.h> 39#include <drm/drm_writeback.h>
39 40
@@ -953,10 +954,33 @@ int drm_atomic_helper_check(struct drm_device *dev,
953 if (state->legacy_cursor_update) 954 if (state->legacy_cursor_update)
954 state->async_update = !drm_atomic_helper_async_check(dev, state); 955 state->async_update = !drm_atomic_helper_async_check(dev, state);
955 956
957 drm_self_refresh_helper_alter_state(state);
958
956 return ret; 959 return ret;
957} 960}
958EXPORT_SYMBOL(drm_atomic_helper_check); 961EXPORT_SYMBOL(drm_atomic_helper_check);
959 962
963static bool
964crtc_needs_disable(struct drm_crtc_state *old_state,
965 struct drm_crtc_state *new_state)
966{
967 /*
968 * No new_state means the crtc is off, so the only criteria is whether
969 * it's currently active or in self refresh mode.
970 */
971 if (!new_state)
972 return drm_atomic_crtc_effectively_active(old_state);
973
974 /*
975 * We need to run through the crtc_funcs->disable() function if the crtc
976 * is currently on, if it's transitioning to self refresh mode, or if
977 * it's in self refresh mode and needs to be fully disabled.
978 */
979 return old_state->active ||
980 (old_state->self_refresh_active && !new_state->enable) ||
981 new_state->self_refresh_active;
982}
983
960static void 984static void
961disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) 985disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
962{ 986{
@@ -977,7 +1001,14 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
977 1001
978 old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc); 1002 old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc);
979 1003
980 if (!old_crtc_state->active || 1004 if (new_conn_state->crtc)
1005 new_crtc_state = drm_atomic_get_new_crtc_state(
1006 old_state,
1007 new_conn_state->crtc);
1008 else
1009 new_crtc_state = NULL;
1010
1011 if (!crtc_needs_disable(old_crtc_state, new_crtc_state) ||
981 !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state)) 1012 !drm_atomic_crtc_needs_modeset(old_conn_state->crtc->state))
982 continue; 1013 continue;
983 1014
@@ -1023,7 +1054,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
1023 if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) 1054 if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
1024 continue; 1055 continue;
1025 1056
1026 if (!old_crtc_state->active) 1057 if (!crtc_needs_disable(old_crtc_state, new_crtc_state))
1027 continue; 1058 continue;
1028 1059
1029 funcs = crtc->helper_private; 1060 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 97ab26679b96..7d7347a6f194 100644
--- a/drivers/gpu/drm/drm_atomic_state_helper.c
+++ b/drivers/gpu/drm/drm_atomic_state_helper.c
@@ -129,6 +129,10 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc,
129 state->commit = NULL; 129 state->commit = NULL;
130 state->event = NULL; 130 state->event = NULL;
131 state->pageflip_flags = 0; 131 state->pageflip_flags = 0;
132
133 /* Self refresh should be canceled when a new update is available */
134 state->active = drm_atomic_crtc_effectively_active(state);
135 state->self_refresh_active = false;
132} 136}
133EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); 137EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state);
134 138
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index eb22e8bdd853..abe38bdf85ae 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,
490 struct drm_mode_config *config = &dev->mode_config; 490 struct drm_mode_config *config = &dev->mode_config;
491 491
492 if (property == config->prop_active) 492 if (property == config->prop_active)
493 *val = state->active; 493 *val = drm_atomic_crtc_effectively_active(state);
494 else if (property == config->prop_mode_id) 494 else if (property == config->prop_mode_id)
495 *val = (state->mode_blob) ? state->mode_blob->base.id : 0; 495 *val = (state->mode_blob) ? state->mode_blob->base.id : 0;
496 else if (property == config->prop_vrr_enabled) 496 else if (property == config->prop_vrr_enabled)
@@ -788,7 +788,10 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
788 if (property == config->prop_crtc_id) { 788 if (property == config->prop_crtc_id) {
789 *val = (state->crtc) ? state->crtc->base.id : 0; 789 *val = (state->crtc) ? state->crtc->base.id : 0;
790 } else if (property == config->dpms_property) { 790 } else if (property == config->dpms_property) {
791 *val = connector->dpms; 791 if (state->crtc && state->crtc->state->self_refresh_active)
792 *val = DRM_MODE_DPMS_ON;
793 else
794 *val = connector->dpms;
792 } else if (property == config->tv_select_subconnector_property) { 795 } else if (property == config->tv_select_subconnector_property) {
793 *val = state->tv.subconnector; 796 *val = state->tv.subconnector;
794 } else if (property == config->tv_left_margin_property) { 797 } 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..2b3daaf77841
--- /dev/null
+++ b/drivers/gpu/drm/drm_self_refresh_helper.c
@@ -0,0 +1,216 @@
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright (C) 2019 Google, Inc.
4 *
5 * Authors:
6 * Sean Paul <seanpaul@chromium.org>
7 */
8#include <linux/bitops.h>
9#include <linux/slab.h>
10#include <linux/workqueue.h>
11
12#include <drm/drm_atomic.h>
13#include <drm/drm_atomic_helper.h>
14#include <drm/drm_connector.h>
15#include <drm/drm_crtc.h>
16#include <drm/drm_device.h>
17#include <drm/drm_mode_config.h>
18#include <drm/drm_modeset_lock.h>
19#include <drm/drm_print.h>
20#include <drm/drm_self_refresh_helper.h>
21
22/**
23 * DOC: overview
24 *
25 * This helper library provides an easy way for drivers to leverage the atomic
26 * framework to implement panel self refresh (SR) support. Drivers are
27 * responsible for initializing and cleaning up the SR helpers on load/unload
28 * (see &drm_self_refresh_helper_init/&drm_self_refresh_helper_cleanup).
29 * The connector is responsible for setting
30 * &drm_connector_state.self_refresh_aware to true at runtime if it is SR-aware
31 * (meaning it knows how to initiate self refresh on the panel).
32 *
33 * Once a crtc has enabled SR using &drm_self_refresh_helper_init, the
34 * helpers will monitor activity and call back into the driver to enable/disable
35 * SR as appropriate. The best way to think about this is that it's a DPMS
36 * on/off request with &drm_crtc_state.self_refresh_active set in crtc state
37 * that tells you to disable/enable SR on the panel instead of power-cycling it.
38 *
39 * During SR, drivers may choose to fully disable their crtc/encoder/bridge
40 * hardware (in which case no driver changes are necessary), or they can inspect
41 * &drm_crtc_state.self_refresh_active if they want to enter low power mode
42 * without full disable (in case full disable/enable is too slow).
43 *
44 * SR will be deactivated if there are any atomic updates affecting the
45 * pipe that is in SR mode. If a crtc is driving multiple connectors, all
46 * connectors must be SR aware and all will enter/exit SR mode at the same time.
47 *
48 * If the crtc and connector are SR aware, but the panel connected does not
49 * support it (or is otherwise unable to enter SR), the driver should fail
50 * atomic_check when &drm_crtc_state.self_refresh_active is true.
51 */
52
53struct drm_self_refresh_data {
54 struct drm_crtc *crtc;
55 struct delayed_work entry_work;
56 struct drm_atomic_state *save_state;
57 unsigned int entry_delay_ms;
58};
59
60static void drm_self_refresh_helper_entry_work(struct work_struct *work)
61{
62 struct drm_self_refresh_data *sr_data = container_of(
63 to_delayed_work(work),
64 struct drm_self_refresh_data, entry_work);
65 struct drm_crtc *crtc = sr_data->crtc;
66 struct drm_device *dev = crtc->dev;
67 struct drm_modeset_acquire_ctx ctx;
68 struct drm_atomic_state *state;
69 struct drm_connector *conn;
70 struct drm_connector_state *conn_state;
71 struct drm_crtc_state *crtc_state;
72 int i, ret;
73
74 drm_modeset_acquire_init(&ctx, 0);
75
76 state = drm_atomic_state_alloc(dev);
77 if (!state) {
78 ret = -ENOMEM;
79 goto out;
80 }
81
82retry:
83 state->acquire_ctx = &ctx;
84
85 crtc_state = drm_atomic_get_crtc_state(state, crtc);
86 if (IS_ERR(crtc_state)) {
87 ret = PTR_ERR(crtc_state);
88 goto out;
89 }
90
91 if (!crtc_state->enable)
92 goto out;
93
94 ret = drm_atomic_add_affected_connectors(state, crtc);
95 if (ret)
96 goto out;
97
98 for_each_new_connector_in_state(state, conn, conn_state, i) {
99 if (!conn_state->self_refresh_aware)
100 goto out;
101 }
102
103 crtc_state->active = false;
104 crtc_state->self_refresh_active = true;
105
106 ret = drm_atomic_commit(state);
107 if (ret)
108 goto out;
109
110out:
111 if (ret == -EDEADLK) {
112 drm_atomic_state_clear(state);
113 ret = drm_modeset_backoff(&ctx);
114 if (!ret)
115 goto retry;
116 }
117
118 drm_atomic_state_put(state);
119 drm_modeset_drop_locks(&ctx);
120 drm_modeset_acquire_fini(&ctx);
121}
122
123/**
124 * drm_self_refresh_helper_alter_state - Alters the atomic state for SR exit
125 * @state: the state currently being checked
126 *
127 * Called at the end of atomic check. This function checks the state for flags
128 * incompatible with self refresh exit and changes them. This is a bit
129 * disingenuous since userspace is expecting one thing and we're giving it
130 * another. However in order to keep self refresh entirely hidden from
131 * userspace, this is required.
132 *
133 * At the end, we queue up the self refresh entry work so we can enter PSR after
134 * the desired delay.
135 */
136void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state)
137{
138 struct drm_crtc *crtc;
139 struct drm_crtc_state *crtc_state;
140 int i;
141
142 if (state->async_update || !state->allow_modeset) {
143 for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
144 if (crtc_state->self_refresh_active) {
145 state->async_update = false;
146 state->allow_modeset = true;
147 break;
148 }
149 }
150 }
151
152 for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
153 struct drm_self_refresh_data *sr_data;
154
155 /* Don't trigger the entry timer when we're already in SR */
156 if (crtc_state->self_refresh_active)
157 continue;
158
159 sr_data = crtc->self_refresh_data;
160 if (!sr_data)
161 continue;
162
163 mod_delayed_work(system_wq, &sr_data->entry_work,
164 msecs_to_jiffies(sr_data->entry_delay_ms));
165 }
166}
167EXPORT_SYMBOL(drm_self_refresh_helper_alter_state);
168
169/**
170 * drm_self_refresh_helper_init - Initializes self refresh helpers for a crtc
171 * @crtc: the crtc which supports self refresh supported displays
172 * @entry_delay_ms: amount of inactivity to wait before entering self refresh
173 *
174 * Returns zero if successful or -errno on failure
175 */
176int drm_self_refresh_helper_init(struct drm_crtc *crtc,
177 unsigned int entry_delay_ms)
178{
179 struct drm_self_refresh_data *sr_data = crtc->self_refresh_data;
180
181 /* Helper is already initialized */
182 if (WARN_ON(sr_data))
183 return -EINVAL;
184
185 sr_data = kzalloc(sizeof(*sr_data), GFP_KERNEL);
186 if (!sr_data)
187 return -ENOMEM;
188
189 INIT_DELAYED_WORK(&sr_data->entry_work,
190 drm_self_refresh_helper_entry_work);
191 sr_data->entry_delay_ms = entry_delay_ms;
192 sr_data->crtc = crtc;
193
194 crtc->self_refresh_data = sr_data;
195 return 0;
196}
197EXPORT_SYMBOL(drm_self_refresh_helper_init);
198
199/**
200 * drm_self_refresh_helper_cleanup - Cleans up self refresh helpers for a crtc
201 * @crtc: the crtc to cleanup
202 */
203void drm_self_refresh_helper_cleanup(struct drm_crtc *crtc)
204{
205 struct drm_self_refresh_data *sr_data = crtc->self_refresh_data;
206
207 /* Helper is already uninitialized */
208 if (sr_data)
209 return;
210
211 crtc->self_refresh_data = NULL;
212
213 cancel_delayed_work_sync(&sr_data->entry_work);
214 kfree(sr_data);
215}
216EXPORT_SYMBOL(drm_self_refresh_helper_cleanup);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index f12215647801..927e1205d7aa 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -957,4 +957,19 @@ drm_atomic_crtc_needs_modeset(const struct drm_crtc_state *state)
957 state->connectors_changed; 957 state->connectors_changed;
958} 958}
959 959
960/**
961 * drm_atomic_crtc_effectively_active - compute whether crtc is actually active
962 * @state: &drm_crtc_state for the CRTC
963 *
964 * When in self refresh mode, the crtc_state->active value will be false, since
965 * the crtc is off. However in some cases we're interested in whether the crtc
966 * is active, or effectively active (ie: it's connected to an active display).
967 * In these cases, use this function instead of just checking active.
968 */
969static inline bool
970drm_atomic_crtc_effectively_active(const struct drm_crtc_state *state)
971{
972 return state->active || state->self_refresh_active;
973}
974
960#endif /* DRM_ATOMIC_H_ */ 975#endif /* DRM_ATOMIC_H_ */
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index 071143bc0ebd..c6f8486d8b8f 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -549,6 +549,20 @@ struct drm_connector_state {
549 struct drm_tv_connector_state tv; 549 struct drm_tv_connector_state tv;
550 550
551 /** 551 /**
552 * @self_refresh_aware:
553 *
554 * This tracks whether a connector is aware of the self refresh state.
555 * It should be set to true for those connector implementations which
556 * understand the self refresh state. This is needed since the crtc
557 * registers the self refresh helpers and it doesn't know if the
558 * connectors downstream have implemented self refresh entry/exit.
559 *
560 * Drivers should set this to true in atomic_check if they know how to
561 * handle self_refresh requests.
562 */
563 bool self_refresh_aware;
564
565 /**
552 * @picture_aspect_ratio: Connector property to control the 566 * @picture_aspect_ratio: Connector property to control the
553 * HDMI infoframe aspect ratio setting. 567 * HDMI infoframe aspect ratio setting.
554 * 568 *
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index dc42b9e35333..128d8b210621 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -54,6 +54,7 @@ struct drm_mode_set;
54struct drm_file; 54struct drm_file;
55struct drm_clip_rect; 55struct drm_clip_rect;
56struct drm_printer; 56struct drm_printer;
57struct drm_self_refresh_data;
57struct device_node; 58struct device_node;
58struct dma_fence; 59struct dma_fence;
59struct edid; 60struct edid;
@@ -301,6 +302,17 @@ struct drm_crtc_state {
301 bool vrr_enabled; 302 bool vrr_enabled;
302 303
303 /** 304 /**
305 * @self_refresh_active:
306 *
307 * Used by the self refresh helpers to denote when a self refresh
308 * transition is occurring. This will be set on enable/disable callbacks
309 * when self refresh is being enabled or disabled. In some cases, it may
310 * not be desirable to fully shut off the crtc during self refresh.
311 * CRTC's can inspect this flag and determine the best course of action.
312 */
313 bool self_refresh_active;
314
315 /**
304 * @event: 316 * @event:
305 * 317 *
306 * Optional pointer to a DRM event to signal upon completion of the 318 * Optional pointer to a DRM event to signal upon completion of the
@@ -1088,6 +1100,13 @@ struct drm_crtc {
1088 * The name of the CRTC's fence timeline. 1100 * The name of the CRTC's fence timeline.
1089 */ 1101 */
1090 char timeline_name[32]; 1102 char timeline_name[32];
1103
1104 /**
1105 * @self_refresh_data: Holds the state for the self refresh helpers
1106 *
1107 * Initialized via drm_self_refresh_helper_register().
1108 */
1109 struct drm_self_refresh_data *self_refresh_data;
1091}; 1110};
1092 1111
1093/** 1112/**
diff --git a/include/drm/drm_self_refresh_helper.h b/include/drm/drm_self_refresh_helper.h
new file mode 100644
index 000000000000..397a583ccca7
--- /dev/null
+++ b/include/drm/drm_self_refresh_helper.h
@@ -0,0 +1,20 @@
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright (C) 2019 Google, Inc.
4 *
5 * Authors:
6 * Sean Paul <seanpaul@chromium.org>
7 */
8#ifndef DRM_SELF_REFRESH_HELPER_H_
9#define DRM_SELF_REFRESH_HELPER_H_
10
11struct drm_atomic_state;
12struct drm_crtc;
13
14void drm_self_refresh_helper_alter_state(struct drm_atomic_state *state);
15
16int drm_self_refresh_helper_init(struct drm_crtc *crtc,
17 unsigned int entry_delay_ms);
18
19void drm_self_refresh_helper_cleanup(struct drm_crtc *crtc);
20#endif