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.
16 #include <drm/drm_crtc_helper.h>
18 #include "rockchip_drm_drv.h"
19 #include "rockchip_drm_psr.h"
21 #define PSR_FLUSH_TIMEOUT_MS 100
24 struct list_head list
;
25 struct drm_encoder
*encoder
;
31 struct delayed_work flush_work
;
33 int (*set
)(struct drm_encoder
*encoder
, bool enable
);
36 static struct psr_drv
*find_psr_by_encoder(struct drm_encoder
*encoder
)
38 struct rockchip_drm_private
*drm_drv
= encoder
->dev
->dev_private
;
41 mutex_lock(&drm_drv
->psr_list_lock
);
42 list_for_each_entry(psr
, &drm_drv
->psr_list
, list
) {
43 if (psr
->encoder
== encoder
)
46 psr
= ERR_PTR(-ENODEV
);
49 mutex_unlock(&drm_drv
->psr_list_lock
);
53 static int psr_set_state_locked(struct psr_drv
*psr
, bool enable
)
57 if (psr
->inhibit_count
> 0)
60 if (enable
== psr
->enabled
)
63 ret
= psr
->set(psr
->encoder
, enable
);
67 psr
->enabled
= enable
;
71 static void psr_flush_handler(struct work_struct
*work
)
73 struct psr_drv
*psr
= container_of(to_delayed_work(work
),
74 struct psr_drv
, flush_work
);
76 mutex_lock(&psr
->lock
);
77 psr_set_state_locked(psr
, true);
78 mutex_unlock(&psr
->lock
);
82 * rockchip_drm_psr_inhibit_put - release PSR inhibit on given encoder
83 * @encoder: encoder to obtain the PSR encoder
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.
91 * Zero on success, negative errno on failure.
93 int rockchip_drm_psr_inhibit_put(struct drm_encoder
*encoder
)
95 struct psr_drv
*psr
= find_psr_by_encoder(encoder
);
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
);
110 EXPORT_SYMBOL(rockchip_drm_psr_inhibit_put
);
113 * rockchip_drm_psr_inhibit_get - acquire PSR inhibit on given encoder
114 * @encoder: encoder to obtain the PSR encoder
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.
122 * Zero on success, negative errno on failure.
124 int rockchip_drm_psr_inhibit_get(struct drm_encoder
*encoder
)
126 struct psr_drv
*psr
= find_psr_by_encoder(encoder
);
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
);
139 EXPORT_SYMBOL(rockchip_drm_psr_inhibit_get
);
141 static void rockchip_drm_do_flush(struct psr_drv
*psr
)
143 cancel_delayed_work_sync(&psr
->flush_work
);
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
);
153 * rockchip_drm_psr_flush_all - force to flush all registered PSR encoders
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
162 * Zero on success, negative errno on failure.
164 void rockchip_drm_psr_flush_all(struct drm_device
*dev
)
166 struct rockchip_drm_private
*drm_drv
= dev
->dev_private
;
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
);
174 EXPORT_SYMBOL(rockchip_drm_psr_flush_all
);
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
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
187 * Zero on success, negative errno on failure.
189 int rockchip_drm_psr_register(struct drm_encoder
*encoder
,
190 int (*psr_set
)(struct drm_encoder
*, bool enable
))
192 struct rockchip_drm_private
*drm_drv
= encoder
->dev
->dev_private
;
195 if (!encoder
|| !psr_set
)
198 psr
= kzalloc(sizeof(struct psr_drv
), GFP_KERNEL
);
202 INIT_DELAYED_WORK(&psr
->flush_work
, psr_flush_handler
);
203 mutex_init(&psr
->lock
);
205 psr
->inhibit_count
= 1;
206 psr
->enabled
= false;
207 psr
->encoder
= encoder
;
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
);
216 EXPORT_SYMBOL(rockchip_drm_psr_register
);
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
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.
229 * Zero on success, negative errno on failure.
231 void rockchip_drm_psr_unregister(struct drm_encoder
*encoder
)
233 struct rockchip_drm_private
*drm_drv
= encoder
->dev
->dev_private
;
234 struct psr_drv
*psr
, *n
;
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
) {
240 * Any other value would mean that the encoder
243 WARN_ON(psr
->inhibit_count
!= 1);
245 list_del(&psr
->list
);
249 mutex_unlock(&drm_drv
->psr_list_lock
);
251 EXPORT_SYMBOL(rockchip_drm_psr_unregister
);