1 /* exynos_drm_crtc.c 2 * 3 * Copyright (c) 2011 Samsung Electronics Co., Ltd. 4 * Authors: 5 * Inki Dae <inki.dae@samsung.com> 6 * Joonyoung Shim <jy0922.shim@samsung.com> 7 * Seung-Woo Kim <sw0312.kim@samsung.com> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the 11 * Free Software Foundation; either version 2 of the License, or (at your 12 * option) any later version. 13 */ 14 15 #include <drm/drmP.h> 16 #include <drm/drm_crtc_helper.h> 17 18 #include "exynos_drm_crtc.h" 19 #include "exynos_drm_drv.h" 20 #include "exynos_drm_encoder.h" 21 #include "exynos_drm_plane.h" 22 23 #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\ 24 drm_crtc) 25 26 enum exynos_crtc_mode { 27 CRTC_MODE_NORMAL, /* normal mode */ 28 CRTC_MODE_BLANK, /* The private plane of crtc is blank */ 29 }; 30 31 /* 32 * Exynos specific crtc structure. 33 * 34 * @drm_crtc: crtc object. 35 * @drm_plane: pointer of private plane object for this crtc 36 * @pipe: a crtc index created at load() with a new crtc object creation 37 * and the crtc object would be set to private->crtc array 38 * to get a crtc object corresponding to this pipe from private->crtc 39 * array when irq interrupt occured. the reason of using this pipe is that 40 * drm framework doesn't support multiple irq yet. 41 * we can refer to the crtc to current hardware interrupt occured through 42 * this pipe value. 43 * @dpms: store the crtc dpms value 44 * @mode: store the crtc mode value 45 */ 46 struct exynos_drm_crtc { 47 struct drm_crtc drm_crtc; 48 struct drm_plane *plane; 49 unsigned int pipe; 50 unsigned int dpms; 51 enum exynos_crtc_mode mode; 52 wait_queue_head_t pending_flip_queue; 53 atomic_t pending_flip; 54 }; 55 56 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 57 { 58 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 59 60 DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); 61 62 if (exynos_crtc->dpms == mode) { 63 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); 64 return; 65 } 66 67 if (mode > DRM_MODE_DPMS_ON) { 68 /* wait for the completion of page flip. */ 69 wait_event(exynos_crtc->pending_flip_queue, 70 atomic_read(&exynos_crtc->pending_flip) == 0); 71 drm_vblank_off(crtc->dev, exynos_crtc->pipe); 72 } 73 74 exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); 75 exynos_crtc->dpms = mode; 76 } 77 78 static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) 79 { 80 /* drm framework doesn't check NULL. */ 81 } 82 83 static void exynos_drm_crtc_commit(struct drm_crtc *crtc) 84 { 85 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 86 87 exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 88 exynos_plane_commit(exynos_crtc->plane); 89 exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); 90 } 91 92 static bool 93 exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, 94 const struct drm_display_mode *mode, 95 struct drm_display_mode *adjusted_mode) 96 { 97 /* drm framework doesn't check NULL */ 98 return true; 99 } 100 101 static int 102 exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, 103 struct drm_display_mode *adjusted_mode, int x, int y, 104 struct drm_framebuffer *old_fb) 105 { 106 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 107 struct drm_plane *plane = exynos_crtc->plane; 108 unsigned int crtc_w; 109 unsigned int crtc_h; 110 int pipe = exynos_crtc->pipe; 111 int ret; 112 113 /* 114 * copy the mode data adjusted by mode_fixup() into crtc->mode 115 * so that hardware can be seet to proper mode. 116 */ 117 memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); 118 119 crtc_w = crtc->fb->width - x; 120 crtc_h = crtc->fb->height - y; 121 122 ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h, 123 x, y, crtc_w, crtc_h); 124 if (ret) 125 return ret; 126 127 plane->crtc = crtc; 128 plane->fb = crtc->fb; 129 130 exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe); 131 132 return 0; 133 } 134 135 static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y, 136 struct drm_framebuffer *old_fb) 137 { 138 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 139 struct drm_plane *plane = exynos_crtc->plane; 140 unsigned int crtc_w; 141 unsigned int crtc_h; 142 int ret; 143 144 /* when framebuffer changing is requested, crtc's dpms should be on */ 145 if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { 146 DRM_ERROR("failed framebuffer changing request.\n"); 147 return -EPERM; 148 } 149 150 crtc_w = crtc->fb->width - x; 151 crtc_h = crtc->fb->height - y; 152 153 ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h, 154 x, y, crtc_w, crtc_h); 155 if (ret) 156 return ret; 157 158 exynos_drm_crtc_commit(crtc); 159 160 return 0; 161 } 162 163 static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 164 struct drm_framebuffer *old_fb) 165 { 166 return exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb); 167 } 168 169 static void exynos_drm_crtc_disable(struct drm_crtc *crtc) 170 { 171 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 172 173 exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF); 174 exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 175 } 176 177 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 178 .dpms = exynos_drm_crtc_dpms, 179 .prepare = exynos_drm_crtc_prepare, 180 .commit = exynos_drm_crtc_commit, 181 .mode_fixup = exynos_drm_crtc_mode_fixup, 182 .mode_set = exynos_drm_crtc_mode_set, 183 .mode_set_base = exynos_drm_crtc_mode_set_base, 184 .disable = exynos_drm_crtc_disable, 185 }; 186 187 static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, 188 struct drm_framebuffer *fb, 189 struct drm_pending_vblank_event *event, 190 uint32_t page_flip_flags) 191 { 192 struct drm_device *dev = crtc->dev; 193 struct exynos_drm_private *dev_priv = dev->dev_private; 194 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 195 struct drm_framebuffer *old_fb = crtc->fb; 196 int ret = -EINVAL; 197 198 /* when the page flip is requested, crtc's dpms should be on */ 199 if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { 200 DRM_ERROR("failed page flip request.\n"); 201 return -EINVAL; 202 } 203 204 mutex_lock(&dev->struct_mutex); 205 206 if (event) { 207 /* 208 * the pipe from user always is 0 so we can set pipe number 209 * of current owner to event. 210 */ 211 event->pipe = exynos_crtc->pipe; 212 213 ret = drm_vblank_get(dev, exynos_crtc->pipe); 214 if (ret) { 215 DRM_DEBUG("failed to acquire vblank counter\n"); 216 217 goto out; 218 } 219 220 spin_lock_irq(&dev->event_lock); 221 list_add_tail(&event->base.link, 222 &dev_priv->pageflip_event_list); 223 atomic_set(&exynos_crtc->pending_flip, 1); 224 spin_unlock_irq(&dev->event_lock); 225 226 crtc->fb = fb; 227 ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y, 228 NULL); 229 if (ret) { 230 crtc->fb = old_fb; 231 232 spin_lock_irq(&dev->event_lock); 233 drm_vblank_put(dev, exynos_crtc->pipe); 234 list_del(&event->base.link); 235 spin_unlock_irq(&dev->event_lock); 236 237 goto out; 238 } 239 } 240 out: 241 mutex_unlock(&dev->struct_mutex); 242 return ret; 243 } 244 245 static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) 246 { 247 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 248 struct exynos_drm_private *private = crtc->dev->dev_private; 249 250 private->crtc[exynos_crtc->pipe] = NULL; 251 252 drm_crtc_cleanup(crtc); 253 kfree(exynos_crtc); 254 } 255 256 static int exynos_drm_crtc_set_property(struct drm_crtc *crtc, 257 struct drm_property *property, 258 uint64_t val) 259 { 260 struct drm_device *dev = crtc->dev; 261 struct exynos_drm_private *dev_priv = dev->dev_private; 262 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 263 264 if (property == dev_priv->crtc_mode_property) { 265 enum exynos_crtc_mode mode = val; 266 267 if (mode == exynos_crtc->mode) 268 return 0; 269 270 exynos_crtc->mode = mode; 271 272 switch (mode) { 273 case CRTC_MODE_NORMAL: 274 exynos_drm_crtc_commit(crtc); 275 break; 276 case CRTC_MODE_BLANK: 277 exynos_plane_dpms(exynos_crtc->plane, 278 DRM_MODE_DPMS_OFF); 279 break; 280 default: 281 break; 282 } 283 284 return 0; 285 } 286 287 return -EINVAL; 288 } 289 290 static struct drm_crtc_funcs exynos_crtc_funcs = { 291 .set_config = drm_crtc_helper_set_config, 292 .page_flip = exynos_drm_crtc_page_flip, 293 .destroy = exynos_drm_crtc_destroy, 294 .set_property = exynos_drm_crtc_set_property, 295 }; 296 297 static const struct drm_prop_enum_list mode_names[] = { 298 { CRTC_MODE_NORMAL, "normal" }, 299 { CRTC_MODE_BLANK, "blank" }, 300 }; 301 302 static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc) 303 { 304 struct drm_device *dev = crtc->dev; 305 struct exynos_drm_private *dev_priv = dev->dev_private; 306 struct drm_property *prop; 307 308 prop = dev_priv->crtc_mode_property; 309 if (!prop) { 310 prop = drm_property_create_enum(dev, 0, "mode", mode_names, 311 ARRAY_SIZE(mode_names)); 312 if (!prop) 313 return; 314 315 dev_priv->crtc_mode_property = prop; 316 } 317 318 drm_object_attach_property(&crtc->base, prop, 0); 319 } 320 321 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) 322 { 323 struct exynos_drm_crtc *exynos_crtc; 324 struct exynos_drm_private *private = dev->dev_private; 325 struct drm_crtc *crtc; 326 327 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); 328 if (!exynos_crtc) 329 return -ENOMEM; 330 331 exynos_crtc->pipe = nr; 332 exynos_crtc->dpms = DRM_MODE_DPMS_OFF; 333 init_waitqueue_head(&exynos_crtc->pending_flip_queue); 334 atomic_set(&exynos_crtc->pending_flip, 0); 335 exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true); 336 if (!exynos_crtc->plane) { 337 kfree(exynos_crtc); 338 return -ENOMEM; 339 } 340 341 crtc = &exynos_crtc->drm_crtc; 342 343 private->crtc[nr] = crtc; 344 345 drm_crtc_init(dev, crtc, &exynos_crtc_funcs); 346 drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); 347 348 exynos_drm_crtc_attach_mode_property(crtc); 349 350 return 0; 351 } 352 353 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) 354 { 355 struct exynos_drm_private *private = dev->dev_private; 356 struct exynos_drm_crtc *exynos_crtc = 357 to_exynos_crtc(private->crtc[crtc]); 358 359 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) 360 return -EPERM; 361 362 exynos_drm_fn_encoder(private->crtc[crtc], &crtc, 363 exynos_drm_enable_vblank); 364 365 return 0; 366 } 367 368 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) 369 { 370 struct exynos_drm_private *private = dev->dev_private; 371 struct exynos_drm_crtc *exynos_crtc = 372 to_exynos_crtc(private->crtc[crtc]); 373 374 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) 375 return; 376 377 exynos_drm_fn_encoder(private->crtc[crtc], &crtc, 378 exynos_drm_disable_vblank); 379 } 380 381 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc) 382 { 383 struct exynos_drm_private *dev_priv = dev->dev_private; 384 struct drm_pending_vblank_event *e, *t; 385 struct drm_crtc *drm_crtc = dev_priv->crtc[crtc]; 386 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); 387 unsigned long flags; 388 389 spin_lock_irqsave(&dev->event_lock, flags); 390 391 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, 392 base.link) { 393 /* if event's pipe isn't same as crtc then ignore it. */ 394 if (crtc != e->pipe) 395 continue; 396 397 list_del(&e->base.link); 398 drm_send_vblank_event(dev, -1, e); 399 drm_vblank_put(dev, crtc); 400 atomic_set(&exynos_crtc->pending_flip, 0); 401 wake_up(&exynos_crtc->pending_flip_queue); 402 } 403 404 spin_unlock_irqrestore(&dev->event_lock, flags); 405 } 406