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 msecs_to_jiffies(3000) /* 3 seconds */
30 struct list_head list
;
31 struct drm_encoder
*encoder
;
36 struct timer_list flush_timer
;
38 void (*set
)(struct drm_encoder
*encoder
, bool enable
);
41 static struct psr_drv
*find_psr_by_crtc(struct drm_crtc
*crtc
)
43 struct rockchip_drm_private
*drm_drv
= crtc
->dev
->dev_private
;
47 spin_lock_irqsave(&drm_drv
->psr_list_lock
, flags
);
48 list_for_each_entry(psr
, &drm_drv
->psr_list
, list
) {
49 if (psr
->encoder
->crtc
== crtc
)
52 psr
= ERR_PTR(-ENODEV
);
55 spin_unlock_irqrestore(&drm_drv
->psr_list_lock
, flags
);
59 static void psr_set_state_locked(struct psr_drv
*psr
, enum psr_state state
)
62 * Allowed finite state machine:
64 * PSR_ENABLE < = = = = = > PSR_FLUSH
68 * PSR_DISABLE < - - - - - - - - -
70 if (state
== psr
->state
)
73 /* Requesting a flush when disabled is a noop */
74 if (state
== PSR_FLUSH
&& psr
->state
== PSR_DISABLE
)
79 /* Already disabled in flush, change the state, but not the hardware */
80 if (state
== PSR_DISABLE
&& psr
->state
== PSR_FLUSH
)
83 /* Actually commit the state change to hardware */
86 psr
->set(psr
->encoder
, true);
91 psr
->set(psr
->encoder
, false);
96 static void psr_set_state(struct psr_drv
*psr
, enum psr_state state
)
100 spin_lock_irqsave(&psr
->lock
, flags
);
101 psr_set_state_locked(psr
, state
);
102 spin_unlock_irqrestore(&psr
->lock
, flags
);
105 static void psr_flush_handler(unsigned long data
)
107 struct psr_drv
*psr
= (struct psr_drv
*)data
;
110 /* If the state has changed since we initiated the flush, do nothing */
111 spin_lock_irqsave(&psr
->lock
, flags
);
112 if (psr
->state
== PSR_FLUSH
)
113 psr_set_state_locked(psr
, PSR_ENABLE
);
114 spin_unlock_irqrestore(&psr
->lock
, flags
);
118 * rockchip_drm_psr_enable - enable the encoder PSR which bind to given CRTC
119 * @crtc: CRTC to obtain the PSR encoder
122 * Zero on success, negative errno on failure.
124 int rockchip_drm_psr_enable(struct drm_crtc
*crtc
)
126 struct psr_drv
*psr
= find_psr_by_crtc(crtc
);
131 psr_set_state(psr
, PSR_ENABLE
);
134 EXPORT_SYMBOL(rockchip_drm_psr_enable
);
137 * rockchip_drm_psr_disable - disable the encoder PSR which bind to given CRTC
138 * @crtc: CRTC to obtain the PSR encoder
141 * Zero on success, negative errno on failure.
143 int rockchip_drm_psr_disable(struct drm_crtc
*crtc
)
145 struct psr_drv
*psr
= find_psr_by_crtc(crtc
);
150 psr_set_state(psr
, PSR_DISABLE
);
153 EXPORT_SYMBOL(rockchip_drm_psr_disable
);
156 * rockchip_drm_psr_flush - force to flush all registered PSR encoders
159 * Disable the PSR function for all registered encoders, and then enable the
160 * PSR function back after PSR_FLUSH_TIMEOUT. If encoder PSR state have been
161 * changed during flush time, then keep the state no change after flush
165 * Zero on success, negative errno on failure.
167 void rockchip_drm_psr_flush(struct drm_device
*dev
)
169 struct rockchip_drm_private
*drm_drv
= dev
->dev_private
;
173 spin_lock_irqsave(&drm_drv
->psr_list_lock
, flags
);
174 list_for_each_entry(psr
, &drm_drv
->psr_list
, list
) {
175 mod_timer(&psr
->flush_timer
,
176 round_jiffies_up(jiffies
+ PSR_FLUSH_TIMEOUT
));
178 psr_set_state(psr
, PSR_FLUSH
);
180 spin_unlock_irqrestore(&drm_drv
->psr_list_lock
, flags
);
182 EXPORT_SYMBOL(rockchip_drm_psr_flush
);
185 * rockchip_drm_psr_register - register encoder to psr driver
186 * @encoder: encoder that obtain the PSR function
187 * @psr_set: call back to set PSR state
190 * Zero on success, negative errno on failure.
192 int rockchip_drm_psr_register(struct drm_encoder
*encoder
,
193 void (*psr_set
)(struct drm_encoder
*, bool enable
))
195 struct rockchip_drm_private
*drm_drv
= encoder
->dev
->dev_private
;
199 if (!encoder
|| !psr_set
)
202 psr
= kzalloc(sizeof(struct psr_drv
), GFP_KERNEL
);
206 setup_timer(&psr
->flush_timer
, psr_flush_handler
, (unsigned long)psr
);
207 spin_lock_init(&psr
->lock
);
209 psr
->state
= PSR_DISABLE
;
210 psr
->encoder
= encoder
;
213 spin_lock_irqsave(&drm_drv
->psr_list_lock
, flags
);
214 list_add_tail(&psr
->list
, &drm_drv
->psr_list
);
215 spin_unlock_irqrestore(&drm_drv
->psr_list_lock
, flags
);
219 EXPORT_SYMBOL(rockchip_drm_psr_register
);
222 * rockchip_drm_psr_unregister - unregister encoder to psr driver
223 * @encoder: encoder that obtain the PSR function
224 * @psr_set: call back to set PSR state
227 * Zero on success, negative errno on failure.
229 void rockchip_drm_psr_unregister(struct drm_encoder
*encoder
)
231 struct rockchip_drm_private
*drm_drv
= encoder
->dev
->dev_private
;
232 struct psr_drv
*psr
, *n
;
235 spin_lock_irqsave(&drm_drv
->psr_list_lock
, flags
);
236 list_for_each_entry_safe(psr
, n
, &drm_drv
->psr_list
, list
) {
237 if (psr
->encoder
== encoder
) {
238 del_timer(&psr
->flush_timer
);
239 list_del(&psr
->list
);
243 spin_unlock_irqrestore(&drm_drv
->psr_list_lock
, flags
);
245 EXPORT_SYMBOL(rockchip_drm_psr_unregister
);