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_fb.h" 34 #include "exynos_drm_encoder.h" 35 #include "exynos_drm_buf.h" 36 37 #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\ 38 drm_crtc) 39 40 /* 41 * Exynos specific crtc postion structure. 42 * 43 * @fb_x: offset x on a framebuffer to be displyed 44 * - the unit is screen coordinates. 45 * @fb_y: offset y on a framebuffer to be displayed 46 * - the unit is screen coordinates. 47 * @crtc_x: offset x on hardware screen. 48 * @crtc_y: offset y on hardware screen. 49 * @crtc_w: width of hardware screen. 50 * @crtc_h: height of hardware screen. 51 */ 52 struct exynos_drm_crtc_pos { 53 unsigned int fb_x; 54 unsigned int fb_y; 55 unsigned int crtc_x; 56 unsigned int crtc_y; 57 unsigned int crtc_w; 58 unsigned int crtc_h; 59 }; 60 61 /* 62 * Exynos specific crtc structure. 63 * 64 * @drm_crtc: crtc object. 65 * @overlay: contain information common to display controller and hdmi and 66 * contents of this overlay object would be copied to sub driver size. 67 * @pipe: a crtc index created at load() with a new crtc object creation 68 * and the crtc object would be set to private->crtc array 69 * to get a crtc object corresponding to this pipe from private->crtc 70 * array when irq interrupt occured. the reason of using this pipe is that 71 * drm framework doesn't support multiple irq yet. 72 * we can refer to the crtc to current hardware interrupt occured through 73 * this pipe value. 74 */ 75 struct exynos_drm_crtc { 76 struct drm_crtc drm_crtc; 77 struct exynos_drm_overlay overlay; 78 unsigned int pipe; 79 }; 80 81 static void exynos_drm_crtc_apply(struct drm_crtc *crtc) 82 { 83 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 84 struct exynos_drm_overlay *overlay = &exynos_crtc->overlay; 85 86 exynos_drm_fn_encoder(crtc, overlay, 87 exynos_drm_encoder_crtc_mode_set); 88 exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit); 89 } 90 91 static int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay, 92 struct drm_framebuffer *fb, 93 struct drm_display_mode *mode, 94 struct exynos_drm_crtc_pos *pos) 95 { 96 struct exynos_drm_buf_entry *entry; 97 unsigned int actual_w; 98 unsigned int actual_h; 99 100 entry = exynos_drm_fb_get_buf(fb); 101 if (!entry) { 102 DRM_LOG_KMS("entry is null.\n"); 103 return -EFAULT; 104 } 105 106 overlay->paddr = entry->paddr; 107 overlay->vaddr = entry->vaddr; 108 109 DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n", 110 (unsigned long)overlay->vaddr, 111 (unsigned long)overlay->paddr); 112 113 actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w); 114 actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h); 115 116 /* set drm framebuffer data. */ 117 overlay->fb_x = pos->fb_x; 118 overlay->fb_y = pos->fb_y; 119 overlay->fb_width = fb->width; 120 overlay->fb_height = fb->height; 121 overlay->bpp = fb->bits_per_pixel; 122 overlay->pitch = fb->pitch; 123 124 /* set overlay range to be displayed. */ 125 overlay->crtc_x = pos->crtc_x; 126 overlay->crtc_y = pos->crtc_y; 127 overlay->crtc_width = actual_w; 128 overlay->crtc_height = actual_h; 129 130 /* set drm mode data. */ 131 overlay->mode_width = mode->hdisplay; 132 overlay->mode_height = mode->vdisplay; 133 overlay->refresh = mode->vrefresh; 134 overlay->scan_flag = mode->flags; 135 136 DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)", 137 overlay->crtc_x, overlay->crtc_y, 138 overlay->crtc_width, overlay->crtc_height); 139 140 return 0; 141 } 142 143 static int exynos_drm_crtc_update(struct drm_crtc *crtc) 144 { 145 struct exynos_drm_crtc *exynos_crtc; 146 struct exynos_drm_overlay *overlay; 147 struct exynos_drm_crtc_pos pos; 148 struct drm_display_mode *mode = &crtc->mode; 149 struct drm_framebuffer *fb = crtc->fb; 150 151 if (!mode || !fb) 152 return -EINVAL; 153 154 exynos_crtc = to_exynos_crtc(crtc); 155 overlay = &exynos_crtc->overlay; 156 157 memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos)); 158 159 /* it means the offset of framebuffer to be displayed. */ 160 pos.fb_x = crtc->x; 161 pos.fb_y = crtc->y; 162 163 /* OSD position to be displayed. */ 164 pos.crtc_x = 0; 165 pos.crtc_y = 0; 166 pos.crtc_w = fb->width - crtc->x; 167 pos.crtc_h = fb->height - crtc->y; 168 169 return exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos); 170 } 171 172 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) 173 { 174 DRM_DEBUG_KMS("%s\n", __FILE__); 175 176 /* TODO */ 177 } 178 179 static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) 180 { 181 DRM_DEBUG_KMS("%s\n", __FILE__); 182 183 /* drm framework doesn't check NULL. */ 184 } 185 186 static void exynos_drm_crtc_commit(struct drm_crtc *crtc) 187 { 188 DRM_DEBUG_KMS("%s\n", __FILE__); 189 190 /* drm framework doesn't check NULL. */ 191 } 192 193 static bool 194 exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, 195 struct drm_display_mode *mode, 196 struct drm_display_mode *adjusted_mode) 197 { 198 DRM_DEBUG_KMS("%s\n", __FILE__); 199 200 /* drm framework doesn't check NULL */ 201 return true; 202 } 203 204 static int 205 exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, 206 struct drm_display_mode *adjusted_mode, int x, int y, 207 struct drm_framebuffer *old_fb) 208 { 209 DRM_DEBUG_KMS("%s\n", __FILE__); 210 211 mode = adjusted_mode; 212 213 return exynos_drm_crtc_update(crtc); 214 } 215 216 static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 217 struct drm_framebuffer *old_fb) 218 { 219 int ret; 220 221 DRM_DEBUG_KMS("%s\n", __FILE__); 222 223 ret = exynos_drm_crtc_update(crtc); 224 if (ret) 225 return ret; 226 227 exynos_drm_crtc_apply(crtc); 228 229 return ret; 230 } 231 232 static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc) 233 { 234 DRM_DEBUG_KMS("%s\n", __FILE__); 235 /* drm framework doesn't check NULL */ 236 } 237 238 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { 239 .dpms = exynos_drm_crtc_dpms, 240 .prepare = exynos_drm_crtc_prepare, 241 .commit = exynos_drm_crtc_commit, 242 .mode_fixup = exynos_drm_crtc_mode_fixup, 243 .mode_set = exynos_drm_crtc_mode_set, 244 .mode_set_base = exynos_drm_crtc_mode_set_base, 245 .load_lut = exynos_drm_crtc_load_lut, 246 }; 247 248 static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, 249 struct drm_framebuffer *fb, 250 struct drm_pending_vblank_event *event) 251 { 252 struct drm_device *dev = crtc->dev; 253 struct exynos_drm_private *dev_priv = dev->dev_private; 254 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 255 struct drm_framebuffer *old_fb = crtc->fb; 256 int ret = -EINVAL; 257 258 DRM_DEBUG_KMS("%s\n", __FILE__); 259 260 mutex_lock(&dev->struct_mutex); 261 262 if (event) { 263 /* 264 * the pipe from user always is 0 so we can set pipe number 265 * of current owner to event. 266 */ 267 event->pipe = exynos_crtc->pipe; 268 269 list_add_tail(&event->base.link, 270 &dev_priv->pageflip_event_list); 271 272 ret = drm_vblank_get(dev, exynos_crtc->pipe); 273 if (ret) { 274 DRM_DEBUG("failed to acquire vblank counter\n"); 275 list_del(&event->base.link); 276 277 goto out; 278 } 279 280 crtc->fb = fb; 281 ret = exynos_drm_crtc_update(crtc); 282 if (ret) { 283 crtc->fb = old_fb; 284 drm_vblank_put(dev, exynos_crtc->pipe); 285 list_del(&event->base.link); 286 287 goto out; 288 } 289 290 /* 291 * the values related to a buffer of the drm framebuffer 292 * to be applied should be set at here. because these values 293 * first, are set to shadow registers and then to 294 * real registers at vsync front porch period. 295 */ 296 exynos_drm_crtc_apply(crtc); 297 } 298 out: 299 mutex_unlock(&dev->struct_mutex); 300 return ret; 301 } 302 303 static void exynos_drm_crtc_destroy(struct drm_crtc *crtc) 304 { 305 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 306 struct exynos_drm_private *private = crtc->dev->dev_private; 307 308 DRM_DEBUG_KMS("%s\n", __FILE__); 309 310 private->crtc[exynos_crtc->pipe] = NULL; 311 312 drm_crtc_cleanup(crtc); 313 kfree(exynos_crtc); 314 } 315 316 static struct drm_crtc_funcs exynos_crtc_funcs = { 317 .set_config = drm_crtc_helper_set_config, 318 .page_flip = exynos_drm_crtc_page_flip, 319 .destroy = exynos_drm_crtc_destroy, 320 }; 321 322 struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev, 323 struct drm_crtc *crtc) 324 { 325 struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); 326 327 return &exynos_crtc->overlay; 328 } 329 330 int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) 331 { 332 struct exynos_drm_crtc *exynos_crtc; 333 struct exynos_drm_private *private = dev->dev_private; 334 struct drm_crtc *crtc; 335 336 DRM_DEBUG_KMS("%s\n", __FILE__); 337 338 exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); 339 if (!exynos_crtc) { 340 DRM_ERROR("failed to allocate exynos crtc\n"); 341 return -ENOMEM; 342 } 343 344 exynos_crtc->pipe = nr; 345 crtc = &exynos_crtc->drm_crtc; 346 347 private->crtc[nr] = crtc; 348 349 drm_crtc_init(dev, crtc, &exynos_crtc_funcs); 350 drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); 351 352 return 0; 353 } 354 355 int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) 356 { 357 struct exynos_drm_private *private = dev->dev_private; 358 359 DRM_DEBUG_KMS("%s\n", __FILE__); 360 361 exynos_drm_fn_encoder(private->crtc[crtc], &crtc, 362 exynos_drm_enable_vblank); 363 364 return 0; 365 } 366 367 void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) 368 { 369 struct exynos_drm_private *private = dev->dev_private; 370 371 DRM_DEBUG_KMS("%s\n", __FILE__); 372 373 exynos_drm_fn_encoder(private->crtc[crtc], &crtc, 374 exynos_drm_disable_vblank); 375 } 376 377 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); 378 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 379 MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>"); 380 MODULE_DESCRIPTION("Samsung SoC DRM CRTC Driver"); 381 MODULE_LICENSE("GPL"); 382