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_drv.h" 19 #include "exynos_drm_encoder.h" 20 #include "exynos_drm_plane.h" 21 22 #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\ 23 drm_crtc) 24 25 enum exynos_crtc_mode { 26 CRTC_MODE_NORMAL, /* normal mode */ 27 CRTC_MODE_BLANK, /* The private plane of crtc is blank */ 28 }; 29 30 /* 31 * Exynos specific crtc structure. 32 * 33 * @drm_crtc: crtc object. 34 * @drm_plane: pointer of private plane object for this crtc 35 * @pipe: a crtc index created at load() with a new crtc object creation 36 * and the crtc object would be set to private->crtc array 37 * to get a crtc object corresponding to this pipe from private->crtc 38 * array when irq interrupt occured. the reason of using this pipe is that 39 * drm framework doesn't support multiple irq yet. 40 * we can refer to the crtc to current hardware interrupt occured through 41 * this pipe value. 42 * @dpms: store the crtc dpms value 43 * @mode: store the crtc mode value 44 */ 45 struct exynos_drm_crtc { 46 struct drm_crtc drm_crtc; 47 struct drm_plane *plane; 48 unsigned int pipe; 49 unsigned int dpms; 50 enum exynos_crtc_mode mode; 51 wait_queue_head_t pending_flip_queue; 52 atomic_t pending_flip; 53 }; 54 55 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 56 { 57 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 58 59 DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); 60 61 if (exynos_crtc->dpms == mode) { 62 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); 63 return; 64 } 65 66 if (mode > DRM_MODE_DPMS_ON) { 67 /* wait for the completion of page flip. */ 68 wait_event(exynos_crtc->pending_flip_queue, 69 atomic_read(&exynos_crtc->pending_flip) == 0); 70 drm_vblank_off(crtc->dev, exynos_crtc->pipe); 71 } 72 73 exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); 74 exynos_crtc->dpms = mode; 75 } 76 77 static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) 78 { 79 /* drm framework doesn't check NULL. */ 80 } 81 82 static void exynos_drm_crtc_commit(struct drm_crtc *crtc) 83 { 84 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 85 86 exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 87 exynos_plane_commit(exynos_crtc->plane); 88 exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); 89 } 90 91 static bool 92 exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, 93 const struct drm_display_mode *mode, 94 struct drm_display_mode *adjusted_mode) 95 { 96 /* drm framework doesn't check NULL */ 97 return true; 98 } 99 100 static int 101 exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, 102 struct drm_display_mode *adjusted_mode, int x, int y, 103 struct drm_framebuffer *old_fb) 104 { 105 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 106 struct drm_plane *plane = exynos_crtc->plane; 107 unsigned int crtc_w; 108 unsigned int crtc_h; 109 int pipe = exynos_crtc->pipe; 110 int ret; 111 112 /* 113 * copy the mode data adjusted by mode_fixup() into crtc->mode 114 * so that hardware can be seet to proper mode. 115 */ 116 memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); 117 118 crtc_w = crtc->fb->width - x; 119 crtc_h = crtc->fb->height - y; 120 121 ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h, 122 x, y, crtc_w, crtc_h); 123 if (ret) 124 return ret; 125 126 plane->crtc = crtc; 127 plane->fb = crtc->fb; 128 129 exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe); 130 131 return 0; 132 } 133 134 static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y, 135 struct drm_framebuffer *old_fb) 136 { 137 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 138 struct drm_plane *plane = exynos_crtc->plane; 139 unsigned int crtc_w; 140 unsigned int crtc_h; 141 int ret; 142 143 /* when framebuffer changing is requested, crtc's dpms should be on */ 144 if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { 145 DRM_ERROR("failed framebuffer changing request.\n"); 146 return -EPERM; 147 } 148 149 crtc_w = crtc->fb->width - x; 150 crtc_h = crtc->fb->height - y; 151 152 ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h, 153 x, y, crtc_w, crtc_h); 154 if (ret) 155 return ret; 156 157 exynos_drm_crtc_commit(crtc); 158 159 return 0; 160 } 161 162 static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 163 struct drm_framebuffer *old_fb) 164 { 165 return exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb); 166 } 167 168 static void exynos_drm_crtc_disable(struct drm_crtc *crtc) 169 { 170 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 171 172 exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF); 173 exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 174 } 175 176 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 177 .dpms = exynos_drm_crtc_dpms, 178 .prepare = exynos_drm_crtc_prepare, 179 .commit = exynos_drm_crtc_commit, 180 .mode_fixup = exynos_drm_crtc_mode_fixup, 181 .mode_set = exynos_drm_crtc_mode_set, 182 .mode_set_base = exynos_drm_crtc_mode_set_base, 183 .disable = exynos_drm_crtc_disable, 184 }; 185 186 static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, 187 struct drm_framebuffer *fb, 188 struct drm_pending_vblank_event *event) 189 { 190 struct drm_device *dev = crtc->dev; 191 struct exynos_drm_private *dev_priv = dev->dev_private; 192 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 193 struct drm_framebuffer *old_fb = crtc->fb; 194 int ret = -EINVAL; 195 196 /* when the page flip is requested, crtc's dpms should be on */ 197 if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { 198 DRM_ERROR("failed page flip request.\n"); 199 return -EINVAL; 200 } 201 202 mutex_lock(&dev->struct_mutex); 203 204 if (event) { 205 /* 206 * the pipe from user always is 0 so we can set pipe number 207 * of current owner to event. 208 */ 209 event->pipe = exynos_crtc->pipe; 210 211 ret = drm_vblank_get(dev, exynos_crtc->pipe); 212 if (ret) { 213 DRM_DEBUG("failed to acquire vblank counter\n"); 214 215 goto out; 216 } 217 218 spin_lock_irq(&dev->event_lock); 219 list_add_tail(&event->base.link, 220 &dev_priv->pageflip_event_list); 221 atomic_set(&exynos_crtc->pending_flip, 1); 222 spin_unlock_irq(&dev->event_lock); 223 224 crtc->fb = fb; 225 ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y, 226 NULL); 227 if (ret) { 228 crtc->fb = old_fb; 229 230 spin_lock_irq(&dev->event_lock); 231 drm_vblank_put(dev, exynos_crtc->pipe); 232 list_del(&event->base.link); 233 spin_unlock_irq(&dev->event_lock); 234 235 goto out; 236 } 237 } 238 out: 239 mutex_unlock(&dev->struct_mutex); 240 return ret; 241 } 242 243 static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) 244 { 245 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 246 struct exynos_drm_private *private = crtc->dev->dev_private; 247 248 private->crtc[exynos_crtc->pipe] = NULL; 249 250 drm_crtc_cleanup(crtc); 251 kfree(exynos_crtc); 252 } 253 254 static int exynos_drm_crtc_set_property(struct drm_crtc *crtc, 255 struct drm_property *property, 256 uint64_t val) 257 { 258 struct drm_device *dev = crtc->dev; 259 struct exynos_drm_private *dev_priv = dev->dev_private; 260 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 261 262 if (property == dev_priv->crtc_mode_property) { 263 enum exynos_crtc_mode mode = val; 264 265 if (mode == exynos_crtc->mode) 266 return 0; 267 268 exynos_crtc->mode = mode; 269 270 switch (mode) { 271 case CRTC_MODE_NORMAL: 272 exynos_drm_crtc_commit(crtc); 273 break; 274 case CRTC_MODE_BLANK: 275 exynos_plane_dpms(exynos_crtc->plane, 276 DRM_MODE_DPMS_OFF); 277 break; 278 default: 279 break; 280 } 281 282 return 0; 283 } 284 285 return -EINVAL; 286 } 287 288 static struct drm_crtc_funcs exynos_crtc_funcs = { 289 .set_config = drm_crtc_helper_set_config, 290 .page_flip = exynos_drm_crtc_page_flip, 291 .destroy = exynos_drm_crtc_destroy, 292 .set_property = exynos_drm_crtc_set_property, 293 }; 294 295 static const struct drm_prop_enum_list mode_names[] = { 296 { CRTC_MODE_NORMAL, "normal" }, 297 { CRTC_MODE_BLANK, "blank" }, 298 }; 299 300 static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc) 301 { 302 struct drm_device *dev = crtc->dev; 303 struct exynos_drm_private *dev_priv = dev->dev_private; 304 struct drm_property *prop; 305 306 prop = dev_priv->crtc_mode_property; 307 if (!prop) { 308 prop = drm_property_create_enum(dev, 0, "mode", mode_names, 309 ARRAY_SIZE(mode_names)); 310 if (!prop) 311 return; 312 313 dev_priv->crtc_mode_property = prop; 314 } 315 316 drm_object_attach_property(&crtc->base, prop, 0); 317 } 318 319 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) 320 { 321 struct exynos_drm_crtc *exynos_crtc; 322 struct exynos_drm_private *private = dev->dev_private; 323 struct drm_crtc *crtc; 324 325 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); 326 if (!exynos_crtc) { 327 DRM_ERROR("failed to allocate exynos crtc\n"); 328 return -ENOMEM; 329 } 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