1 /* exynos_drm_fimd.c 2 * 3 * Copyright (C) 2011 Samsung Electronics Co.Ltd 4 * Authors: 5 * Joonyoung Shim <jy0922.shim@samsung.com> 6 * Inki Dae <inki.dae@samsung.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 * 13 */ 14 #include <drm/drmP.h> 15 16 #include <linux/kernel.h> 17 #include <linux/platform_device.h> 18 #include <linux/clk.h> 19 #include <linux/of.h> 20 #include <linux/of_device.h> 21 #include <linux/pm_runtime.h> 22 23 #include <video/of_display_timing.h> 24 #include <video/of_videomode.h> 25 #include <video/samsung_fimd.h> 26 #include <drm/exynos_drm.h> 27 28 #include "exynos_drm_drv.h" 29 #include "exynos_drm_fbdev.h" 30 #include "exynos_drm_crtc.h" 31 #include "exynos_drm_iommu.h" 32 33 /* 34 * FIMD stands for Fully Interactive Mobile Display and 35 * as a display controller, it transfers contents drawn on memory 36 * to a LCD Panel through Display Interfaces such as RGB or 37 * CPU Interface. 38 */ 39 40 #define FIMD_DEFAULT_FRAMERATE 60 41 42 /* position control register for hardware window 0, 2 ~ 4.*/ 43 #define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16) 44 #define VIDOSD_B(win) (VIDOSD_BASE + 0x04 + (win) * 16) 45 /* 46 * size control register for hardware windows 0 and alpha control register 47 * for hardware windows 1 ~ 4 48 */ 49 #define VIDOSD_C(win) (VIDOSD_BASE + 0x08 + (win) * 16) 50 /* size control register for hardware windows 1 ~ 2. */ 51 #define VIDOSD_D(win) (VIDOSD_BASE + 0x0C + (win) * 16) 52 53 #define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) 54 #define VIDWx_BUF_END(win, buf) (VIDW_BUF_END(buf) + (win) * 8) 55 #define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) 56 57 /* color key control register for hardware window 1 ~ 4. */ 58 #define WKEYCON0_BASE(x) ((WKEYCON0 + 0x140) + ((x - 1) * 8)) 59 /* color key value register for hardware window 1 ~ 4. */ 60 #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + ((x - 1) * 8)) 61 62 /* FIMD has totally five hardware windows. */ 63 #define WINDOWS_NR 5 64 65 #define get_fimd_manager(mgr) platform_get_drvdata(to_platform_device(dev)) 66 67 struct fimd_driver_data { 68 unsigned int timing_base; 69 70 unsigned int has_shadowcon:1; 71 unsigned int has_clksel:1; 72 unsigned int has_limited_fmt:1; 73 }; 74 75 static struct fimd_driver_data s3c64xx_fimd_driver_data = { 76 .timing_base = 0x0, 77 .has_clksel = 1, 78 .has_limited_fmt = 1, 79 }; 80 81 static struct fimd_driver_data exynos4_fimd_driver_data = { 82 .timing_base = 0x0, 83 .has_shadowcon = 1, 84 }; 85 86 static struct fimd_driver_data exynos5_fimd_driver_data = { 87 .timing_base = 0x20000, 88 .has_shadowcon = 1, 89 }; 90 91 struct fimd_win_data { 92 unsigned int offset_x; 93 unsigned int offset_y; 94 unsigned int ovl_width; 95 unsigned int ovl_height; 96 unsigned int fb_width; 97 unsigned int fb_height; 98 unsigned int bpp; 99 unsigned int pixel_format; 100 dma_addr_t dma_addr; 101 unsigned int buf_offsize; 102 unsigned int line_size; /* bytes */ 103 bool enabled; 104 bool resume; 105 }; 106 107 struct fimd_context { 108 struct device *dev; 109 struct drm_device *drm_dev; 110 struct clk *bus_clk; 111 struct clk *lcd_clk; 112 void __iomem *regs; 113 struct drm_display_mode mode; 114 struct fimd_win_data win_data[WINDOWS_NR]; 115 unsigned int default_win; 116 unsigned long irq_flags; 117 u32 vidcon1; 118 bool suspended; 119 int pipe; 120 wait_queue_head_t wait_vsync_queue; 121 atomic_t wait_vsync_event; 122 123 struct exynos_drm_panel_info panel; 124 struct fimd_driver_data *driver_data; 125 }; 126 127 static const struct of_device_id fimd_driver_dt_match[] = { 128 { .compatible = "samsung,s3c6400-fimd", 129 .data = &s3c64xx_fimd_driver_data }, 130 { .compatible = "samsung,exynos4210-fimd", 131 .data = &exynos4_fimd_driver_data }, 132 { .compatible = "samsung,exynos5250-fimd", 133 .data = &exynos5_fimd_driver_data }, 134 {}, 135 }; 136 137 static inline struct fimd_driver_data *drm_fimd_get_driver_data( 138 struct platform_device *pdev) 139 { 140 const struct of_device_id *of_id = 141 of_match_device(fimd_driver_dt_match, &pdev->dev); 142 143 return (struct fimd_driver_data *)of_id->data; 144 } 145 146 static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, 147 struct drm_device *drm_dev, int pipe) 148 { 149 struct fimd_context *ctx = mgr->ctx; 150 151 ctx->drm_dev = drm_dev; 152 ctx->pipe = pipe; 153 154 /* 155 * enable drm irq mode. 156 * - with irq_enabled = true, we can use the vblank feature. 157 * 158 * P.S. note that we wouldn't use drm irq handler but 159 * just specific driver own one instead because 160 * drm framework supports only one irq handler. 161 */ 162 drm_dev->irq_enabled = true; 163 164 /* 165 * with vblank_disable_allowed = true, vblank interrupt will be disabled 166 * by drm timer once a current process gives up ownership of 167 * vblank event.(after drm_vblank_put function is called) 168 */ 169 drm_dev->vblank_disable_allowed = true; 170 171 /* attach this sub driver to iommu mapping if supported. */ 172 if (is_drm_iommu_supported(ctx->drm_dev)) 173 drm_iommu_attach_device(ctx->drm_dev, ctx->dev); 174 175 return 0; 176 } 177 178 static void fimd_mgr_remove(struct exynos_drm_manager *mgr) 179 { 180 struct fimd_context *ctx = mgr->ctx; 181 182 /* detach this sub driver from iommu mapping if supported. */ 183 if (is_drm_iommu_supported(ctx->drm_dev)) 184 drm_iommu_detach_device(ctx->drm_dev, ctx->dev); 185 } 186 187 static u32 fimd_calc_clkdiv(struct fimd_context *ctx, 188 const struct drm_display_mode *mode) 189 { 190 unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh; 191 u32 clkdiv; 192 193 /* Find the clock divider value that gets us closest to ideal_clk */ 194 clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk); 195 196 return (clkdiv < 0x100) ? clkdiv : 0xff; 197 } 198 199 static bool fimd_mode_fixup(struct exynos_drm_manager *mgr, 200 const struct drm_display_mode *mode, 201 struct drm_display_mode *adjusted_mode) 202 { 203 if (adjusted_mode->vrefresh == 0) 204 adjusted_mode->vrefresh = FIMD_DEFAULT_FRAMERATE; 205 206 return true; 207 } 208 209 static void fimd_mode_set(struct exynos_drm_manager *mgr, 210 const struct drm_display_mode *in_mode) 211 { 212 struct fimd_context *ctx = mgr->ctx; 213 214 drm_mode_copy(&ctx->mode, in_mode); 215 } 216 217 static void fimd_commit(struct exynos_drm_manager *mgr) 218 { 219 struct fimd_context *ctx = mgr->ctx; 220 struct drm_display_mode *mode = &ctx->mode; 221 struct fimd_driver_data *driver_data; 222 u32 val, clkdiv, vidcon1; 223 int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd; 224 225 driver_data = ctx->driver_data; 226 if (ctx->suspended) 227 return; 228 229 /* nothing to do if we haven't set the mode yet */ 230 if (mode->htotal == 0 || mode->vtotal == 0) 231 return; 232 233 /* setup polarity values */ 234 vidcon1 = ctx->vidcon1; 235 if (mode->flags & DRM_MODE_FLAG_NVSYNC) 236 vidcon1 |= VIDCON1_INV_VSYNC; 237 if (mode->flags & DRM_MODE_FLAG_NHSYNC) 238 vidcon1 |= VIDCON1_INV_HSYNC; 239 writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); 240 241 /* setup vertical timing values. */ 242 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; 243 vbpd = mode->crtc_vtotal - mode->crtc_vsync_end; 244 vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay; 245 246 val = VIDTCON0_VBPD(vbpd - 1) | 247 VIDTCON0_VFPD(vfpd - 1) | 248 VIDTCON0_VSPW(vsync_len - 1); 249 writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); 250 251 /* setup horizontal timing values. */ 252 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; 253 hbpd = mode->crtc_htotal - mode->crtc_hsync_end; 254 hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay; 255 256 val = VIDTCON1_HBPD(hbpd - 1) | 257 VIDTCON1_HFPD(hfpd - 1) | 258 VIDTCON1_HSPW(hsync_len - 1); 259 writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); 260 261 /* setup horizontal and vertical display size. */ 262 val = VIDTCON2_LINEVAL(mode->vdisplay - 1) | 263 VIDTCON2_HOZVAL(mode->hdisplay - 1) | 264 VIDTCON2_LINEVAL_E(mode->vdisplay - 1) | 265 VIDTCON2_HOZVAL_E(mode->hdisplay - 1); 266 writel(val, ctx->regs + driver_data->timing_base + VIDTCON2); 267 268 /* 269 * fields of register with prefix '_F' would be updated 270 * at vsync(same as dma start) 271 */ 272 val = VIDCON0_ENVID | VIDCON0_ENVID_F; 273 274 if (ctx->driver_data->has_clksel) 275 val |= VIDCON0_CLKSEL_LCD; 276 277 clkdiv = fimd_calc_clkdiv(ctx, mode); 278 if (clkdiv > 1) 279 val |= VIDCON0_CLKVAL_F(clkdiv - 1) | VIDCON0_CLKDIR; 280 281 writel(val, ctx->regs + VIDCON0); 282 } 283 284 static int fimd_enable_vblank(struct exynos_drm_manager *mgr) 285 { 286 struct fimd_context *ctx = mgr->ctx; 287 u32 val; 288 289 if (ctx->suspended) 290 return -EPERM; 291 292 if (!test_and_set_bit(0, &ctx->irq_flags)) { 293 val = readl(ctx->regs + VIDINTCON0); 294 295 val |= VIDINTCON0_INT_ENABLE; 296 val |= VIDINTCON0_INT_FRAME; 297 298 val &= ~VIDINTCON0_FRAMESEL0_MASK; 299 val |= VIDINTCON0_FRAMESEL0_VSYNC; 300 val &= ~VIDINTCON0_FRAMESEL1_MASK; 301 val |= VIDINTCON0_FRAMESEL1_NONE; 302 303 writel(val, ctx->regs + VIDINTCON0); 304 } 305 306 return 0; 307 } 308 309 static void fimd_disable_vblank(struct exynos_drm_manager *mgr) 310 { 311 struct fimd_context *ctx = mgr->ctx; 312 u32 val; 313 314 if (ctx->suspended) 315 return; 316 317 if (test_and_clear_bit(0, &ctx->irq_flags)) { 318 val = readl(ctx->regs + VIDINTCON0); 319 320 val &= ~VIDINTCON0_INT_FRAME; 321 val &= ~VIDINTCON0_INT_ENABLE; 322 323 writel(val, ctx->regs + VIDINTCON0); 324 } 325 } 326 327 static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr) 328 { 329 struct fimd_context *ctx = mgr->ctx; 330 331 if (ctx->suspended) 332 return; 333 334 atomic_set(&ctx->wait_vsync_event, 1); 335 336 /* 337 * wait for FIMD to signal VSYNC interrupt or return after 338 * timeout which is set to 50ms (refresh rate of 20). 339 */ 340 if (!wait_event_timeout(ctx->wait_vsync_queue, 341 !atomic_read(&ctx->wait_vsync_event), 342 HZ/20)) 343 DRM_DEBUG_KMS("vblank wait timed out.\n"); 344 } 345 346 static void fimd_win_mode_set(struct exynos_drm_manager *mgr, 347 struct exynos_drm_overlay *overlay) 348 { 349 struct fimd_context *ctx = mgr->ctx; 350 struct fimd_win_data *win_data; 351 int win; 352 unsigned long offset; 353 354 if (!overlay) { 355 DRM_ERROR("overlay is NULL\n"); 356 return; 357 } 358 359 win = overlay->zpos; 360 if (win == DEFAULT_ZPOS) 361 win = ctx->default_win; 362 363 if (win < 0 || win >= WINDOWS_NR) 364 return; 365 366 offset = overlay->fb_x * (overlay->bpp >> 3); 367 offset += overlay->fb_y * overlay->pitch; 368 369 DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch); 370 371 win_data = &ctx->win_data[win]; 372 373 win_data->offset_x = overlay->crtc_x; 374 win_data->offset_y = overlay->crtc_y; 375 win_data->ovl_width = overlay->crtc_width; 376 win_data->ovl_height = overlay->crtc_height; 377 win_data->fb_width = overlay->fb_width; 378 win_data->fb_height = overlay->fb_height; 379 win_data->dma_addr = overlay->dma_addr[0] + offset; 380 win_data->bpp = overlay->bpp; 381 win_data->pixel_format = overlay->pixel_format; 382 win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) * 383 (overlay->bpp >> 3); 384 win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3); 385 386 DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n", 387 win_data->offset_x, win_data->offset_y); 388 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", 389 win_data->ovl_width, win_data->ovl_height); 390 DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr); 391 DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n", 392 overlay->fb_width, overlay->crtc_width); 393 } 394 395 static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) 396 { 397 struct fimd_win_data *win_data = &ctx->win_data[win]; 398 unsigned long val; 399 400 val = WINCONx_ENWIN; 401 402 /* 403 * In case of s3c64xx, window 0 doesn't support alpha channel. 404 * So the request format is ARGB8888 then change it to XRGB8888. 405 */ 406 if (ctx->driver_data->has_limited_fmt && !win) { 407 if (win_data->pixel_format == DRM_FORMAT_ARGB8888) 408 win_data->pixel_format = DRM_FORMAT_XRGB8888; 409 } 410 411 switch (win_data->pixel_format) { 412 case DRM_FORMAT_C8: 413 val |= WINCON0_BPPMODE_8BPP_PALETTE; 414 val |= WINCONx_BURSTLEN_8WORD; 415 val |= WINCONx_BYTSWP; 416 break; 417 case DRM_FORMAT_XRGB1555: 418 val |= WINCON0_BPPMODE_16BPP_1555; 419 val |= WINCONx_HAWSWP; 420 val |= WINCONx_BURSTLEN_16WORD; 421 break; 422 case DRM_FORMAT_RGB565: 423 val |= WINCON0_BPPMODE_16BPP_565; 424 val |= WINCONx_HAWSWP; 425 val |= WINCONx_BURSTLEN_16WORD; 426 break; 427 case DRM_FORMAT_XRGB8888: 428 val |= WINCON0_BPPMODE_24BPP_888; 429 val |= WINCONx_WSWP; 430 val |= WINCONx_BURSTLEN_16WORD; 431 break; 432 case DRM_FORMAT_ARGB8888: 433 val |= WINCON1_BPPMODE_25BPP_A1888 434 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; 435 val |= WINCONx_WSWP; 436 val |= WINCONx_BURSTLEN_16WORD; 437 break; 438 default: 439 DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n"); 440 441 val |= WINCON0_BPPMODE_24BPP_888; 442 val |= WINCONx_WSWP; 443 val |= WINCONx_BURSTLEN_16WORD; 444 break; 445 } 446 447 DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp); 448 449 writel(val, ctx->regs + WINCON(win)); 450 } 451 452 static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win) 453 { 454 unsigned int keycon0 = 0, keycon1 = 0; 455 456 keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F | 457 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0); 458 459 keycon1 = WxKEYCON1_COLVAL(0xffffffff); 460 461 writel(keycon0, ctx->regs + WKEYCON0_BASE(win)); 462 writel(keycon1, ctx->regs + WKEYCON1_BASE(win)); 463 } 464 465 /** 466 * shadow_protect_win() - disable updating values from shadow registers at vsync 467 * 468 * @win: window to protect registers for 469 * @protect: 1 to protect (disable updates) 470 */ 471 static void fimd_shadow_protect_win(struct fimd_context *ctx, 472 int win, bool protect) 473 { 474 u32 reg, bits, val; 475 476 if (ctx->driver_data->has_shadowcon) { 477 reg = SHADOWCON; 478 bits = SHADOWCON_WINx_PROTECT(win); 479 } else { 480 reg = PRTCON; 481 bits = PRTCON_PROTECT; 482 } 483 484 val = readl(ctx->regs + reg); 485 if (protect) 486 val |= bits; 487 else 488 val &= ~bits; 489 writel(val, ctx->regs + reg); 490 } 491 492 static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) 493 { 494 struct fimd_context *ctx = mgr->ctx; 495 struct fimd_win_data *win_data; 496 int win = zpos; 497 unsigned long val, alpha, size; 498 unsigned int last_x; 499 unsigned int last_y; 500 501 if (ctx->suspended) 502 return; 503 504 if (win == DEFAULT_ZPOS) 505 win = ctx->default_win; 506 507 if (win < 0 || win >= WINDOWS_NR) 508 return; 509 510 win_data = &ctx->win_data[win]; 511 512 /* If suspended, enable this on resume */ 513 if (ctx->suspended) { 514 win_data->resume = true; 515 return; 516 } 517 518 /* 519 * SHADOWCON/PRTCON register is used for enabling timing. 520 * 521 * for example, once only width value of a register is set, 522 * if the dma is started then fimd hardware could malfunction so 523 * with protect window setting, the register fields with prefix '_F' 524 * wouldn't be updated at vsync also but updated once unprotect window 525 * is set. 526 */ 527 528 /* protect windows */ 529 fimd_shadow_protect_win(ctx, win, true); 530 531 /* buffer start address */ 532 val = (unsigned long)win_data->dma_addr; 533 writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); 534 535 /* buffer end address */ 536 size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3); 537 val = (unsigned long)(win_data->dma_addr + size); 538 writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); 539 540 DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n", 541 (unsigned long)win_data->dma_addr, val, size); 542 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", 543 win_data->ovl_width, win_data->ovl_height); 544 545 /* buffer size */ 546 val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) | 547 VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size) | 548 VIDW_BUF_SIZE_OFFSET_E(win_data->buf_offsize) | 549 VIDW_BUF_SIZE_PAGEWIDTH_E(win_data->line_size); 550 writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0)); 551 552 /* OSD position */ 553 val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) | 554 VIDOSDxA_TOPLEFT_Y(win_data->offset_y) | 555 VIDOSDxA_TOPLEFT_X_E(win_data->offset_x) | 556 VIDOSDxA_TOPLEFT_Y_E(win_data->offset_y); 557 writel(val, ctx->regs + VIDOSD_A(win)); 558 559 last_x = win_data->offset_x + win_data->ovl_width; 560 if (last_x) 561 last_x--; 562 last_y = win_data->offset_y + win_data->ovl_height; 563 if (last_y) 564 last_y--; 565 566 val = VIDOSDxB_BOTRIGHT_X(last_x) | VIDOSDxB_BOTRIGHT_Y(last_y) | 567 VIDOSDxB_BOTRIGHT_X_E(last_x) | VIDOSDxB_BOTRIGHT_Y_E(last_y); 568 569 writel(val, ctx->regs + VIDOSD_B(win)); 570 571 DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n", 572 win_data->offset_x, win_data->offset_y, last_x, last_y); 573 574 /* hardware window 0 doesn't support alpha channel. */ 575 if (win != 0) { 576 /* OSD alpha */ 577 alpha = VIDISD14C_ALPHA1_R(0xf) | 578 VIDISD14C_ALPHA1_G(0xf) | 579 VIDISD14C_ALPHA1_B(0xf); 580 581 writel(alpha, ctx->regs + VIDOSD_C(win)); 582 } 583 584 /* OSD size */ 585 if (win != 3 && win != 4) { 586 u32 offset = VIDOSD_D(win); 587 if (win == 0) 588 offset = VIDOSD_C(win); 589 val = win_data->ovl_width * win_data->ovl_height; 590 writel(val, ctx->regs + offset); 591 592 DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val); 593 } 594 595 fimd_win_set_pixfmt(ctx, win); 596 597 /* hardware window 0 doesn't support color key. */ 598 if (win != 0) 599 fimd_win_set_colkey(ctx, win); 600 601 /* wincon */ 602 val = readl(ctx->regs + WINCON(win)); 603 val |= WINCONx_ENWIN; 604 writel(val, ctx->regs + WINCON(win)); 605 606 /* Enable DMA channel and unprotect windows */ 607 fimd_shadow_protect_win(ctx, win, false); 608 609 if (ctx->driver_data->has_shadowcon) { 610 val = readl(ctx->regs + SHADOWCON); 611 val |= SHADOWCON_CHx_ENABLE(win); 612 writel(val, ctx->regs + SHADOWCON); 613 } 614 615 win_data->enabled = true; 616 } 617 618 static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) 619 { 620 struct fimd_context *ctx = mgr->ctx; 621 struct fimd_win_data *win_data; 622 int win = zpos; 623 u32 val; 624 625 if (win == DEFAULT_ZPOS) 626 win = ctx->default_win; 627 628 if (win < 0 || win >= WINDOWS_NR) 629 return; 630 631 win_data = &ctx->win_data[win]; 632 633 if (ctx->suspended) { 634 /* do not resume this window*/ 635 win_data->resume = false; 636 return; 637 } 638 639 /* protect windows */ 640 fimd_shadow_protect_win(ctx, win, true); 641 642 /* wincon */ 643 val = readl(ctx->regs + WINCON(win)); 644 val &= ~WINCONx_ENWIN; 645 writel(val, ctx->regs + WINCON(win)); 646 647 /* unprotect windows */ 648 if (ctx->driver_data->has_shadowcon) { 649 val = readl(ctx->regs + SHADOWCON); 650 val &= ~SHADOWCON_CHx_ENABLE(win); 651 writel(val, ctx->regs + SHADOWCON); 652 } 653 654 fimd_shadow_protect_win(ctx, win, false); 655 656 win_data->enabled = false; 657 } 658 659 static void fimd_clear_win(struct fimd_context *ctx, int win) 660 { 661 writel(0, ctx->regs + WINCON(win)); 662 writel(0, ctx->regs + VIDOSD_A(win)); 663 writel(0, ctx->regs + VIDOSD_B(win)); 664 writel(0, ctx->regs + VIDOSD_C(win)); 665 666 if (win == 1 || win == 2) 667 writel(0, ctx->regs + VIDOSD_D(win)); 668 669 fimd_shadow_protect_win(ctx, win, false); 670 } 671 672 static void fimd_window_suspend(struct exynos_drm_manager *mgr) 673 { 674 struct fimd_context *ctx = mgr->ctx; 675 struct fimd_win_data *win_data; 676 int i; 677 678 for (i = 0; i < WINDOWS_NR; i++) { 679 win_data = &ctx->win_data[i]; 680 win_data->resume = win_data->enabled; 681 if (win_data->enabled) 682 fimd_win_disable(mgr, i); 683 } 684 fimd_wait_for_vblank(mgr); 685 } 686 687 static void fimd_window_resume(struct exynos_drm_manager *mgr) 688 { 689 struct fimd_context *ctx = mgr->ctx; 690 struct fimd_win_data *win_data; 691 int i; 692 693 for (i = 0; i < WINDOWS_NR; i++) { 694 win_data = &ctx->win_data[i]; 695 win_data->enabled = win_data->resume; 696 win_data->resume = false; 697 } 698 } 699 700 static void fimd_apply(struct exynos_drm_manager *mgr) 701 { 702 struct fimd_context *ctx = mgr->ctx; 703 struct fimd_win_data *win_data; 704 int i; 705 706 for (i = 0; i < WINDOWS_NR; i++) { 707 win_data = &ctx->win_data[i]; 708 if (win_data->enabled) 709 fimd_win_commit(mgr, i); 710 } 711 712 fimd_commit(mgr); 713 } 714 715 static int fimd_poweron(struct exynos_drm_manager *mgr) 716 { 717 struct fimd_context *ctx = mgr->ctx; 718 int ret; 719 720 if (!ctx->suspended) 721 return 0; 722 723 ctx->suspended = false; 724 725 pm_runtime_get_sync(ctx->dev); 726 727 ret = clk_prepare_enable(ctx->bus_clk); 728 if (ret < 0) { 729 DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret); 730 goto bus_clk_err; 731 } 732 733 ret = clk_prepare_enable(ctx->lcd_clk); 734 if (ret < 0) { 735 DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret); 736 goto lcd_clk_err; 737 } 738 739 /* if vblank was enabled status, enable it again. */ 740 if (test_and_clear_bit(0, &ctx->irq_flags)) { 741 ret = fimd_enable_vblank(mgr); 742 if (ret) { 743 DRM_ERROR("Failed to re-enable vblank [%d]\n", ret); 744 goto enable_vblank_err; 745 } 746 } 747 748 fimd_window_resume(mgr); 749 750 fimd_apply(mgr); 751 752 return 0; 753 754 enable_vblank_err: 755 clk_disable_unprepare(ctx->lcd_clk); 756 lcd_clk_err: 757 clk_disable_unprepare(ctx->bus_clk); 758 bus_clk_err: 759 ctx->suspended = true; 760 return ret; 761 } 762 763 static int fimd_poweroff(struct exynos_drm_manager *mgr) 764 { 765 struct fimd_context *ctx = mgr->ctx; 766 767 if (ctx->suspended) 768 return 0; 769 770 /* 771 * We need to make sure that all windows are disabled before we 772 * suspend that connector. Otherwise we might try to scan from 773 * a destroyed buffer later. 774 */ 775 fimd_window_suspend(mgr); 776 777 clk_disable_unprepare(ctx->lcd_clk); 778 clk_disable_unprepare(ctx->bus_clk); 779 780 pm_runtime_put_sync(ctx->dev); 781 782 ctx->suspended = true; 783 return 0; 784 } 785 786 static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) 787 { 788 DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); 789 790 switch (mode) { 791 case DRM_MODE_DPMS_ON: 792 fimd_poweron(mgr); 793 break; 794 case DRM_MODE_DPMS_STANDBY: 795 case DRM_MODE_DPMS_SUSPEND: 796 case DRM_MODE_DPMS_OFF: 797 fimd_poweroff(mgr); 798 break; 799 default: 800 DRM_DEBUG_KMS("unspecified mode %d\n", mode); 801 break; 802 } 803 } 804 805 static struct exynos_drm_manager_ops fimd_manager_ops = { 806 .initialize = fimd_mgr_initialize, 807 .remove = fimd_mgr_remove, 808 .dpms = fimd_dpms, 809 .mode_fixup = fimd_mode_fixup, 810 .mode_set = fimd_mode_set, 811 .commit = fimd_commit, 812 .enable_vblank = fimd_enable_vblank, 813 .disable_vblank = fimd_disable_vblank, 814 .wait_for_vblank = fimd_wait_for_vblank, 815 .win_mode_set = fimd_win_mode_set, 816 .win_commit = fimd_win_commit, 817 .win_disable = fimd_win_disable, 818 }; 819 820 static struct exynos_drm_manager fimd_manager = { 821 .type = EXYNOS_DISPLAY_TYPE_LCD, 822 .ops = &fimd_manager_ops, 823 }; 824 825 static irqreturn_t fimd_irq_handler(int irq, void *dev_id) 826 { 827 struct fimd_context *ctx = (struct fimd_context *)dev_id; 828 u32 val; 829 830 val = readl(ctx->regs + VIDINTCON1); 831 832 if (val & VIDINTCON1_INT_FRAME) 833 /* VSYNC interrupt */ 834 writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); 835 836 /* check the crtc is detached already from encoder */ 837 if (ctx->pipe < 0 || !ctx->drm_dev) 838 goto out; 839 840 drm_handle_vblank(ctx->drm_dev, ctx->pipe); 841 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); 842 843 /* set wait vsync event to zero and wake up queue. */ 844 if (atomic_read(&ctx->wait_vsync_event)) { 845 atomic_set(&ctx->wait_vsync_event, 0); 846 wake_up(&ctx->wait_vsync_queue); 847 } 848 out: 849 return IRQ_HANDLED; 850 } 851 852 static int fimd_probe(struct platform_device *pdev) 853 { 854 struct device *dev = &pdev->dev; 855 struct fimd_context *ctx; 856 struct resource *res; 857 int win; 858 int ret = -EINVAL; 859 860 if (!dev->of_node) 861 return -ENODEV; 862 863 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 864 if (!ctx) 865 return -ENOMEM; 866 867 ctx->dev = dev; 868 ctx->suspended = true; 869 870 if (of_property_read_bool(dev->of_node, "samsung,invert-vden")) 871 ctx->vidcon1 |= VIDCON1_INV_VDEN; 872 if (of_property_read_bool(dev->of_node, "samsung,invert-vclk")) 873 ctx->vidcon1 |= VIDCON1_INV_VCLK; 874 875 ctx->bus_clk = devm_clk_get(dev, "fimd"); 876 if (IS_ERR(ctx->bus_clk)) { 877 dev_err(dev, "failed to get bus clock\n"); 878 return PTR_ERR(ctx->bus_clk); 879 } 880 881 ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd"); 882 if (IS_ERR(ctx->lcd_clk)) { 883 dev_err(dev, "failed to get lcd clock\n"); 884 return PTR_ERR(ctx->lcd_clk); 885 } 886 887 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 888 889 ctx->regs = devm_ioremap_resource(dev, res); 890 if (IS_ERR(ctx->regs)) 891 return PTR_ERR(ctx->regs); 892 893 res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync"); 894 if (!res) { 895 dev_err(dev, "irq request failed.\n"); 896 return -ENXIO; 897 } 898 899 ret = devm_request_irq(dev, res->start, fimd_irq_handler, 900 0, "drm_fimd", ctx); 901 if (ret) { 902 dev_err(dev, "irq request failed.\n"); 903 return ret; 904 } 905 906 ctx->driver_data = drm_fimd_get_driver_data(pdev); 907 init_waitqueue_head(&ctx->wait_vsync_queue); 908 atomic_set(&ctx->wait_vsync_event, 0); 909 910 platform_set_drvdata(pdev, &fimd_manager); 911 912 fimd_manager.ctx = ctx; 913 exynos_drm_manager_register(&fimd_manager); 914 915 exynos_dpi_probe(ctx->dev); 916 917 pm_runtime_enable(dev); 918 919 for (win = 0; win < WINDOWS_NR; win++) 920 fimd_clear_win(ctx, win); 921 922 return 0; 923 } 924 925 static int fimd_remove(struct platform_device *pdev) 926 { 927 struct exynos_drm_manager *mgr = platform_get_drvdata(pdev); 928 929 exynos_dpi_remove(&pdev->dev); 930 931 exynos_drm_manager_unregister(&fimd_manager); 932 933 fimd_dpms(mgr, DRM_MODE_DPMS_OFF); 934 935 pm_runtime_disable(&pdev->dev); 936 937 return 0; 938 } 939 940 struct platform_driver fimd_driver = { 941 .probe = fimd_probe, 942 .remove = fimd_remove, 943 .driver = { 944 .name = "exynos4-fb", 945 .owner = THIS_MODULE, 946 .of_match_table = fimd_driver_dt_match, 947 }, 948 }; 949