1
2
3
4
5
6
7
8
9
10
11
12
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
23struct 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
36static 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
48out:
49 mutex_unlock(&drm_drv->psr_list_lock);
50 return psr;
51}
52
53static 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
71static 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
83
84
85
86
87
88
89
90
91
92
93int 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}
110EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put);
111
112
113
114
115
116
117
118
119
120
121
122
123
124int 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}
139EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get);
140
141static 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
154
155
156
157
158
159
160
161
162
163
164void 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}
174EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189int 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 = encoder->dev->dev_private;
193 struct psr_drv *psr;
194
195 if (!encoder || !psr_set)
196 return -EINVAL;
197
198 psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
199 if (!psr)
200 return -ENOMEM;
201
202 INIT_DELAYED_WORK(&psr->flush_work, psr_flush_handler);
203 mutex_init(&psr->lock);
204
205 psr->inhibit_count = 1;
206 psr->enabled = false;
207 psr->encoder = encoder;
208 psr->set = psr_set;
209
210 mutex_lock(&drm_drv->psr_list_lock);
211 list_add_tail(&psr->list, &drm_drv->psr_list);
212 mutex_unlock(&drm_drv->psr_list_lock);
213
214 return 0;
215}
216EXPORT_SYMBOL(rockchip_drm_psr_register);
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231void rockchip_drm_psr_unregister(struct drm_encoder *encoder)
232{
233 struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
234 struct psr_drv *psr, *n;
235
236 mutex_lock(&drm_drv->psr_list_lock);
237 list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
238 if (psr->encoder == encoder) {
239
240
241
242
243 WARN_ON(psr->inhibit_count != 1);
244
245 list_del(&psr->list);
246 kfree(psr);
247 }
248 }
249 mutex_unlock(&drm_drv->psr_list_lock);
250}
251EXPORT_SYMBOL(rockchip_drm_psr_unregister);
252