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 }; 52 53 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 54 { 55 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 56 57 DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); 58 59 if (exynos_crtc->dpms == mode) { 60 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); 61 return; 62 } 63 64 exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); 65 exynos_crtc->dpms = mode; 66 } 67 68 static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) 69 { 70 DRM_DEBUG_KMS("%s\n", __FILE__); 71 72 /* drm framework doesn't check NULL. */ 73 } 74 75 static void exynos_drm_crtc_commit(struct drm_crtc *crtc) 76 { 77 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 78 79 DRM_DEBUG_KMS("%s\n", __FILE__); 80 81 exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 82 exynos_plane_commit(exynos_crtc->plane); 83 exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); 84 } 85 86 static bool 87 exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, 88 const struct drm_display_mode *mode, 89 struct drm_display_mode *adjusted_mode) 90 { 91 DRM_DEBUG_KMS("%s\n", __FILE__); 92 93 /* drm framework doesn't check NULL */ 94 return true; 95 } 96 97 static int 98 exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, 99 struct drm_display_mode *adjusted_mode, int x, int y, 100 struct drm_framebuffer *old_fb) 101 { 102 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 103 struct drm_plane *plane = exynos_crtc->plane; 104 unsigned int crtc_w; 105 unsigned int crtc_h; 106 int pipe = exynos_crtc->pipe; 107 int ret; 108 109 DRM_DEBUG_KMS("%s\n", __FILE__); 110 111 /* 112 * copy the mode data adjusted by mode_fixup() into crtc->mode 113 * so that hardware can be seet to proper mode. 114 */ 115 memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); 116 117 crtc_w = crtc->fb->width - x; 118 crtc_h = crtc->fb->height - y; 119 120 ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h, 121 x, y, crtc_w, crtc_h); 122 if (ret) 123 return ret; 124 125 plane->crtc = crtc; 126 plane->fb = crtc->fb; 127 128 exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe); 129 130 return 0; 131 } 132 133 static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 134 struct drm_framebuffer *old_fb) 135 { 136 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 137 struct drm_plane *plane = exynos_crtc->plane; 138 unsigned int crtc_w; 139 unsigned int crtc_h; 140 int ret; 141 142 DRM_DEBUG_KMS("%s\n", __FILE__); 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 void exynos_drm_crtc_load_lut(struct drm_crtc *crtc) 164 { 165 DRM_DEBUG_KMS("%s\n", __FILE__); 166 /* drm framework doesn't check NULL */ 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 DRM_DEBUG_KMS("%s\n", __FILE__); 174 175 exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF); 176 exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 177 } 178 179 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 180 .dpms = exynos_drm_crtc_dpms, 181 .prepare = exynos_drm_crtc_prepare, 182 .commit = exynos_drm_crtc_commit, 183 .mode_fixup = exynos_drm_crtc_mode_fixup, 184 .mode_set = exynos_drm_crtc_mode_set, 185 .mode_set_base = exynos_drm_crtc_mode_set_base, 186 .load_lut = exynos_drm_crtc_load_lut, 187 .disable = exynos_drm_crtc_disable, 188 }; 189 190 static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, 191 struct drm_framebuffer *fb, 192 struct drm_pending_vblank_event *event) 193 { 194 struct drm_device *dev = crtc->dev; 195 struct exynos_drm_private *dev_priv = dev->dev_private; 196 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 197 struct drm_framebuffer *old_fb = crtc->fb; 198 int ret = -EINVAL; 199 200 DRM_DEBUG_KMS("%s\n", __FILE__); 201 202 /* when the page flip is requested, crtc's dpms should be on */ 203 if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) { 204 DRM_ERROR("failed page flip request.\n"); 205 return -EINVAL; 206 } 207 208 mutex_lock(&dev->struct_mutex); 209 210 if (event) { 211 /* 212 * the pipe from user always is 0 so we can set pipe number 213 * of current owner to event. 214 */ 215 event->pipe = exynos_crtc->pipe; 216 217 ret = drm_vblank_get(dev, exynos_crtc->pipe); 218 if (ret) { 219 DRM_DEBUG("failed to acquire vblank counter\n"); 220 list_del(&event->base.link); 221 222 goto out; 223 } 224 225 spin_lock_irq(&dev->event_lock); 226 list_add_tail(&event->base.link, 227 &dev_priv->pageflip_event_list); 228 spin_unlock_irq(&dev->event_lock); 229 230 crtc->fb = fb; 231 ret = exynos_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, 232 NULL); 233 if (ret) { 234 crtc->fb = old_fb; 235 236 spin_lock_irq(&dev->event_lock); 237 drm_vblank_put(dev, exynos_crtc->pipe); 238 list_del(&event->base.link); 239 spin_unlock_irq(&dev->event_lock); 240 241 goto out; 242 } 243 } 244 out: 245 mutex_unlock(&dev->struct_mutex); 246 return ret; 247 } 248 249 static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) 250 { 251 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 252 struct exynos_drm_private *private = crtc->dev->dev_private; 253 254 DRM_DEBUG_KMS("%s\n", __FILE__); 255 256 private->crtc[exynos_crtc->pipe] = NULL; 257 258 drm_crtc_cleanup(crtc); 259 kfree(exynos_crtc); 260 } 261 262 static int exynos_drm_crtc_set_property(struct drm_crtc *crtc, 263 struct drm_property *property, 264 uint64_t val) 265 { 266 struct drm_device *dev = crtc->dev; 267 struct exynos_drm_private *dev_priv = dev->dev_private; 268 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 269 270 DRM_DEBUG_KMS("%s\n", __func__); 271 272 if (property == dev_priv->crtc_mode_property) { 273 enum exynos_crtc_mode mode = val; 274 275 if (mode == exynos_crtc->mode) 276 return 0; 277 278 exynos_crtc->mode = mode; 279 280 switch (mode) { 281 case CRTC_MODE_NORMAL: 282 exynos_drm_crtc_commit(crtc); 283 break; 284 case CRTC_MODE_BLANK: 285 exynos_plane_dpms(exynos_crtc->plane, 286 DRM_MODE_DPMS_OFF); 287 break; 288 default: 289 break; 290 } 291 292 return 0; 293 } 294 295 return -EINVAL; 296 } 297 298 static struct drm_crtc_funcs exynos_crtc_funcs = { 299 .set_config = drm_crtc_helper_set_config, 300 .page_flip = exynos_drm_crtc_page_flip, 301 .destroy = exynos_drm_crtc_destroy, 302 .set_property = exynos_drm_crtc_set_property, 303 }; 304 305 static const struct drm_prop_enum_list mode_names[] = { 306 { CRTC_MODE_NORMAL, "normal" }, 307 { CRTC_MODE_BLANK, "blank" }, 308 }; 309 310 static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc) 311 { 312 struct drm_device *dev = crtc->dev; 313 struct exynos_drm_private *dev_priv = dev->dev_private; 314 struct drm_property *prop; 315 316 DRM_DEBUG_KMS("%s\n", __func__); 317 318 prop = dev_priv->crtc_mode_property; 319 if (!prop) { 320 prop = drm_property_create_enum(dev, 0, "mode", mode_names, 321 ARRAY_SIZE(mode_names)); 322 if (!prop) 323 return; 324 325 dev_priv->crtc_mode_property = prop; 326 } 327 328 drm_object_attach_property(&crtc->base, prop, 0); 329 } 330 331 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) 332 { 333 struct exynos_drm_crtc *exynos_crtc; 334 struct exynos_drm_private *private = dev->dev_private; 335 struct drm_crtc *crtc; 336 337 DRM_DEBUG_KMS("%s\n", __FILE__); 338 339 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); 340 if (!exynos_crtc) { 341 DRM_ERROR("failed to allocate exynos crtc\n"); 342 return -ENOMEM; 343 } 344 345 exynos_crtc->pipe = nr; 346 exynos_crtc->dpms = DRM_MODE_DPMS_OFF; 347 exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true); 348 if (!exynos_crtc->plane) { 349 kfree(exynos_crtc); 350 return -ENOMEM; 351 } 352 353 crtc = &exynos_crtc->drm_crtc; 354 355 private->crtc[nr] = crtc; 356 357 drm_crtc_init(dev, crtc, &exynos_crtc_funcs); 358 drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); 359 360 exynos_drm_crtc_attach_mode_property(crtc); 361 362 return 0; 363 } 364 365 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) 366 { 367 struct exynos_drm_private *private = dev->dev_private; 368 struct exynos_drm_crtc *exynos_crtc = 369 to_exynos_crtc(private->crtc[crtc]); 370 371 DRM_DEBUG_KMS("%s\n", __FILE__); 372 373 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) 374 return -EPERM; 375 376 exynos_drm_fn_encoder(private->crtc[crtc], &crtc, 377 exynos_drm_enable_vblank); 378 379 return 0; 380 } 381 382 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) 383 { 384 struct exynos_drm_private *private = dev->dev_private; 385 struct exynos_drm_crtc *exynos_crtc = 386 to_exynos_crtc(private->crtc[crtc]); 387 388 DRM_DEBUG_KMS("%s\n", __FILE__); 389 390 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) 391 return; 392 393 exynos_drm_fn_encoder(private->crtc[crtc], &crtc, 394 exynos_drm_disable_vblank); 395 } 396 397 void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc) 398 { 399 struct exynos_drm_private *dev_priv = dev->dev_private; 400 struct drm_pending_vblank_event *e, *t; 401 struct timeval now; 402 unsigned long flags; 403 404 DRM_DEBUG_KMS("%s\n", __FILE__); 405 406 spin_lock_irqsave(&dev->event_lock, flags); 407 408 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, 409 base.link) { 410 /* if event's pipe isn't same as crtc then ignore it. */ 411 if (crtc != e->pipe) 412 continue; 413 414 do_gettimeofday(&now); 415 e->event.sequence = 0; 416 e->event.tv_sec = now.tv_sec; 417 e->event.tv_usec = now.tv_usec; 418 419 list_move_tail(&e->base.link, &e->base.file_priv->event_list); 420 wake_up_interruptible(&e->base.file_priv->event_wait); 421 drm_vblank_put(dev, crtc); 422 } 423 424 spin_unlock_irqrestore(&dev->event_lock, flags); 425 } 426