Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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