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 
find_psr_by_encoder(struct drm_encoder * encoder)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 
psr_set_state_locked(struct psr_drv * psr,bool enable)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 
psr_flush_handler(struct work_struct * work)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  */
rockchip_drm_psr_inhibit_put(struct drm_encoder * encoder)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  */
rockchip_drm_psr_inhibit_get(struct drm_encoder * encoder)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 
rockchip_drm_do_flush(struct psr_drv * psr)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  */
rockchip_drm_psr_flush_all(struct drm_device * dev)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  */
rockchip_drm_psr_register(struct drm_encoder * encoder,int (* psr_set)(struct drm_encoder *,bool enable))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 = 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 }
216 EXPORT_SYMBOL(rockchip_drm_psr_register);
217 
218 /**
219  * rockchip_drm_psr_unregister - unregister encoder to psr driver
220  * @encoder: encoder that obtain the PSR function
221  * @psr_set: call back to set PSR state
222  *
223  * It is expected that the PSR inhibit counter is 1 when this function is
224  * called, which corresponds to a state when related encoder has been
225  * disconnected from any CRTCs and its driver called
226  * rockchip_drm_psr_inhibit_get() to stop the PSR logic.
227  *
228  * Returns:
229  * Zero on success, negative errno on failure.
230  */
rockchip_drm_psr_unregister(struct drm_encoder * encoder)231 void 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 			 * Any other value would mean that the encoder
241 			 * is still in use.
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 }
251 EXPORT_SYMBOL(rockchip_drm_psr_unregister);
252