dt-bindings: mtd: ingenic: Use standard ecc-engine property
[linux/fpc-iii.git] / drivers / gpu / drm / rockchip / rockchip_drm_psr.c
bloba0c8bd235b675b26ff7192367b36d05463479b41
1 /*
2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3 * Author: Yakir Yang <ykk@rock-chips.com>
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <drm/drmP.h>
16 #include <drm/drm_atomic.h>
17 #include <drm/drm_probe_helper.h>
19 #include "rockchip_drm_drv.h"
20 #include "rockchip_drm_psr.h"
22 #define PSR_FLUSH_TIMEOUT_MS 100
24 struct psr_drv {
25 struct list_head list;
26 struct drm_encoder *encoder;
28 struct mutex lock;
29 int inhibit_count;
30 bool enabled;
32 struct delayed_work flush_work;
34 int (*set)(struct drm_encoder *encoder, bool enable);
37 static struct psr_drv *find_psr_by_encoder(struct drm_encoder *encoder)
39 struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
40 struct psr_drv *psr;
42 mutex_lock(&drm_drv->psr_list_lock);
43 list_for_each_entry(psr, &drm_drv->psr_list, list) {
44 if (psr->encoder == encoder)
45 goto out;
47 psr = ERR_PTR(-ENODEV);
49 out:
50 mutex_unlock(&drm_drv->psr_list_lock);
51 return psr;
54 static int psr_set_state_locked(struct psr_drv *psr, bool enable)
56 int ret;
58 if (psr->inhibit_count > 0)
59 return -EINVAL;
61 if (enable == psr->enabled)
62 return 0;
64 ret = psr->set(psr->encoder, enable);
65 if (ret)
66 return ret;
68 psr->enabled = enable;
69 return 0;
72 static void psr_flush_handler(struct work_struct *work)
74 struct psr_drv *psr = container_of(to_delayed_work(work),
75 struct psr_drv, flush_work);
77 mutex_lock(&psr->lock);
78 psr_set_state_locked(psr, true);
79 mutex_unlock(&psr->lock);
82 /**
83 * rockchip_drm_psr_inhibit_put - release PSR inhibit on given encoder
84 * @encoder: encoder to obtain the PSR encoder
86 * Decrements PSR inhibit count on given encoder. Should be called only
87 * for a PSR inhibit count increment done before. If PSR inhibit counter
88 * reaches zero, PSR flush work is scheduled to make the hardware enter
89 * PSR mode in PSR_FLUSH_TIMEOUT_MS.
91 * Returns:
92 * Zero on success, negative errno on failure.
94 int rockchip_drm_psr_inhibit_put(struct drm_encoder *encoder)
96 struct psr_drv *psr = find_psr_by_encoder(encoder);
98 if (IS_ERR(psr))
99 return PTR_ERR(psr);
101 mutex_lock(&psr->lock);
102 --psr->inhibit_count;
103 WARN_ON(psr->inhibit_count < 0);
104 if (!psr->inhibit_count)
105 mod_delayed_work(system_wq, &psr->flush_work,
106 PSR_FLUSH_TIMEOUT_MS);
107 mutex_unlock(&psr->lock);
109 return 0;
111 EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put);
113 void rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state)
115 struct drm_crtc *crtc;
116 struct drm_crtc_state *crtc_state;
117 struct drm_encoder *encoder;
118 u32 encoder_mask = 0;
119 int i;
121 for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
122 encoder_mask |= crtc_state->encoder_mask;
123 encoder_mask |= crtc->state->encoder_mask;
126 drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
127 rockchip_drm_psr_inhibit_get(encoder);
129 EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get_state);
131 void rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state)
133 struct drm_crtc *crtc;
134 struct drm_crtc_state *crtc_state;
135 struct drm_encoder *encoder;
136 u32 encoder_mask = 0;
137 int i;
139 for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
140 encoder_mask |= crtc_state->encoder_mask;
141 encoder_mask |= crtc->state->encoder_mask;
144 drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
145 rockchip_drm_psr_inhibit_put(encoder);
147 EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put_state);
150 * rockchip_drm_psr_inhibit_get - acquire PSR inhibit on given encoder
151 * @encoder: encoder to obtain the PSR encoder
153 * Increments PSR inhibit count on given encoder. This function guarantees
154 * that after it returns PSR is turned off on given encoder and no PSR-related
155 * hardware state change occurs at least until a matching call to
156 * rockchip_drm_psr_inhibit_put() is done.
158 * Returns:
159 * Zero on success, negative errno on failure.
161 int rockchip_drm_psr_inhibit_get(struct drm_encoder *encoder)
163 struct psr_drv *psr = find_psr_by_encoder(encoder);
165 if (IS_ERR(psr))
166 return PTR_ERR(psr);
168 mutex_lock(&psr->lock);
169 psr_set_state_locked(psr, false);
170 ++psr->inhibit_count;
171 mutex_unlock(&psr->lock);
172 cancel_delayed_work_sync(&psr->flush_work);
174 return 0;
176 EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get);
178 static void rockchip_drm_do_flush(struct psr_drv *psr)
180 cancel_delayed_work_sync(&psr->flush_work);
182 mutex_lock(&psr->lock);
183 if (!psr_set_state_locked(psr, false))
184 mod_delayed_work(system_wq, &psr->flush_work,
185 PSR_FLUSH_TIMEOUT_MS);
186 mutex_unlock(&psr->lock);
190 * rockchip_drm_psr_flush_all - force to flush all registered PSR encoders
191 * @dev: drm device
193 * Disable the PSR function for all registered encoders, and then enable the
194 * PSR function back after PSR_FLUSH_TIMEOUT. If encoder PSR state have been
195 * changed during flush time, then keep the state no change after flush
196 * timeout.
198 * Returns:
199 * Zero on success, negative errno on failure.
201 void rockchip_drm_psr_flush_all(struct drm_device *dev)
203 struct rockchip_drm_private *drm_drv = dev->dev_private;
204 struct psr_drv *psr;
206 mutex_lock(&drm_drv->psr_list_lock);
207 list_for_each_entry(psr, &drm_drv->psr_list, list)
208 rockchip_drm_do_flush(psr);
209 mutex_unlock(&drm_drv->psr_list_lock);
211 EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
214 * rockchip_drm_psr_register - register encoder to psr driver
215 * @encoder: encoder that obtain the PSR function
216 * @psr_set: call back to set PSR state
218 * The function returns with PSR inhibit counter initialized with one
219 * and the caller (typically encoder driver) needs to call
220 * rockchip_drm_psr_inhibit_put() when it becomes ready to accept PSR
221 * enable request.
223 * Returns:
224 * Zero on success, negative errno on failure.
226 int rockchip_drm_psr_register(struct drm_encoder *encoder,
227 int (*psr_set)(struct drm_encoder *, bool enable))
229 struct rockchip_drm_private *drm_drv;
230 struct psr_drv *psr;
232 if (!encoder || !psr_set)
233 return -EINVAL;
235 drm_drv = encoder->dev->dev_private;
237 psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
238 if (!psr)
239 return -ENOMEM;
241 INIT_DELAYED_WORK(&psr->flush_work, psr_flush_handler);
242 mutex_init(&psr->lock);
244 psr->inhibit_count = 1;
245 psr->enabled = false;
246 psr->encoder = encoder;
247 psr->set = psr_set;
249 mutex_lock(&drm_drv->psr_list_lock);
250 list_add_tail(&psr->list, &drm_drv->psr_list);
251 mutex_unlock(&drm_drv->psr_list_lock);
253 return 0;
255 EXPORT_SYMBOL(rockchip_drm_psr_register);
258 * rockchip_drm_psr_unregister - unregister encoder to psr driver
259 * @encoder: encoder that obtain the PSR function
260 * @psr_set: call back to set PSR state
262 * It is expected that the PSR inhibit counter is 1 when this function is
263 * called, which corresponds to a state when related encoder has been
264 * disconnected from any CRTCs and its driver called
265 * rockchip_drm_psr_inhibit_get() to stop the PSR logic.
267 * Returns:
268 * Zero on success, negative errno on failure.
270 void rockchip_drm_psr_unregister(struct drm_encoder *encoder)
272 struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
273 struct psr_drv *psr, *n;
275 mutex_lock(&drm_drv->psr_list_lock);
276 list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
277 if (psr->encoder == encoder) {
279 * Any other value would mean that the encoder
280 * is still in use.
282 WARN_ON(psr->inhibit_count != 1);
284 list_del(&psr->list);
285 kfree(psr);
288 mutex_unlock(&drm_drv->psr_list_lock);
290 EXPORT_SYMBOL(rockchip_drm_psr_unregister);