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 * Permission is hereby granted, free of charge, to any person obtaining a 10 * copy of this software and associated documentation files (the "Software"), 11 * to deal in the Software without restriction, including without limitation 12 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 13 * and/or sell copies of the Software, and to permit persons to whom the 14 * Software is furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice (including the next 17 * paragraph) shall be included in all copies or substantial portions of the 18 * Software. 19 * 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 23 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 * OTHER DEALINGS IN THE SOFTWARE. 27 */ 28 29 #include "drmP.h" 30 #include "drm_crtc_helper.h" 31 32 #include "exynos_drm_drv.h" 33 #include "exynos_drm_crtc.h" 34 #include "exynos_drm_fb.h" 35 #include "exynos_drm_encoder.h" 36 #include "exynos_drm_gem.h" 37 #include "exynos_drm_plane.h" 38 39 #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\ 40 drm_crtc) 41 42 /* 43 * Exynos specific crtc structure. 44 * 45 * @drm_crtc: crtc object. 46 * @drm_plane: pointer of private plane object for this crtc 47 * @pipe: a crtc index created at load() with a new crtc object creation 48 * and the crtc object would be set to private->crtc array 49 * to get a crtc object corresponding to this pipe from private->crtc 50 * array when irq interrupt occured. the reason of using this pipe is that 51 * drm framework doesn't support multiple irq yet. 52 * we can refer to the crtc to current hardware interrupt occured through 53 * this pipe value. 54 * @dpms: store the crtc dpms value 55 */ 56 struct exynos_drm_crtc { 57 struct drm_crtc drm_crtc; 58 struct drm_plane *plane; 59 unsigned int pipe; 60 unsigned int dpms; 61 }; 62 63 static void exynos_drm_crtc_apply(struct drm_crtc *crtc) 64 { 65 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 66 struct exynos_drm_overlay *overlay = 67 get_exynos_drm_overlay(exynos_crtc->plane); 68 69 exynos_drm_fn_encoder(crtc, overlay, 70 exynos_drm_encoder_crtc_mode_set); 71 exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit); 72 } 73 74 int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay, 75 struct drm_framebuffer *fb, 76 struct drm_display_mode *mode, 77 struct exynos_drm_crtc_pos *pos) 78 { 79 struct exynos_drm_gem_buf *buffer; 80 unsigned int actual_w; 81 unsigned int actual_h; 82 int nr = exynos_drm_format_num_buffers(fb->pixel_format); 83 int i; 84 85 for (i = 0; i < nr; i++) { 86 buffer = exynos_drm_fb_buffer(fb, i); 87 if (!buffer) { 88 DRM_LOG_KMS("buffer is null\n"); 89 return -EFAULT; 90 } 91 92 overlay->dma_addr[i] = buffer->dma_addr; 93 overlay->vaddr[i] = buffer->kvaddr; 94 95 DRM_DEBUG_KMS("buffer: %d, vaddr = 0x%lx, dma_addr = 0x%lx\n", 96 i, (unsigned long)overlay->vaddr[i], 97 (unsigned long)overlay->dma_addr[i]); 98 } 99 100 actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w); 101 actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h); 102 103 /* set drm framebuffer data. */ 104 overlay->fb_x = pos->fb_x; 105 overlay->fb_y = pos->fb_y; 106 overlay->fb_width = fb->width; 107 overlay->fb_height = fb->height; 108 overlay->src_width = pos->src_w; 109 overlay->src_height = pos->src_h; 110 overlay->bpp = fb->bits_per_pixel; 111 overlay->pitch = fb->pitches[0]; 112 overlay->pixel_format = fb->pixel_format; 113 114 /* set overlay range to be displayed. */ 115 overlay->crtc_x = pos->crtc_x; 116 overlay->crtc_y = pos->crtc_y; 117 overlay->crtc_width = actual_w; 118 overlay->crtc_height = actual_h; 119 120 /* set drm mode data. */ 121 overlay->mode_width = mode->hdisplay; 122 overlay->mode_height = mode->vdisplay; 123 overlay->refresh = mode->vrefresh; 124 overlay->scan_flag = mode->flags; 125 126 DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)", 127 overlay->crtc_x, overlay->crtc_y, 128 overlay->crtc_width, overlay->crtc_height); 129 130 return 0; 131 } 132 133 static int exynos_drm_crtc_update(struct drm_crtc *crtc) 134 { 135 struct exynos_drm_crtc *exynos_crtc; 136 struct exynos_drm_overlay *overlay; 137 struct exynos_drm_crtc_pos pos; 138 struct drm_display_mode *mode = &crtc->mode; 139 struct drm_framebuffer *fb = crtc->fb; 140 141 if (!mode || !fb) 142 return -EINVAL; 143 144 exynos_crtc = to_exynos_crtc(crtc); 145 overlay = get_exynos_drm_overlay(exynos_crtc->plane); 146 147 memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos)); 148 149 /* it means the offset of framebuffer to be displayed. */ 150 pos.fb_x = crtc->x; 151 pos.fb_y = crtc->y; 152 153 /* OSD position to be displayed. */ 154 pos.crtc_x = 0; 155 pos.crtc_y = 0; 156 pos.crtc_w = fb->width - crtc->x; 157 pos.crtc_h = fb->height - crtc->y; 158 pos.src_w = pos.crtc_w; 159 pos.src_h = pos.crtc_h; 160 161 return exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos); 162 } 163 164 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 165 { 166 struct drm_device *dev = crtc->dev; 167 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 168 169 DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); 170 171 if (exynos_crtc->dpms == mode) { 172 DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); 173 return; 174 } 175 176 mutex_lock(&dev->struct_mutex); 177 178 switch (mode) { 179 case DRM_MODE_DPMS_ON: 180 exynos_drm_fn_encoder(crtc, &mode, 181 exynos_drm_encoder_crtc_dpms); 182 exynos_crtc->dpms = mode; 183 break; 184 case DRM_MODE_DPMS_STANDBY: 185 case DRM_MODE_DPMS_SUSPEND: 186 case DRM_MODE_DPMS_OFF: 187 exynos_drm_fn_encoder(crtc, &mode, 188 exynos_drm_encoder_crtc_dpms); 189 exynos_crtc->dpms = mode; 190 break; 191 default: 192 DRM_ERROR("unspecified mode %d\n", mode); 193 break; 194 } 195 196 mutex_unlock(&dev->struct_mutex); 197 } 198 199 static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) 200 { 201 DRM_DEBUG_KMS("%s\n", __FILE__); 202 203 /* drm framework doesn't check NULL. */ 204 } 205 206 static void exynos_drm_crtc_commit(struct drm_crtc *crtc) 207 { 208 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 209 210 DRM_DEBUG_KMS("%s\n", __FILE__); 211 212 /* 213 * when set_crtc is requested from user or at booting time, 214 * crtc->commit would be called without dpms call so if dpms is 215 * no power on then crtc->dpms should be called 216 * with DRM_MODE_DPMS_ON for the hardware power to be on. 217 */ 218 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) { 219 int mode = DRM_MODE_DPMS_ON; 220 221 /* 222 * enable hardware(power on) to all encoders hdmi connected 223 * to current crtc. 224 */ 225 exynos_drm_crtc_dpms(crtc, mode); 226 /* 227 * enable dma to all encoders connected to current crtc and 228 * lcd panel. 229 */ 230 exynos_drm_fn_encoder(crtc, &mode, 231 exynos_drm_encoder_dpms_from_crtc); 232 } 233 234 exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit); 235 } 236 237 static bool 238 exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, 239 const struct drm_display_mode *mode, 240 struct drm_display_mode *adjusted_mode) 241 { 242 DRM_DEBUG_KMS("%s\n", __FILE__); 243 244 /* drm framework doesn't check NULL */ 245 return true; 246 } 247 248 static int 249 exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, 250 struct drm_display_mode *adjusted_mode, int x, int y, 251 struct drm_framebuffer *old_fb) 252 { 253 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 254 struct exynos_drm_overlay *overlay = 255 get_exynos_drm_overlay(exynos_crtc->plane); 256 int pipe = exynos_crtc->pipe; 257 int ret; 258 259 DRM_DEBUG_KMS("%s\n", __FILE__); 260 261 /* 262 * copy the mode data adjusted by mode_fixup() into crtc->mode 263 * so that hardware can be seet to proper mode. 264 */ 265 memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); 266 267 ret = exynos_drm_crtc_update(crtc); 268 if (ret) 269 return ret; 270 271 exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_crtc_mode_set); 272 exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe); 273 274 return 0; 275 } 276 277 static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 278 struct drm_framebuffer *old_fb) 279 { 280 int ret; 281 282 DRM_DEBUG_KMS("%s\n", __FILE__); 283 284 ret = exynos_drm_crtc_update(crtc); 285 if (ret) 286 return ret; 287 288 exynos_drm_crtc_apply(crtc); 289 290 return ret; 291 } 292 293 static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc) 294 { 295 DRM_DEBUG_KMS("%s\n", __FILE__); 296 /* drm framework doesn't check NULL */ 297 } 298 299 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 300 .dpms = exynos_drm_crtc_dpms, 301 .prepare = exynos_drm_crtc_prepare, 302 .commit = exynos_drm_crtc_commit, 303 .mode_fixup = exynos_drm_crtc_mode_fixup, 304 .mode_set = exynos_drm_crtc_mode_set, 305 .mode_set_base = exynos_drm_crtc_mode_set_base, 306 .load_lut = exynos_drm_crtc_load_lut, 307 }; 308 309 static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, 310 struct drm_framebuffer *fb, 311 struct drm_pending_vblank_event *event) 312 { 313 struct drm_device *dev = crtc->dev; 314 struct exynos_drm_private *dev_priv = dev->dev_private; 315 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 316 struct drm_framebuffer *old_fb = crtc->fb; 317 int ret = -EINVAL; 318 319 DRM_DEBUG_KMS("%s\n", __FILE__); 320 321 mutex_lock(&dev->struct_mutex); 322 323 if (event) { 324 /* 325 * the pipe from user always is 0 so we can set pipe number 326 * of current owner to event. 327 */ 328 event->pipe = exynos_crtc->pipe; 329 330 ret = drm_vblank_get(dev, exynos_crtc->pipe); 331 if (ret) { 332 DRM_DEBUG("failed to acquire vblank counter\n"); 333 list_del(&event->base.link); 334 335 goto out; 336 } 337 338 list_add_tail(&event->base.link, 339 &dev_priv->pageflip_event_list); 340 341 crtc->fb = fb; 342 ret = exynos_drm_crtc_update(crtc); 343 if (ret) { 344 crtc->fb = old_fb; 345 drm_vblank_put(dev, exynos_crtc->pipe); 346 list_del(&event->base.link); 347 348 goto out; 349 } 350 351 /* 352 * the values related to a buffer of the drm framebuffer 353 * to be applied should be set at here. because these values 354 * first, are set to shadow registers and then to 355 * real registers at vsync front porch period. 356 */ 357 exynos_drm_crtc_apply(crtc); 358 } 359 out: 360 mutex_unlock(&dev->struct_mutex); 361 return ret; 362 } 363 364 static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) 365 { 366 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 367 struct exynos_drm_private *private = crtc->dev->dev_private; 368 369 DRM_DEBUG_KMS("%s\n", __FILE__); 370 371 private->crtc[exynos_crtc->pipe] = NULL; 372 373 drm_crtc_cleanup(crtc); 374 kfree(exynos_crtc); 375 } 376 377 static struct drm_crtc_funcs exynos_crtc_funcs = { 378 .set_config = drm_crtc_helper_set_config, 379 .page_flip = exynos_drm_crtc_page_flip, 380 .destroy = exynos_drm_crtc_destroy, 381 }; 382 383 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) 384 { 385 struct exynos_drm_crtc *exynos_crtc; 386 struct exynos_drm_private *private = dev->dev_private; 387 struct drm_crtc *crtc; 388 389 DRM_DEBUG_KMS("%s\n", __FILE__); 390 391 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); 392 if (!exynos_crtc) { 393 DRM_ERROR("failed to allocate exynos crtc\n"); 394 return -ENOMEM; 395 } 396 397 exynos_crtc->pipe = nr; 398 exynos_crtc->dpms = DRM_MODE_DPMS_OFF; 399 exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true); 400 if (!exynos_crtc->plane) { 401 kfree(exynos_crtc); 402 return -ENOMEM; 403 } 404 405 crtc = &exynos_crtc->drm_crtc; 406 407 private->crtc[nr] = crtc; 408 409 drm_crtc_init(dev, crtc, &exynos_crtc_funcs); 410 drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); 411 412 return 0; 413 } 414 415 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) 416 { 417 struct exynos_drm_private *private = dev->dev_private; 418 struct exynos_drm_crtc *exynos_crtc = 419 to_exynos_crtc(private->crtc[crtc]); 420 421 DRM_DEBUG_KMS("%s\n", __FILE__); 422 423 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) 424 return -EPERM; 425 426 exynos_drm_fn_encoder(private->crtc[crtc], &crtc, 427 exynos_drm_enable_vblank); 428 429 return 0; 430 } 431 432 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) 433 { 434 struct exynos_drm_private *private = dev->dev_private; 435 struct exynos_drm_crtc *exynos_crtc = 436 to_exynos_crtc(private->crtc[crtc]); 437 438 DRM_DEBUG_KMS("%s\n", __FILE__); 439 440 if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) 441 return; 442 443 exynos_drm_fn_encoder(private->crtc[crtc], &crtc, 444 exynos_drm_disable_vblank); 445 } 446