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 "drmP.h" 15 16 #include <linux/kernel.h> 17 #include <linux/module.h> 18 #include <linux/platform_device.h> 19 #include <linux/clk.h> 20 21 #include <drm/exynos_drm.h> 22 #include <plat/regs-fb-v4.h> 23 24 #include "exynos_drm_drv.h" 25 #include "exynos_drm_fbdev.h" 26 #include "exynos_drm_crtc.h" 27 28 /* 29 * FIMD is stand for Fully Interactive Mobile Display and 30 * as a display controller, it transfers contents drawn on memory 31 * to a LCD Panel through Display Interfaces such as RGB or 32 * CPU Interface. 33 */ 34 35 /* position control register for hardware window 0, 2 ~ 4.*/ 36 #define VIDOSD_A(win) (VIDOSD_BASE + 0x00 + (win) * 16) 37 #define VIDOSD_B(win) (VIDOSD_BASE + 0x04 + (win) * 16) 38 /* size control register for hardware window 0. */ 39 #define VIDOSD_C_SIZE_W0 (VIDOSD_BASE + 0x08) 40 /* alpha control register for hardware window 1 ~ 4. */ 41 #define VIDOSD_C(win) (VIDOSD_BASE + 0x18 + (win) * 16) 42 /* size control register for hardware window 1 ~ 4. */ 43 #define VIDOSD_D(win) (VIDOSD_BASE + 0x0C + (win) * 16) 44 45 #define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) 46 #define VIDWx_BUF_END(win, buf) (VIDW_BUF_END(buf) + (win) * 8) 47 #define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) 48 49 /* color key control register for hardware window 1 ~ 4. */ 50 #define WKEYCON0_BASE(x) ((WKEYCON0 + 0x140) + (x * 8)) 51 /* color key value register for hardware window 1 ~ 4. */ 52 #define WKEYCON1_BASE(x) ((WKEYCON1 + 0x140) + (x * 8)) 53 54 /* FIMD has totally five hardware windows. */ 55 #define WINDOWS_NR 5 56 57 #define get_fimd_context(dev) platform_get_drvdata(to_platform_device(dev)) 58 59 struct fimd_win_data { 60 unsigned int offset_x; 61 unsigned int offset_y; 62 unsigned int ovl_width; 63 unsigned int ovl_height; 64 unsigned int fb_width; 65 unsigned int fb_height; 66 unsigned int bpp; 67 dma_addr_t dma_addr; 68 void __iomem *vaddr; 69 unsigned int buf_offsize; 70 unsigned int line_size; /* bytes */ 71 }; 72 73 struct fimd_context { 74 struct exynos_drm_subdrv subdrv; 75 int irq; 76 struct drm_crtc *crtc; 77 struct clk *bus_clk; 78 struct clk *lcd_clk; 79 struct resource *regs_res; 80 void __iomem *regs; 81 struct fimd_win_data win_data[WINDOWS_NR]; 82 unsigned int clkdiv; 83 unsigned int default_win; 84 unsigned long irq_flags; 85 u32 vidcon0; 86 u32 vidcon1; 87 88 struct fb_videomode *timing; 89 }; 90 91 static bool fimd_display_is_connected(struct device *dev) 92 { 93 DRM_DEBUG_KMS("%s\n", __FILE__); 94 95 /* TODO. */ 96 97 return true; 98 } 99 100 static void *fimd_get_timing(struct device *dev) 101 { 102 struct fimd_context *ctx = get_fimd_context(dev); 103 104 DRM_DEBUG_KMS("%s\n", __FILE__); 105 106 return ctx->timing; 107 } 108 109 static int fimd_check_timing(struct device *dev, void *timing) 110 { 111 DRM_DEBUG_KMS("%s\n", __FILE__); 112 113 /* TODO. */ 114 115 return 0; 116 } 117 118 static int fimd_display_power_on(struct device *dev, int mode) 119 { 120 DRM_DEBUG_KMS("%s\n", __FILE__); 121 122 /* TODO. */ 123 124 return 0; 125 } 126 127 static struct exynos_drm_display_ops fimd_display_ops = { 128 .type = EXYNOS_DISPLAY_TYPE_LCD, 129 .is_connected = fimd_display_is_connected, 130 .get_timing = fimd_get_timing, 131 .check_timing = fimd_check_timing, 132 .power_on = fimd_display_power_on, 133 }; 134 135 static void fimd_commit(struct device *dev) 136 { 137 struct fimd_context *ctx = get_fimd_context(dev); 138 struct fb_videomode *timing = ctx->timing; 139 u32 val; 140 141 DRM_DEBUG_KMS("%s\n", __FILE__); 142 143 /* setup polarity values from machine code. */ 144 writel(ctx->vidcon1, ctx->regs + VIDCON1); 145 146 /* setup vertical timing values. */ 147 val = VIDTCON0_VBPD(timing->upper_margin - 1) | 148 VIDTCON0_VFPD(timing->lower_margin - 1) | 149 VIDTCON0_VSPW(timing->vsync_len - 1); 150 writel(val, ctx->regs + VIDTCON0); 151 152 /* setup horizontal timing values. */ 153 val = VIDTCON1_HBPD(timing->left_margin - 1) | 154 VIDTCON1_HFPD(timing->right_margin - 1) | 155 VIDTCON1_HSPW(timing->hsync_len - 1); 156 writel(val, ctx->regs + VIDTCON1); 157 158 /* setup horizontal and vertical display size. */ 159 val = VIDTCON2_LINEVAL(timing->yres - 1) | 160 VIDTCON2_HOZVAL(timing->xres - 1); 161 writel(val, ctx->regs + VIDTCON2); 162 163 /* setup clock source, clock divider, enable dma. */ 164 val = ctx->vidcon0; 165 val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); 166 167 if (ctx->clkdiv > 1) 168 val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR; 169 else 170 val &= ~VIDCON0_CLKDIR; /* 1:1 clock */ 171 172 /* 173 * fields of register with prefix '_F' would be updated 174 * at vsync(same as dma start) 175 */ 176 val |= VIDCON0_ENVID | VIDCON0_ENVID_F; 177 writel(val, ctx->regs + VIDCON0); 178 } 179 180 static void fimd_disable(struct device *dev) 181 { 182 struct fimd_context *ctx = get_fimd_context(dev); 183 struct exynos_drm_subdrv *subdrv = &ctx->subdrv; 184 struct drm_device *drm_dev = subdrv->drm_dev; 185 struct exynos_drm_manager *manager = &subdrv->manager; 186 u32 val; 187 188 DRM_DEBUG_KMS("%s\n", __FILE__); 189 190 /* fimd dma off */ 191 val = readl(ctx->regs + VIDCON0); 192 val &= ~(VIDCON0_ENVID | VIDCON0_ENVID_F); 193 writel(val, ctx->regs + VIDCON0); 194 195 /* 196 * if vblank is enabled status with dma off then 197 * it disables vsync interrupt. 198 */ 199 if (drm_dev->vblank_enabled[manager->pipe] && 200 atomic_read(&drm_dev->vblank_refcount[manager->pipe])) { 201 drm_vblank_put(drm_dev, manager->pipe); 202 203 /* 204 * if vblank_disable_allowed is 0 then disable 205 * vsync interrupt right now else the vsync interrupt 206 * would be disabled by drm timer once a current process 207 * gives up ownershop of vblank event. 208 */ 209 if (!drm_dev->vblank_disable_allowed) 210 drm_vblank_off(drm_dev, manager->pipe); 211 } 212 } 213 214 static int fimd_enable_vblank(struct device *dev) 215 { 216 struct fimd_context *ctx = get_fimd_context(dev); 217 u32 val; 218 219 DRM_DEBUG_KMS("%s\n", __FILE__); 220 221 if (!test_and_set_bit(0, &ctx->irq_flags)) { 222 val = readl(ctx->regs + VIDINTCON0); 223 224 val |= VIDINTCON0_INT_ENABLE; 225 val |= VIDINTCON0_INT_FRAME; 226 227 val &= ~VIDINTCON0_FRAMESEL0_MASK; 228 val |= VIDINTCON0_FRAMESEL0_VSYNC; 229 val &= ~VIDINTCON0_FRAMESEL1_MASK; 230 val |= VIDINTCON0_FRAMESEL1_NONE; 231 232 writel(val, ctx->regs + VIDINTCON0); 233 } 234 235 return 0; 236 } 237 238 static void fimd_disable_vblank(struct device *dev) 239 { 240 struct fimd_context *ctx = get_fimd_context(dev); 241 u32 val; 242 243 DRM_DEBUG_KMS("%s\n", __FILE__); 244 245 if (test_and_clear_bit(0, &ctx->irq_flags)) { 246 val = readl(ctx->regs + VIDINTCON0); 247 248 val &= ~VIDINTCON0_INT_FRAME; 249 val &= ~VIDINTCON0_INT_ENABLE; 250 251 writel(val, ctx->regs + VIDINTCON0); 252 } 253 } 254 255 static struct exynos_drm_manager_ops fimd_manager_ops = { 256 .commit = fimd_commit, 257 .disable = fimd_disable, 258 .enable_vblank = fimd_enable_vblank, 259 .disable_vblank = fimd_disable_vblank, 260 }; 261 262 static void fimd_win_mode_set(struct device *dev, 263 struct exynos_drm_overlay *overlay) 264 { 265 struct fimd_context *ctx = get_fimd_context(dev); 266 struct fimd_win_data *win_data; 267 unsigned long offset; 268 269 DRM_DEBUG_KMS("%s\n", __FILE__); 270 271 if (!overlay) { 272 dev_err(dev, "overlay is NULL\n"); 273 return; 274 } 275 276 offset = overlay->fb_x * (overlay->bpp >> 3); 277 offset += overlay->fb_y * overlay->pitch; 278 279 DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch); 280 281 win_data = &ctx->win_data[ctx->default_win]; 282 283 win_data->offset_x = overlay->crtc_x; 284 win_data->offset_y = overlay->crtc_y; 285 win_data->ovl_width = overlay->crtc_width; 286 win_data->ovl_height = overlay->crtc_height; 287 win_data->fb_width = overlay->fb_width; 288 win_data->fb_height = overlay->fb_height; 289 win_data->dma_addr = overlay->dma_addr + offset; 290 win_data->vaddr = overlay->vaddr + offset; 291 win_data->bpp = overlay->bpp; 292 win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) * 293 (overlay->bpp >> 3); 294 win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3); 295 296 DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n", 297 win_data->offset_x, win_data->offset_y); 298 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", 299 win_data->ovl_width, win_data->ovl_height); 300 DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n", 301 (unsigned long)win_data->dma_addr, 302 (unsigned long)win_data->vaddr); 303 DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n", 304 overlay->fb_width, overlay->crtc_width); 305 } 306 307 static void fimd_win_set_pixfmt(struct device *dev, unsigned int win) 308 { 309 struct fimd_context *ctx = get_fimd_context(dev); 310 struct fimd_win_data *win_data = &ctx->win_data[win]; 311 unsigned long val; 312 313 DRM_DEBUG_KMS("%s\n", __FILE__); 314 315 val = WINCONx_ENWIN; 316 317 switch (win_data->bpp) { 318 case 1: 319 val |= WINCON0_BPPMODE_1BPP; 320 val |= WINCONx_BITSWP; 321 val |= WINCONx_BURSTLEN_4WORD; 322 break; 323 case 2: 324 val |= WINCON0_BPPMODE_2BPP; 325 val |= WINCONx_BITSWP; 326 val |= WINCONx_BURSTLEN_8WORD; 327 break; 328 case 4: 329 val |= WINCON0_BPPMODE_4BPP; 330 val |= WINCONx_BITSWP; 331 val |= WINCONx_BURSTLEN_8WORD; 332 break; 333 case 8: 334 val |= WINCON0_BPPMODE_8BPP_PALETTE; 335 val |= WINCONx_BURSTLEN_8WORD; 336 val |= WINCONx_BYTSWP; 337 break; 338 case 16: 339 val |= WINCON0_BPPMODE_16BPP_565; 340 val |= WINCONx_HAWSWP; 341 val |= WINCONx_BURSTLEN_16WORD; 342 break; 343 case 24: 344 val |= WINCON0_BPPMODE_24BPP_888; 345 val |= WINCONx_WSWP; 346 val |= WINCONx_BURSTLEN_16WORD; 347 break; 348 case 32: 349 val |= WINCON1_BPPMODE_28BPP_A4888 350 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; 351 val |= WINCONx_WSWP; 352 val |= WINCONx_BURSTLEN_16WORD; 353 break; 354 default: 355 DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n"); 356 357 val |= WINCON0_BPPMODE_24BPP_888; 358 val |= WINCONx_WSWP; 359 val |= WINCONx_BURSTLEN_16WORD; 360 break; 361 } 362 363 DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp); 364 365 writel(val, ctx->regs + WINCON(win)); 366 } 367 368 static void fimd_win_set_colkey(struct device *dev, unsigned int win) 369 { 370 struct fimd_context *ctx = get_fimd_context(dev); 371 unsigned int keycon0 = 0, keycon1 = 0; 372 373 DRM_DEBUG_KMS("%s\n", __FILE__); 374 375 keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F | 376 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0); 377 378 keycon1 = WxKEYCON1_COLVAL(0xffffffff); 379 380 writel(keycon0, ctx->regs + WKEYCON0_BASE(win)); 381 writel(keycon1, ctx->regs + WKEYCON1_BASE(win)); 382 } 383 384 static void fimd_win_commit(struct device *dev) 385 { 386 struct fimd_context *ctx = get_fimd_context(dev); 387 struct fimd_win_data *win_data; 388 int win = ctx->default_win; 389 unsigned long val, alpha, size; 390 391 DRM_DEBUG_KMS("%s\n", __FILE__); 392 393 if (win < 0 || win > WINDOWS_NR) 394 return; 395 396 win_data = &ctx->win_data[win]; 397 398 /* 399 * SHADOWCON register is used for enabling timing. 400 * 401 * for example, once only width value of a register is set, 402 * if the dma is started then fimd hardware could malfunction so 403 * with protect window setting, the register fields with prefix '_F' 404 * wouldn't be updated at vsync also but updated once unprotect window 405 * is set. 406 */ 407 408 /* protect windows */ 409 val = readl(ctx->regs + SHADOWCON); 410 val |= SHADOWCON_WINx_PROTECT(win); 411 writel(val, ctx->regs + SHADOWCON); 412 413 /* buffer start address */ 414 val = (unsigned long)win_data->dma_addr; 415 writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); 416 417 /* buffer end address */ 418 size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3); 419 val = (unsigned long)(win_data->dma_addr + size); 420 writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); 421 422 DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n", 423 (unsigned long)win_data->dma_addr, val, size); 424 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", 425 win_data->ovl_width, win_data->ovl_height); 426 427 /* buffer size */ 428 val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) | 429 VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size); 430 writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0)); 431 432 /* OSD position */ 433 val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) | 434 VIDOSDxA_TOPLEFT_Y(win_data->offset_y); 435 writel(val, ctx->regs + VIDOSD_A(win)); 436 437 val = VIDOSDxB_BOTRIGHT_X(win_data->offset_x + 438 win_data->ovl_width - 1) | 439 VIDOSDxB_BOTRIGHT_Y(win_data->offset_y + 440 win_data->ovl_height - 1); 441 writel(val, ctx->regs + VIDOSD_B(win)); 442 443 DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n", 444 win_data->offset_x, win_data->offset_y, 445 win_data->offset_x + win_data->ovl_width - 1, 446 win_data->offset_y + win_data->ovl_height - 1); 447 448 /* hardware window 0 doesn't support alpha channel. */ 449 if (win != 0) { 450 /* OSD alpha */ 451 alpha = VIDISD14C_ALPHA1_R(0xf) | 452 VIDISD14C_ALPHA1_G(0xf) | 453 VIDISD14C_ALPHA1_B(0xf); 454 455 writel(alpha, ctx->regs + VIDOSD_C(win)); 456 } 457 458 /* OSD size */ 459 if (win != 3 && win != 4) { 460 u32 offset = VIDOSD_D(win); 461 if (win == 0) 462 offset = VIDOSD_C_SIZE_W0; 463 val = win_data->ovl_width * win_data->ovl_height; 464 writel(val, ctx->regs + offset); 465 466 DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val); 467 } 468 469 fimd_win_set_pixfmt(dev, win); 470 471 /* hardware window 0 doesn't support color key. */ 472 if (win != 0) 473 fimd_win_set_colkey(dev, win); 474 475 /* Enable DMA channel and unprotect windows */ 476 val = readl(ctx->regs + SHADOWCON); 477 val |= SHADOWCON_CHx_ENABLE(win); 478 val &= ~SHADOWCON_WINx_PROTECT(win); 479 writel(val, ctx->regs + SHADOWCON); 480 } 481 482 static void fimd_win_disable(struct device *dev) 483 { 484 struct fimd_context *ctx = get_fimd_context(dev); 485 int win = ctx->default_win; 486 u32 val; 487 488 DRM_DEBUG_KMS("%s\n", __FILE__); 489 490 if (win < 0 || win > WINDOWS_NR) 491 return; 492 493 /* protect windows */ 494 val = readl(ctx->regs + SHADOWCON); 495 val |= SHADOWCON_WINx_PROTECT(win); 496 writel(val, ctx->regs + SHADOWCON); 497 498 /* wincon */ 499 val = readl(ctx->regs + WINCON(win)); 500 val &= ~WINCONx_ENWIN; 501 writel(val, ctx->regs + WINCON(win)); 502 503 /* unprotect windows */ 504 val = readl(ctx->regs + SHADOWCON); 505 val &= ~SHADOWCON_CHx_ENABLE(win); 506 val &= ~SHADOWCON_WINx_PROTECT(win); 507 writel(val, ctx->regs + SHADOWCON); 508 } 509 510 static struct exynos_drm_overlay_ops fimd_overlay_ops = { 511 .mode_set = fimd_win_mode_set, 512 .commit = fimd_win_commit, 513 .disable = fimd_win_disable, 514 }; 515 516 static void fimd_finish_pageflip(struct drm_device *drm_dev, int crtc) 517 { 518 struct exynos_drm_private *dev_priv = drm_dev->dev_private; 519 struct drm_pending_vblank_event *e, *t; 520 struct timeval now; 521 unsigned long flags; 522 bool is_checked = false; 523 524 spin_lock_irqsave(&drm_dev->event_lock, flags); 525 526 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, 527 base.link) { 528 /* if event's pipe isn't same as crtc then ignore it. */ 529 if (crtc != e->pipe) 530 continue; 531 532 is_checked = true; 533 534 do_gettimeofday(&now); 535 e->event.sequence = 0; 536 e->event.tv_sec = now.tv_sec; 537 e->event.tv_usec = now.tv_usec; 538 539 list_move_tail(&e->base.link, &e->base.file_priv->event_list); 540 wake_up_interruptible(&e->base.file_priv->event_wait); 541 } 542 543 if (is_checked) 544 drm_vblank_put(drm_dev, crtc); 545 546 spin_unlock_irqrestore(&drm_dev->event_lock, flags); 547 } 548 549 static irqreturn_t fimd_irq_handler(int irq, void *dev_id) 550 { 551 struct fimd_context *ctx = (struct fimd_context *)dev_id; 552 struct exynos_drm_subdrv *subdrv = &ctx->subdrv; 553 struct drm_device *drm_dev = subdrv->drm_dev; 554 struct exynos_drm_manager *manager = &subdrv->manager; 555 u32 val; 556 557 val = readl(ctx->regs + VIDINTCON1); 558 559 if (val & VIDINTCON1_INT_FRAME) 560 /* VSYNC interrupt */ 561 writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); 562 563 /* 564 * in case that vblank_disable_allowed is 1, it could induce 565 * the problem that manager->pipe could be -1 because with 566 * disable callback, vsync interrupt isn't disabled and at this moment, 567 * vsync interrupt could occur. the vsync interrupt would be disabled 568 * by timer handler later. 569 */ 570 if (manager->pipe == -1) 571 return IRQ_HANDLED; 572 573 drm_handle_vblank(drm_dev, manager->pipe); 574 fimd_finish_pageflip(drm_dev, manager->pipe); 575 576 return IRQ_HANDLED; 577 } 578 579 static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev) 580 { 581 DRM_DEBUG_KMS("%s\n", __FILE__); 582 583 /* 584 * enable drm irq mode. 585 * - with irq_enabled = 1, we can use the vblank feature. 586 * 587 * P.S. note that we wouldn't use drm irq handler but 588 * just specific driver own one instead because 589 * drm framework supports only one irq handler. 590 */ 591 drm_dev->irq_enabled = 1; 592 593 return 0; 594 } 595 596 static void fimd_subdrv_remove(struct drm_device *drm_dev) 597 { 598 DRM_DEBUG_KMS("%s\n", __FILE__); 599 600 /* TODO. */ 601 } 602 603 static int fimd_calc_clkdiv(struct fimd_context *ctx, 604 struct fb_videomode *timing) 605 { 606 unsigned long clk = clk_get_rate(ctx->lcd_clk); 607 u32 retrace; 608 u32 clkdiv; 609 u32 best_framerate = 0; 610 u32 framerate; 611 612 DRM_DEBUG_KMS("%s\n", __FILE__); 613 614 retrace = timing->left_margin + timing->hsync_len + 615 timing->right_margin + timing->xres; 616 retrace *= timing->upper_margin + timing->vsync_len + 617 timing->lower_margin + timing->yres; 618 619 /* default framerate is 60Hz */ 620 if (!timing->refresh) 621 timing->refresh = 60; 622 623 clk /= retrace; 624 625 for (clkdiv = 1; clkdiv < 0x100; clkdiv++) { 626 int tmp; 627 628 /* get best framerate */ 629 framerate = clk / clkdiv; 630 tmp = timing->refresh - framerate; 631 if (tmp < 0) { 632 best_framerate = framerate; 633 continue; 634 } else { 635 if (!best_framerate) 636 best_framerate = framerate; 637 else if (tmp < (best_framerate - framerate)) 638 best_framerate = framerate; 639 break; 640 } 641 } 642 643 return clkdiv; 644 } 645 646 static void fimd_clear_win(struct fimd_context *ctx, int win) 647 { 648 u32 val; 649 650 DRM_DEBUG_KMS("%s\n", __FILE__); 651 652 writel(0, ctx->regs + WINCON(win)); 653 writel(0, ctx->regs + VIDOSD_A(win)); 654 writel(0, ctx->regs + VIDOSD_B(win)); 655 writel(0, ctx->regs + VIDOSD_C(win)); 656 657 if (win == 1 || win == 2) 658 writel(0, ctx->regs + VIDOSD_D(win)); 659 660 val = readl(ctx->regs + SHADOWCON); 661 val &= ~SHADOWCON_WINx_PROTECT(win); 662 writel(val, ctx->regs + SHADOWCON); 663 } 664 665 static int __devinit fimd_probe(struct platform_device *pdev) 666 { 667 struct device *dev = &pdev->dev; 668 struct fimd_context *ctx; 669 struct exynos_drm_subdrv *subdrv; 670 struct exynos_drm_fimd_pdata *pdata; 671 struct fb_videomode *timing; 672 struct resource *res; 673 int win; 674 int ret = -EINVAL; 675 676 DRM_DEBUG_KMS("%s\n", __FILE__); 677 678 pdata = pdev->dev.platform_data; 679 if (!pdata) { 680 dev_err(dev, "no platform data specified\n"); 681 return -EINVAL; 682 } 683 684 timing = &pdata->timing; 685 if (!timing) { 686 dev_err(dev, "timing is null.\n"); 687 return -EINVAL; 688 } 689 690 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 691 if (!ctx) 692 return -ENOMEM; 693 694 ctx->bus_clk = clk_get(dev, "fimd"); 695 if (IS_ERR(ctx->bus_clk)) { 696 dev_err(dev, "failed to get bus clock\n"); 697 ret = PTR_ERR(ctx->bus_clk); 698 goto err_clk_get; 699 } 700 701 clk_enable(ctx->bus_clk); 702 703 ctx->lcd_clk = clk_get(dev, "sclk_fimd"); 704 if (IS_ERR(ctx->lcd_clk)) { 705 dev_err(dev, "failed to get lcd clock\n"); 706 ret = PTR_ERR(ctx->lcd_clk); 707 goto err_bus_clk; 708 } 709 710 clk_enable(ctx->lcd_clk); 711 712 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 713 if (!res) { 714 dev_err(dev, "failed to find registers\n"); 715 ret = -ENOENT; 716 goto err_clk; 717 } 718 719 ctx->regs_res = request_mem_region(res->start, resource_size(res), 720 dev_name(dev)); 721 if (!ctx->regs_res) { 722 dev_err(dev, "failed to claim register region\n"); 723 ret = -ENOENT; 724 goto err_clk; 725 } 726 727 ctx->regs = ioremap(res->start, resource_size(res)); 728 if (!ctx->regs) { 729 dev_err(dev, "failed to map registers\n"); 730 ret = -ENXIO; 731 goto err_req_region_io; 732 } 733 734 res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 735 if (!res) { 736 dev_err(dev, "irq request failed.\n"); 737 goto err_req_region_irq; 738 } 739 740 ctx->irq = res->start; 741 742 for (win = 0; win < WINDOWS_NR; win++) 743 fimd_clear_win(ctx, win); 744 745 ret = request_irq(ctx->irq, fimd_irq_handler, 0, "drm_fimd", ctx); 746 if (ret < 0) { 747 dev_err(dev, "irq request failed.\n"); 748 goto err_req_irq; 749 } 750 751 ctx->clkdiv = fimd_calc_clkdiv(ctx, timing); 752 ctx->vidcon0 = pdata->vidcon0; 753 ctx->vidcon1 = pdata->vidcon1; 754 ctx->default_win = pdata->default_win; 755 ctx->timing = timing; 756 757 timing->pixclock = clk_get_rate(ctx->lcd_clk) / ctx->clkdiv; 758 759 DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n", 760 timing->pixclock, ctx->clkdiv); 761 762 subdrv = &ctx->subdrv; 763 764 subdrv->probe = fimd_subdrv_probe; 765 subdrv->remove = fimd_subdrv_remove; 766 subdrv->manager.pipe = -1; 767 subdrv->manager.ops = &fimd_manager_ops; 768 subdrv->manager.overlay_ops = &fimd_overlay_ops; 769 subdrv->manager.display_ops = &fimd_display_ops; 770 subdrv->manager.dev = dev; 771 772 platform_set_drvdata(pdev, ctx); 773 exynos_drm_subdrv_register(subdrv); 774 775 return 0; 776 777 err_req_irq: 778 err_req_region_irq: 779 iounmap(ctx->regs); 780 781 err_req_region_io: 782 release_resource(ctx->regs_res); 783 kfree(ctx->regs_res); 784 785 err_clk: 786 clk_disable(ctx->lcd_clk); 787 clk_put(ctx->lcd_clk); 788 789 err_bus_clk: 790 clk_disable(ctx->bus_clk); 791 clk_put(ctx->bus_clk); 792 793 err_clk_get: 794 kfree(ctx); 795 return ret; 796 } 797 798 static int __devexit fimd_remove(struct platform_device *pdev) 799 { 800 struct fimd_context *ctx = platform_get_drvdata(pdev); 801 802 DRM_DEBUG_KMS("%s\n", __FILE__); 803 804 exynos_drm_subdrv_unregister(&ctx->subdrv); 805 806 clk_disable(ctx->lcd_clk); 807 clk_disable(ctx->bus_clk); 808 clk_put(ctx->lcd_clk); 809 clk_put(ctx->bus_clk); 810 811 iounmap(ctx->regs); 812 release_resource(ctx->regs_res); 813 kfree(ctx->regs_res); 814 free_irq(ctx->irq, ctx); 815 816 kfree(ctx); 817 818 return 0; 819 } 820 821 static struct platform_driver fimd_driver = { 822 .probe = fimd_probe, 823 .remove = __devexit_p(fimd_remove), 824 .driver = { 825 .name = "exynos4-fb", 826 .owner = THIS_MODULE, 827 }, 828 }; 829 830 static int __init fimd_init(void) 831 { 832 return platform_driver_register(&fimd_driver); 833 } 834 835 static void __exit fimd_exit(void) 836 { 837 platform_driver_unregister(&fimd_driver); 838 } 839 840 module_init(fimd_init); 841 module_exit(fimd_exit); 842 843 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); 844 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); 845 MODULE_DESCRIPTION("Samsung DRM FIMD Driver"); 846 MODULE_LICENSE("GPL"); 847