]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/gpu/drm/rockchip/rockchip_drm_psr.c
Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mirror_ubuntu-jammy-kernel.git] / drivers / gpu / drm / rockchip / rockchip_drm_psr.c
CommitLineData
9c92ab61 1// SPDX-License-Identifier: GPL-2.0-only
5182c1a5
YY
2/*
3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4 * Author: Yakir Yang <ykk@rock-chips.com>
5182c1a5
YY
5 */
6
7#include <drm/drmP.h>
15609559 8#include <drm/drm_atomic.h>
fcd70cd3 9#include <drm/drm_probe_helper.h>
5182c1a5
YY
10
11#include "rockchip_drm_drv.h"
12#include "rockchip_drm_psr.h"
13
60beeccc 14#define PSR_FLUSH_TIMEOUT_MS 100
5182c1a5 15
5182c1a5
YY
16struct psr_drv {
17 struct list_head list;
18 struct drm_encoder *encoder;
19
60beeccc 20 struct mutex lock;
6e6cf3e2 21 int inhibit_count;
39b138ea 22 bool enabled;
5182c1a5 23
60beeccc 24 struct delayed_work flush_work;
5182c1a5 25
2a7b44c5 26 int (*set)(struct drm_encoder *encoder, bool enable);
5182c1a5
YY
27};
28
7f3c191b 29static struct psr_drv *find_psr_by_encoder(struct drm_encoder *encoder)
30{
31 struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
32 struct psr_drv *psr;
7f3c191b 33
60beeccc 34 mutex_lock(&drm_drv->psr_list_lock);
7f3c191b 35 list_for_each_entry(psr, &drm_drv->psr_list, list) {
36 if (psr->encoder == encoder)
37 goto out;
38 }
39 psr = ERR_PTR(-ENODEV);
40
41out:
60beeccc 42 mutex_unlock(&drm_drv->psr_list_lock);
7f3c191b 43 return psr;
44}
45
39b138ea 46static int psr_set_state_locked(struct psr_drv *psr, bool enable)
5182c1a5 47{
39b138ea 48 int ret;
be91a983 49
6e6cf3e2 50 if (psr->inhibit_count > 0)
39b138ea 51 return -EINVAL;
2a7b44c5 52
39b138ea
TF
53 if (enable == psr->enabled)
54 return 0;
5182c1a5 55
39b138ea
TF
56 ret = psr->set(psr->encoder, enable);
57 if (ret)
58 return ret;
59
60 psr->enabled = enable;
61 return 0;
eec85347
SP
62}
63
60beeccc 64static void psr_flush_handler(struct work_struct *work)
5182c1a5 65{
60beeccc
SP
66 struct psr_drv *psr = container_of(to_delayed_work(work),
67 struct psr_drv, flush_work);
5182c1a5 68
60beeccc 69 mutex_lock(&psr->lock);
39b138ea 70 psr_set_state_locked(psr, true);
60beeccc 71 mutex_unlock(&psr->lock);
5182c1a5
YY
72}
73
74/**
6e6cf3e2 75 * rockchip_drm_psr_inhibit_put - release PSR inhibit on given encoder
7f3c191b 76 * @encoder: encoder to obtain the PSR encoder
5182c1a5 77 *
6e6cf3e2
TF
78 * Decrements PSR inhibit count on given encoder. Should be called only
79 * for a PSR inhibit count increment done before. If PSR inhibit counter
80 * reaches zero, PSR flush work is scheduled to make the hardware enter
81 * PSR mode in PSR_FLUSH_TIMEOUT_MS.
82 *
5182c1a5
YY
83 * Returns:
84 * Zero on success, negative errno on failure.
85 */
6e6cf3e2 86int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder)
5182c1a5 87{
7f3c191b 88 struct psr_drv *psr = find_psr_by_encoder(encoder);
5182c1a5
YY
89
90 if (IS_ERR(psr))
91 return PTR_ERR(psr);
92
60beeccc 93 mutex_lock(&psr->lock);
6e6cf3e2
TF
94 --psr->inhibit_count;
95 WARN_ON(psr->inhibit_count < 0);
96 if (!psr->inhibit_count)
97 mod_delayed_work(system_wq, &psr->flush_work,
98 PSR_FLUSH_TIMEOUT_MS);
60beeccc 99 mutex_unlock(&psr->lock);
b883c9ba 100
5182c1a5
YY
101 return 0;
102}
6e6cf3e2 103EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put);
5182c1a5 104
15609559
EBS
105void rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state)
106{
107 struct drm_crtc *crtc;
108 struct drm_crtc_state *crtc_state;
109 struct drm_encoder *encoder;
110 u32 encoder_mask = 0;
111 int i;
112
113 for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
114 encoder_mask |= crtc_state->encoder_mask;
115 encoder_mask |= crtc->state->encoder_mask;
116 }
117
118 drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
119 rockchip_drm_psr_inhibit_get(encoder);
120}
121EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get_state);
122
123void rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state)
124{
125 struct drm_crtc *crtc;
126 struct drm_crtc_state *crtc_state;
127 struct drm_encoder *encoder;
128 u32 encoder_mask = 0;
129 int i;
130
131 for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
132 encoder_mask |= crtc_state->encoder_mask;
133 encoder_mask |= crtc->state->encoder_mask;
134 }
135
136 drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
137 rockchip_drm_psr_inhibit_put(encoder);
138}
139EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put_state);
140
5182c1a5 141/**
6e6cf3e2 142 * rockchip_drm_psr_inhibit_get - acquire PSR inhibit on given encoder
7f3c191b 143 * @encoder: encoder to obtain the PSR encoder
5182c1a5 144 *
6e6cf3e2
TF
145 * Increments PSR inhibit count on given encoder. This function guarantees
146 * that after it returns PSR is turned off on given encoder and no PSR-related
147 * hardware state change occurs at least until a matching call to
148 * rockchip_drm_psr_inhibit_put() is done.
149 *
5182c1a5
YY
150 * Returns:
151 * Zero on success, negative errno on failure.
152 */
6e6cf3e2 153int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder)
5182c1a5 154{
7f3c191b 155 struct psr_drv *psr = find_psr_by_encoder(encoder);
b883c9ba
SP
156
157 if (IS_ERR(psr))
158 return PTR_ERR(psr);
159
60beeccc 160 mutex_lock(&psr->lock);
6e6cf3e2
TF
161 psr_set_state_locked(psr, false);
162 ++psr->inhibit_count;
60beeccc
SP
163 mutex_unlock(&psr->lock);
164 cancel_delayed_work_sync(&psr->flush_work);
b883c9ba
SP
165
166 return 0;
167}
6e6cf3e2 168EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get);
b883c9ba
SP
169
170static void rockchip_drm_do_flush(struct psr_drv *psr)
171{
39b138ea
TF
172 cancel_delayed_work_sync(&psr->flush_work);
173
174 mutex_lock(&psr->lock);
175 if (!psr_set_state_locked(psr, false))
176 mod_delayed_work(system_wq, &psr->flush_work,
177 PSR_FLUSH_TIMEOUT_MS);
178 mutex_unlock(&psr->lock);
b883c9ba 179}
5182c1a5 180
5182c1a5 181/**
b883c9ba 182 * rockchip_drm_psr_flush_all - force to flush all registered PSR encoders
5182c1a5
YY
183 * @dev: drm device
184 *
185 * Disable the PSR function for all registered encoders, and then enable the
186 * PSR function back after PSR_FLUSH_TIMEOUT. If encoder PSR state have been
187 * changed during flush time, then keep the state no change after flush
188 * timeout.
189 *
190 * Returns:
191 * Zero on success, negative errno on failure.
192 */
b883c9ba 193void rockchip_drm_psr_flush_all(struct drm_device *dev)
5182c1a5
YY
194{
195 struct rockchip_drm_private *drm_drv = dev->dev_private;
196 struct psr_drv *psr;
197
60beeccc 198 mutex_lock(&drm_drv->psr_list_lock);
b883c9ba
SP
199 list_for_each_entry(psr, &drm_drv->psr_list, list)
200 rockchip_drm_do_flush(psr);
60beeccc 201 mutex_unlock(&drm_drv->psr_list_lock);
5182c1a5 202}
b883c9ba 203EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
5182c1a5
YY
204
205/**
206 * rockchip_drm_psr_register - register encoder to psr driver
207 * @encoder: encoder that obtain the PSR function
208 * @psr_set: call back to set PSR state
209 *
6e6cf3e2
TF
210 * The function returns with PSR inhibit counter initialized with one
211 * and the caller (typically encoder driver) needs to call
212 * rockchip_drm_psr_inhibit_put() when it becomes ready to accept PSR
213 * enable request.
214 *
5182c1a5
YY
215 * Returns:
216 * Zero on success, negative errno on failure.
217 */
218int rockchip_drm_psr_register(struct drm_encoder *encoder,
2a7b44c5 219 int (*psr_set)(struct drm_encoder *, bool enable))
5182c1a5 220{
4eda776c 221 struct rockchip_drm_private *drm_drv;
5182c1a5
YY
222 struct psr_drv *psr;
223
224 if (!encoder || !psr_set)
225 return -EINVAL;
226
4eda776c
EBS
227 drm_drv = encoder->dev->dev_private;
228
5182c1a5
YY
229 psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
230 if (!psr)
231 return -ENOMEM;
232
60beeccc
SP
233 INIT_DELAYED_WORK(&psr->flush_work, psr_flush_handler);
234 mutex_init(&psr->lock);
5182c1a5 235
6e6cf3e2 236 psr->inhibit_count = 1;
39b138ea 237 psr->enabled = false;
5182c1a5
YY
238 psr->encoder = encoder;
239 psr->set = psr_set;
240
60beeccc 241 mutex_lock(&drm_drv->psr_list_lock);
5182c1a5 242 list_add_tail(&psr->list, &drm_drv->psr_list);
60beeccc 243 mutex_unlock(&drm_drv->psr_list_lock);
5182c1a5
YY
244
245 return 0;
246}
247EXPORT_SYMBOL(rockchip_drm_psr_register);
248
249/**
250 * rockchip_drm_psr_unregister - unregister encoder to psr driver
251 * @encoder: encoder that obtain the PSR function
252 * @psr_set: call back to set PSR state
253 *
6e6cf3e2
TF
254 * It is expected that the PSR inhibit counter is 1 when this function is
255 * called, which corresponds to a state when related encoder has been
256 * disconnected from any CRTCs and its driver called
257 * rockchip_drm_psr_inhibit_get() to stop the PSR logic.
258 *
5182c1a5
YY
259 * Returns:
260 * Zero on success, negative errno on failure.
261 */
262void rockchip_drm_psr_unregister(struct drm_encoder *encoder)
263{
264 struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
265 struct psr_drv *psr, *n;
266
60beeccc 267 mutex_lock(&drm_drv->psr_list_lock);
5182c1a5
YY
268 list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
269 if (psr->encoder == encoder) {
6e6cf3e2
TF
270 /*
271 * Any other value would mean that the encoder
272 * is still in use.
273 */
274 WARN_ON(psr->inhibit_count != 1);
275
5182c1a5
YY
276 list_del(&psr->list);
277 kfree(psr);
278 }
279 }
60beeccc 280 mutex_unlock(&drm_drv->psr_list_lock);
5182c1a5
YY
281}
282EXPORT_SYMBOL(rockchip_drm_psr_unregister);