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 < - - - - - - - - -
71 /* Forbid no state change */
72 if (state == psr->state)
75 /* Forbid DISABLE change to FLUSH */
76 if (state == PSR_FLUSH && psr->state == PSR_DISABLE)
81 /* Allow but no need hardware change, just need assign the state */
82 if (state == PSR_DISABLE && psr->state == PSR_FLUSH)
85 /* Refact to hardware state change */
88 psr->set(psr->encoder, true);
93 psr->set(psr->encoder, false);
98 static void psr_set_state(struct psr_drv *psr, enum psr_state state)
102 spin_lock_irqsave(&psr->lock, flags);
103 psr_set_state_locked(psr, state);
104 spin_unlock_irqrestore(&psr->lock, flags);
107 static void psr_flush_handler(unsigned long data)
109 struct psr_drv *psr = (struct psr_drv *)data;
115 /* State changed between flush time, then keep it */
116 spin_lock_irqsave(&psr->lock, flags);
117 if (psr->state == PSR_FLUSH)
118 psr_set_state_locked(psr, PSR_ENABLE);
119 spin_unlock_irqrestore(&psr->lock, flags);
123 * rockchip_drm_psr_enable - enable the encoder PSR which bind to given CRTC
124 * @crtc: CRTC to obtain the PSR encoder
127 * Zero on success, negative errno on failure.
129 int rockchip_drm_psr_enable(struct drm_crtc *crtc)
131 struct psr_drv *psr = find_psr_by_crtc(crtc);
136 psr_set_state(psr, PSR_ENABLE);
139 EXPORT_SYMBOL(rockchip_drm_psr_enable);
142 * rockchip_drm_psr_disable - disable the encoder PSR which bind to given CRTC
143 * @crtc: CRTC to obtain the PSR encoder
146 * Zero on success, negative errno on failure.
148 int rockchip_drm_psr_disable(struct drm_crtc *crtc)
150 struct psr_drv *psr = find_psr_by_crtc(crtc);
155 psr_set_state(psr, PSR_DISABLE);
158 EXPORT_SYMBOL(rockchip_drm_psr_disable);
161 * rockchip_drm_psr_flush - force to flush all registered PSR encoders
164 * Disable the PSR function for all registered encoders, and then enable the
165 * PSR function back after PSR_FLUSH_TIMEOUT. If encoder PSR state have been
166 * changed during flush time, then keep the state no change after flush
170 * Zero on success, negative errno on failure.
172 void rockchip_drm_psr_flush(struct drm_device *dev)
174 struct rockchip_drm_private *drm_drv = dev->dev_private;
178 spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
179 list_for_each_entry(psr, &drm_drv->psr_list, list) {
180 mod_timer(&psr->flush_timer,
181 round_jiffies_up(jiffies + PSR_FLUSH_TIMEOUT));
183 psr_set_state(psr, PSR_FLUSH);
185 spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
187 EXPORT_SYMBOL(rockchip_drm_psr_flush);
190 * rockchip_drm_psr_register - register encoder to psr driver
191 * @encoder: encoder that obtain the PSR function
192 * @psr_set: call back to set PSR state
195 * Zero on success, negative errno on failure.
197 int rockchip_drm_psr_register(struct drm_encoder *encoder,
198 void (*psr_set)(struct drm_encoder *, bool enable))
200 struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
204 if (!encoder || !psr_set)
207 psr = kzalloc(sizeof(struct psr_drv), GFP_KERNEL);
211 setup_timer(&psr->flush_timer, psr_flush_handler, (unsigned long)psr);
212 spin_lock_init(&psr->lock);
214 psr->state = PSR_DISABLE;
215 psr->encoder = encoder;
218 spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
219 list_add_tail(&psr->list, &drm_drv->psr_list);
220 spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
224 EXPORT_SYMBOL(rockchip_drm_psr_register);
227 * rockchip_drm_psr_unregister - unregister encoder to psr driver
228 * @encoder: encoder that obtain the PSR function
229 * @psr_set: call back to set PSR state
232 * Zero on success, negative errno on failure.
234 void rockchip_drm_psr_unregister(struct drm_encoder *encoder)
236 struct rockchip_drm_private *drm_drv = encoder->dev->dev_private;
237 struct psr_drv *psr, *n;
240 spin_lock_irqsave(&drm_drv->psr_list_lock, flags);
241 list_for_each_entry_safe(psr, n, &drm_drv->psr_list, list) {
242 if (psr->encoder == encoder) {
243 del_timer(&psr->flush_timer);
244 list_del(&psr->list);
248 spin_unlock_irqrestore(&drm_drv->psr_list_lock, flags);
250 EXPORT_SYMBOL(rockchip_drm_psr_unregister);