Linux-libre 4.15.7-gnu
[librecmc/linux-libre.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       msecs_to_jiffies(100)
22
23 enum psr_state {
24         PSR_FLUSH,
25         PSR_ENABLE,
26         PSR_DISABLE,
27 };
28
29 struct psr_drv {
30         struct list_head        list;
31         struct drm_encoder      *encoder;
32
33         spinlock_t              lock;
34         bool                    active;
35         enum psr_state          state;
36
37         struct timer_list       flush_timer;
38
39         void (*set)(struct drm_encoder *encoder, bool enable);
40 };
41
42 static struct psr_drv *find_psr_by_crtc(struct drm_crtc *crtc)
43 {
44         struct rockchip_drm_private *drm_drv = crtc->dev->dev_private;
45         struct psr_drv *psr;
46         unsigned long flags;
47
48         spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
49         list_for_each_entry(psr, &drm_drv->psr_list, list) {
50                 if (psr->encoder->crtc == crtc)
51                         goto out;
52         }
53         psr = ERR_PTR(-ENODEV);
54
55 out:
56         spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
57         return psr;
58 }
59
60 static void psr_set_state_locked(struct psr_drv *psr, enum psr_state state)
61 {
62         /*
63          * Allowed finite state machine:
64          *
65          *   PSR_ENABLE  < = = = = = >  PSR_FLUSH
66          *       | ^                        |
67          *       | |                        |
68          *       v |                        |
69          *   PSR_DISABLE < - - - - - - - - -
70          */
71         if (state == psr->state || !psr->active)
72                 return;
73
74         /* Already disabled in flush, change the state, but not the hardware */
75         if (state == PSR_DISABLE && psr->state == PSR_FLUSH) {
76                 psr->state = state;
77                 return;
78         }
79
80         psr->state = state;
81
82         /* Actually commit the state change to hardware */
83         switch (psr->state) {
84         case PSR_ENABLE:
85                 psr->set(psr->encoder, true);
86                 break;
87
88         case PSR_DISABLE:
89         case PSR_FLUSH:
90                 psr->set(psr->encoder, false);
91                 break;
92         }
93 }
94
95 static void psr_set_state(struct psr_drv *psr, enum psr_state state)
96 {
97         unsigned long flags;
98
99         spin_lock_irqsave(&psr->lock, flags);
100         psr_set_state_locked(psr, state);
101         spin_unlock_irqrestore(&psr->lock, flags);
102 }
103
104 static void psr_flush_handler(struct timer_list *t)
105 {
106         struct psr_drv *psr = from_timer(psr, t, flush_timer);
107         unsigned long flags;
108
109         /* If the state has changed since we initiated the flush, do nothing */
110         spin_lock_irqsave(&psr->lock, flags);
111         if (psr->state == PSR_FLUSH)
112                 psr_set_state_locked(psr, PSR_ENABLE);
113         spin_unlock_irqrestore(&psr->lock, flags);
114 }
115
116 /**
117  * rockchip_drm_psr_activate - activate PSR on the given pipe
118  * @crtc: CRTC to obtain the PSR encoder
119  *
120  * Returns:
121  * Zero on success, negative errno on failure.
122  */
123 int rockchip_drm_psr_activate(struct drm_crtc *crtc)
124 {
125         struct psr_drv *psr = find_psr_by_crtc(crtc);
126         unsigned long flags;
127
128         if (IS_ERR(psr))
129                 return PTR_ERR(psr);
130
131         spin_lock_irqsave(&psr->lock, flags);
132         psr->active = true;
133         spin_unlock_irqrestore(&psr->lock, flags);
134
135         return 0;
136 }
137 EXPORT_SYMBOL(rockchip_drm_psr_activate);
138
139 /**
140  * rockchip_drm_psr_deactivate - deactivate PSR on the given pipe
141  * @crtc: CRTC to obtain the PSR encoder
142  *
143  * Returns:
144  * Zero on success, negative errno on failure.
145  */
146 int rockchip_drm_psr_deactivate(struct drm_crtc *crtc)
147 {
148         struct psr_drv *psr = find_psr_by_crtc(crtc);
149         unsigned long flags;
150
151         if (IS_ERR(psr))
152                 return PTR_ERR(psr);
153
154         spin_lock_irqsave(&psr->lock, flags);
155         psr->active = false;
156         spin_unlock_irqrestore(&psr->lock, flags);
157         del_timer_sync(&psr->flush_timer);
158
159         return 0;
160 }
161 EXPORT_SYMBOL(rockchip_drm_psr_deactivate);
162
163 static void rockchip_drm_do_flush(struct psr_drv *psr)
164 {
165         mod_timer(&psr->flush_timer,
166                   round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT));
167         psr_set_state(psr, PSR_FLUSH);
168 }
169
170 /**
171  * rockchip_drm_psr_flush - flush a single pipe
172  * @crtc: CRTC of the pipe to flush
173  *
174  * Returns:
175  * 0 on success, -errno on fail
176  */
177 int rockchip_drm_psr_flush(struct drm_crtc *crtc)
178 {
179         struct psr_drv *psr = find_psr_by_crtc(crtc);
180         if (IS_ERR(psr))
181                 return PTR_ERR(psr);
182
183         rockchip_drm_do_flush(psr);
184         return 0;
185 }
186 EXPORT_SYMBOL(rockchip_drm_psr_flush);
187
188 /**
189  * rockchip_drm_psr_flush_all - force to flush all registered PSR encoders
190  * @dev: drm device
191  *
192  * Disable the PSR function for all registered encoders, and then enable the
193  * PSR function back after PSR_FLUSH_TIMEOUT. If encoder PSR state have been
194  * changed during flush time, then keep the state no change after flush
195  * timeout.
196  *
197  * Returns:
198  * Zero on success, negative errno on failure.
199  */
200 void rockchip_drm_psr_flush_all(struct drm_device *dev)
201 {
202         struct rockchip_drm_private *drm_drv = dev->dev_private;
203         struct psr_drv *psr;
204         unsigned long flags;
205
206         spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
207         list_for_each_entry(psr, &drm_drv->psr_list, list)
208                 rockchip_drm_do_flush(psr);
209         spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
210 }
211 EXPORT_SYMBOL(rockchip_drm_psr_flush_all);
212
213 /**
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
217  *
218  * Returns:
219  * Zero on success, negative errno on failure.
220  */
221 int rockchip_drm_psr_register(struct drm_encoder *encoder,
222                         void (*psr_set)(struct drm_encoder *, bool enable))
223 {
224         struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
225         struct psr_drv *psr;
226         unsigned long flags;
227
228         if (!encoder || !psr_set)
229                 return -EINVAL;
230
231         psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
232         if (!psr)
233                 return -ENOMEM;
234
235         timer_setup(&psr->flush_timer, psr_flush_handler, 0);
236         spin_lock_init(&psr->lock);
237
238         psr->active = true;
239         psr->state = PSR_DISABLE;
240         psr->encoder = encoder;
241         psr->set = psr_set;
242
243         spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
244         list_add_tail(&psr->list, &drm_drv->psr_list);
245         spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
246
247         return 0;
248 }
249 EXPORT_SYMBOL(rockchip_drm_psr_register);
250
251 /**
252  * rockchip_drm_psr_unregister - unregister encoder to psr driver
253  * @encoder: encoder that obtain the PSR function
254  * @psr_set: call back to set PSR state
255  *
256  * Returns:
257  * Zero on success, negative errno on failure.
258  */
259 void rockchip_drm_psr_unregister(struct drm_encoder *encoder)
260 {
261         struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
262         struct psr_drv *psr, *n;
263         unsigned long flags;
264
265         spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
266         list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
267                 if (psr->encoder == encoder) {
268                         del_timer(&psr->flush_timer);
269                         list_del(&psr->list);
270                         kfree(psr);
271                 }
272         }
273         spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
274 }
275 EXPORT_SYMBOL(rockchip_drm_psr_unregister);