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