Merge branch 'drm-fixes-5.2' of git://people.freedesktop.org/~agd5f/linux into drm...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / rockchip / rockchip_drm_psr.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4  * Author: Yakir Yang <ykk@rock-chips.com>
5  */
6
7 #include <drm/drmP.h>
8 #include <drm/drm_atomic.h>
9 #include <drm/drm_probe_helper.h>
10
11 #include "rockchip_drm_drv.h"
12 #include "rockchip_drm_psr.h"
13
14 #define PSR_FLUSH_TIMEOUT_MS    100
15
16 struct psr_drv {
17         struct list_head        list;
18         struct drm_encoder      *encoder;
19
20         struct mutex            lock;
21         int                     inhibit_count;
22         bool                    enabled;
23
24         struct delayed_work     flush_work;
25
26         int (*set)(struct drm_encoder *encoder, bool enable);
27 };
28
29 static 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;
33
34         mutex_lock(&drm_drv->psr_list_lock);
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
41 out:
42         mutex_unlock(&drm_drv->psr_list_lock);
43         return psr;
44 }
45
46 static int psr_set_state_locked(struct psr_drv *psr, bool enable)
47 {
48         int ret;
49
50         if (psr->inhibit_count > 0)
51                 return -EINVAL;
52
53         if (enable == psr->enabled)
54                 return 0;
55
56         ret = psr->set(psr->encoder, enable);
57         if (ret)
58                 return ret;
59
60         psr->enabled = enable;
61         return 0;
62 }
63
64 static void psr_flush_handler(struct work_struct *work)
65 {
66         struct psr_drv *psr = container_of(to_delayed_work(work),
67                                            struct psr_drv, flush_work);
68
69         mutex_lock(&psr->lock);
70         psr_set_state_locked(psr, true);
71         mutex_unlock(&psr->lock);
72 }
73
74 /**
75  * rockchip_drm_psr_inhibit_put - release PSR inhibit on given encoder
76  * @encoder: encoder to obtain the PSR encoder
77  *
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  *
83  * Returns:
84  * Zero on success, negative errno on failure.
85  */
86 int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder)
87 {
88         struct psr_drv *psr = find_psr_by_encoder(encoder);
89
90         if (IS_ERR(psr))
91                 return PTR_ERR(psr);
92
93         mutex_lock(&psr->lock);
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);
99         mutex_unlock(&psr->lock);
100
101         return 0;
102 }
103 EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put);
104
105 void 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 }
121 EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get_state);
122
123 void 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 }
139 EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put_state);
140
141 /**
142  * rockchip_drm_psr_inhibit_get - acquire PSR inhibit on given encoder
143  * @encoder: encoder to obtain the PSR encoder
144  *
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  *
150  * Returns:
151  * Zero on success, negative errno on failure.
152  */
153 int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder)
154 {
155         struct psr_drv *psr = find_psr_by_encoder(encoder);
156
157         if (IS_ERR(psr))
158                 return PTR_ERR(psr);
159
160         mutex_lock(&psr->lock);
161         psr_set_state_locked(psr, false);
162         ++psr->inhibit_count;
163         mutex_unlock(&psr->lock);
164         cancel_delayed_work_sync(&psr->flush_work);
165
166         return 0;
167 }
168 EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get);
169
170 static void rockchip_drm_do_flush(struct psr_drv *psr)
171 {
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);
179 }
180
181 /**
182  * rockchip_drm_psr_flush_all - force to flush all registered PSR encoders
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  */
193 void rockchip_drm_psr_flush_all(struct drm_device *dev)
194 {
195         struct rockchip_drm_private *drm_drv = dev->dev_private;
196         struct psr_drv *psr;
197
198         mutex_lock(&drm_drv->psr_list_lock);
199         list_for_each_entry(psr, &drm_drv->psr_list, list)
200                 rockchip_drm_do_flush(psr);
201         mutex_unlock(&drm_drv->psr_list_lock);
202 }
203 EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
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  *
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  *
215  * Returns:
216  * Zero on success, negative errno on failure.
217  */
218 int rockchip_drm_psr_register(struct drm_encoder *encoder,
219                         int (*psr_set)(struct drm_encoder *, bool enable))
220 {
221         struct rockchip_drm_private *drm_drv;
222         struct psr_drv *psr;
223
224         if (!encoder || !psr_set)
225                 return -EINVAL;
226
227         drm_drv = encoder->dev->dev_private;
228
229         psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
230         if (!psr)
231                 return -ENOMEM;
232
233         INIT_DELAYED_WORK(&psr->flush_work, psr_flush_handler);
234         mutex_init(&psr->lock);
235
236         psr->inhibit_count = 1;
237         psr->enabled = false;
238         psr->encoder = encoder;
239         psr->set = psr_set;
240
241         mutex_lock(&drm_drv->psr_list_lock);
242         list_add_tail(&psr->list, &drm_drv->psr_list);
243         mutex_unlock(&drm_drv->psr_list_lock);
244
245         return 0;
246 }
247 EXPORT_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  *
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  *
259  * Returns:
260  * Zero on success, negative errno on failure.
261  */
262 void 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
267         mutex_lock(&drm_drv->psr_list_lock);
268         list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
269                 if (psr->encoder == encoder) {
270                         /*
271                          * Any other value would mean that the encoder
272                          * is still in use.
273                          */
274                         WARN_ON(psr->inhibit_count != 1);
275
276                         list_del(&psr->list);
277                         kfree(psr);
278                 }
279         }
280         mutex_unlock(&drm_drv->psr_list_lock);
281 }
282 EXPORT_SYMBOL(rockchip_drm_psr_unregister);