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