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 * @manager: the manager associated with this crtc 37 * @pipe: a crtc index created at load() with a new crtc object creation 38 * and the crtc object would be set to private->crtc array 39 * to get a crtc object corresponding to this pipe from private->crtc 40 * array when irq interrupt occurred. the reason of using this pipe is that 41 * drm framework doesn't support multiple irq yet. 42 * we can refer to the crtc to current hardware interrupt occurred through 43 * this pipe value. 44 * @dpms: store the crtc dpms value 45 * @mode: store the crtc mode value 46 */ 47 struct exynos_drm_crtc { 48 struct drm_crtc drm_crtc; 49 struct drm_plane *plane; 50 struct exynos_drm_manager *manager; 51 unsigned int pipe; 52 unsigned int dpms; 53 enum exynos_crtc_mode mode; 54 wait_queue_head_t pending_flip_queue; 55 atomic_t pending_flip; 56 }; 57 58 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 59 { 60 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 61 struct exynos_drm_manager *manager = exynos_crtc->manager; 62 63 DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); 64 65 if (exynos_crtc->dpms == mode) { 66 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); 67 return; 68 } 69 70 if (mode > DRM_MODE_DPMS_ON) { 71 /* wait for the completion of page flip. */ 72 if (!wait_event_timeout(exynos_crtc->pending_flip_queue, 73 !atomic_read(&exynos_crtc->pending_flip), 74 HZ/20)) 75 atomic_set(&exynos_crtc->pending_flip, 0); 76 drm_vblank_off(crtc->dev, exynos_crtc->pipe); 77 } 78 79 if (manager->ops->dpms) 80 manager->ops->dpms(manager, mode); 81 82 exynos_crtc->dpms = mode; 83 } 84 85 static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) 86 { 87 /* drm framework doesn't check NULL. */ 88 } 89 90 static void exynos_drm_crtc_commit(struct drm_crtc *crtc) 91 { 92 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 93 struct exynos_drm_manager *manager = exynos_crtc->manager; 94 95 exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 96 97 exynos_plane_commit(exynos_crtc->plane); 98 99 if (manager->ops->commit) 100 manager->ops->commit(manager); 101 102 exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); 103 } 104 105 static bool 106 exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, 107 const struct drm_display_mode *mode, 108 struct drm_display_mode *adjusted_mode) 109 { 110 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 111 struct exynos_drm_manager *manager = exynos_crtc->manager; 112 113 if (manager->ops->mode_fixup) 114 return manager->ops->mode_fixup(manager, mode, adjusted_mode); 115 116 return true; 117 } 118 119 static int 120 exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, 121 struct drm_display_mode *adjusted_mode, int x, int y, 122 struct drm_framebuffer *old_fb) 123 { 124 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 125 struct exynos_drm_manager *manager = exynos_crtc->manager; 126 struct drm_plane *plane = exynos_crtc->plane; 127 unsigned int crtc_w; 128 unsigned int crtc_h; 129 int ret; 130 131 /* 132 * copy the mode data adjusted by mode_fixup() into crtc->mode 133 * so that hardware can be seet to proper mode. 134 */ 135 memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); 136 137 crtc_w = crtc->primary->fb->width - x; 138 crtc_h = crtc->primary->fb->height - y; 139 140 if (manager->ops->mode_set) 141 manager->ops->mode_set(manager, &crtc->mode); 142 143 ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h, 144 x, y, crtc_w, crtc_h); 145 if (ret) 146 return ret; 147 148 plane->crtc = crtc; 149 plane->fb = crtc->primary->fb; 150 drm_framebuffer_reference(plane->fb); 151 152 return 0; 153 } 154 155 static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y, 156 struct drm_framebuffer *old_fb) 157 { 158 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 159 struct drm_plane *plane = exynos_crtc->plane; 160 unsigned int crtc_w; 161 unsigned int crtc_h; 162 int ret; 163 164 /* when framebuffer changing is requested, crtc's dpms should be on */ 165 if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { 166 DRM_ERROR("failed framebuffer changing request.\n"); 167 return -EPERM; 168 } 169 170 crtc_w = crtc->primary->fb->width - x; 171 crtc_h = crtc->primary->fb->height - y; 172 173 ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h, 174 x, y, crtc_w, crtc_h); 175 if (ret) 176 return ret; 177 178 exynos_drm_crtc_commit(crtc); 179 180 return 0; 181 } 182 183 static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 184 struct drm_framebuffer *old_fb) 185 { 186 return exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb); 187 } 188 189 static void exynos_drm_crtc_disable(struct drm_crtc *crtc) 190 { 191 struct drm_plane *plane; 192 int ret; 193 194 exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 195 196 drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { 197 if (plane->crtc != crtc) 198 continue; 199 200 ret = plane->funcs->disable_plane(plane); 201 if (ret) 202 DRM_ERROR("Failed to disable plane %d\n", ret); 203 } 204 } 205 206 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 207 .dpms = exynos_drm_crtc_dpms, 208 .prepare = exynos_drm_crtc_prepare, 209 .commit = exynos_drm_crtc_commit, 210 .mode_fixup = exynos_drm_crtc_mode_fixup, 211 .mode_set = exynos_drm_crtc_mode_set, 212 .mode_set_base = exynos_drm_crtc_mode_set_base, 213 .disable = exynos_drm_crtc_disable, 214 }; 215 216 static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, 217 struct drm_framebuffer *fb, 218 struct drm_pending_vblank_event *event, 219 uint32_t page_flip_flags) 220 { 221 struct drm_device *dev = crtc->dev; 222 struct exynos_drm_private *dev_priv = dev->dev_private; 223 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 224 struct drm_framebuffer *old_fb = crtc->primary->fb; 225 int ret = -EINVAL; 226 227 /* when the page flip is requested, crtc's dpms should be on */ 228 if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { 229 DRM_ERROR("failed page flip request.\n"); 230 return -EINVAL; 231 } 232 233 mutex_lock(&dev->struct_mutex); 234 235 if (event) { 236 /* 237 * the pipe from user always is 0 so we can set pipe number 238 * of current owner to event. 239 */ 240 event->pipe = exynos_crtc->pipe; 241 242 ret = drm_vblank_get(dev, exynos_crtc->pipe); 243 if (ret) { 244 DRM_DEBUG("failed to acquire vblank counter\n"); 245 246 goto out; 247 } 248 249 spin_lock_irq(&dev->event_lock); 250 list_add_tail(&event->base.link, 251 &dev_priv->pageflip_event_list); 252 atomic_set(&exynos_crtc->pending_flip, 1); 253 spin_unlock_irq(&dev->event_lock); 254 255 crtc->primary->fb = fb; 256 ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y, 257 NULL); 258 if (ret) { 259 crtc->primary->fb = old_fb; 260 261 spin_lock_irq(&dev->event_lock); 262 drm_vblank_put(dev, exynos_crtc->pipe); 263 list_del(&event->base.link); 264 atomic_set(&exynos_crtc->pending_flip, 0); 265 spin_unlock_irq(&dev->event_lock); 266 267 goto out; 268 } 269 } 270 out: 271 mutex_unlock(&dev->struct_mutex); 272 return ret; 273 } 274 275 static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) 276 { 277 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 278 struct exynos_drm_private *private = crtc->dev->dev_private; 279 280 private->crtc[exynos_crtc->pipe] = NULL; 281 282 drm_crtc_cleanup(crtc); 283 kfree(exynos_crtc); 284 } 285 286 static int exynos_drm_crtc_set_property(struct drm_crtc *crtc, 287 struct drm_property *property, 288 uint64_t val) 289 { 290 struct drm_device *dev = crtc->dev; 291 struct exynos_drm_private *dev_priv = dev->dev_private; 292 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 293 294 if (property == dev_priv->crtc_mode_property) { 295 enum exynos_crtc_mode mode = val; 296 297 if (mode == exynos_crtc->mode) 298 return 0; 299 300 exynos_crtc->mode = mode; 301 302 switch (mode) { 303 case CRTC_MODE_NORMAL: 304 exynos_drm_crtc_commit(crtc); 305 break; 306 case CRTC_MODE_BLANK: 307 exynos_plane_dpms(exynos_crtc->plane, 308 DRM_MODE_DPMS_OFF); 309 break; 310 default: 311 break; 312 } 313 314 return 0; 315 } 316 317 return -EINVAL; 318 } 319 320 static struct drm_crtc_funcs exynos_crtc_funcs = { 321 .set_config = drm_crtc_helper_set_config, 322 .page_flip = exynos_drm_crtc_page_flip, 323 .destroy = exynos_drm_crtc_destroy, 324 .set_property = exynos_drm_crtc_set_property, 325 }; 326 327 static const struct drm_prop_enum_list mode_names[] = { 328 { CRTC_MODE_NORMAL, "normal" }, 329 { CRTC_MODE_BLANK, "blank" }, 330 }; 331 332 static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc) 333 { 334 struct drm_device *dev = crtc->dev; 335 struct exynos_drm_private *dev_priv = dev->dev_private; 336 struct drm_property *prop; 337 338 prop = dev_priv->crtc_mode_property; 339 if (!prop) { 340 prop = drm_property_create_enum(dev, 0, "mode", mode_names, 341 ARRAY_SIZE(mode_names)); 342 if (!prop) 343 return; 344 345 dev_priv->crtc_mode_property = prop; 346 } 347 348 drm_object_attach_property(&crtc->base, prop, 0); 349 } 350 351 int exynos_drm_crtc_create(struct exynos_drm_manager *manager) 352 { 353 struct exynos_drm_crtc *exynos_crtc; 354 struct exynos_drm_private *private = manager->drm_dev->dev_private; 355 struct drm_crtc *crtc; 356 357 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); 358 if (!exynos_crtc) 359 return -ENOMEM; 360 361 init_waitqueue_head(&exynos_crtc->pending_flip_queue); 362 atomic_set(&exynos_crtc->pending_flip, 0); 363 364 exynos_crtc->dpms = DRM_MODE_DPMS_OFF; 365 exynos_crtc->manager = manager; 366 exynos_crtc->pipe = manager->pipe; 367 exynos_crtc->plane = exynos_plane_init(manager->drm_dev, 368 1 << manager->pipe, true); 369 if (!exynos_crtc->plane) { 370 kfree(exynos_crtc); 371 return -ENOMEM; 372 } 373 374 manager->crtc = &exynos_crtc->drm_crtc; 375 crtc = &exynos_crtc->drm_crtc; 376 377 private->crtc[manager->pipe] = crtc; 378 379 drm_crtc_init(manager->drm_dev, crtc, &exynos_crtc_funcs); 380 drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); 381 382 exynos_drm_crtc_attach_mode_property(crtc); 383 384 return 0; 385 } 386 387 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) 388 { 389 struct exynos_drm_private *private = dev->dev_private; 390 struct exynos_drm_crtc *exynos_crtc = 391 to_exynos_crtc(private->crtc[pipe]); 392 struct exynos_drm_manager *manager = exynos_crtc->manager; 393 394 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) 395 return -EPERM; 396 397 if (manager->ops->enable_vblank) 398 manager->ops->enable_vblank(manager); 399 400 return 0; 401 } 402 403 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) 404 { 405 struct exynos_drm_private *private = dev->dev_private; 406 struct exynos_drm_crtc *exynos_crtc = 407 to_exynos_crtc(private->crtc[pipe]); 408 struct exynos_drm_manager *manager = exynos_crtc->manager; 409 410 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) 411 return; 412 413 if (manager->ops->disable_vblank) 414 manager->ops->disable_vblank(manager); 415 } 416 417 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) 418 { 419 struct exynos_drm_private *dev_priv = dev->dev_private; 420 struct drm_pending_vblank_event *e, *t; 421 struct drm_crtc *drm_crtc = dev_priv->crtc[pipe]; 422 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); 423 unsigned long flags; 424 425 spin_lock_irqsave(&dev->event_lock, flags); 426 427 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, 428 base.link) { 429 /* if event's pipe isn't same as crtc then ignore it. */ 430 if (pipe != e->pipe) 431 continue; 432 433 list_del(&e->base.link); 434 drm_send_vblank_event(dev, -1, e); 435 drm_vblank_put(dev, pipe); 436 atomic_set(&exynos_crtc->pending_flip, 0); 437 wake_up(&exynos_crtc->pending_flip_queue); 438 } 439 440 spin_unlock_irqrestore(&dev->event_lock, flags); 441 } 442 443 void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc, 444 struct exynos_drm_overlay *overlay) 445 { 446 struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; 447 448 if (manager->ops->win_mode_set) 449 manager->ops->win_mode_set(manager, overlay); 450 } 451 452 void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos) 453 { 454 struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; 455 456 if (manager->ops->win_commit) 457 manager->ops->win_commit(manager, zpos); 458 } 459 460 void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos) 461 { 462 struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; 463 464 if (manager->ops->win_enable) 465 manager->ops->win_enable(manager, zpos); 466 } 467 468 void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos) 469 { 470 struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; 471 472 if (manager->ops->win_disable) 473 manager->ops->win_disable(manager, zpos); 474 } 475 476 void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) 477 { 478 struct exynos_drm_manager *manager; 479 struct drm_device *dev = fb->dev; 480 struct drm_crtc *crtc; 481 482 /* 483 * make sure that overlay data are updated to real hardware 484 * for all encoders. 485 */ 486 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 487 manager = to_exynos_crtc(crtc)->manager; 488 489 /* 490 * wait for vblank interrupt 491 * - this makes sure that overlay data are updated to 492 * real hardware. 493 */ 494 if (manager->ops->wait_for_vblank) 495 manager->ops->wait_for_vblank(manager); 496 } 497 } 498 499 int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev, 500 unsigned int out_type) 501 { 502 struct drm_crtc *crtc; 503 504 list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) { 505 struct exynos_drm_crtc *exynos_crtc; 506 507 exynos_crtc = to_exynos_crtc(crtc); 508 if (exynos_crtc->manager->type == out_type) 509 return exynos_crtc->manager->pipe; 510 } 511 512 return -EPERM; 513 } 514 515 void exynos_drm_crtc_te_handler(struct drm_crtc *crtc) 516 { 517 struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; 518 519 if (manager->ops->te_handler) 520 manager->ops->te_handler(manager); 521 } 522