3 * Copyright (C) 2011 Samsung Electronics Co.Ltd
5 * Joonyoung Shim <jy0922.shim@samsung.com>
6 * Inki Dae <inki.dae@samsung.com>
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.
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/clk.h>
21 #include <drm/exynos_drm.h>
22 #include <plat/regs-fb-v4.h>
24 #include "exynos_drm_drv.h"
25 #include "exynos_drm_fbdev.h"
26 #include "exynos_drm_crtc.h"
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
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)
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)
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))
54 /* FIMD has totally five hardware windows. */
57 #define get_fimd_context(dev) platform_get_drvdata(to_platform_device(dev))
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
;
69 unsigned int buf_offsize
;
70 unsigned int line_size
; /* bytes */
74 struct exynos_drm_subdrv subdrv
;
76 struct drm_crtc
*crtc
;
79 struct resource
*regs_res
;
81 struct fimd_win_data win_data
[WINDOWS_NR
];
83 unsigned int default_win
;
84 unsigned long irq_flags
;
88 struct fb_videomode
*timing
;
91 static bool fimd_display_is_connected(struct device
*dev
)
93 struct fimd_context
*ctx
= get_fimd_context(dev
);
95 DRM_DEBUG_KMS("%s\n", __FILE__
);
102 static void *fimd_get_timing(struct device
*dev
)
104 struct fimd_context
*ctx
= get_fimd_context(dev
);
106 DRM_DEBUG_KMS("%s\n", __FILE__
);
111 static int fimd_check_timing(struct device
*dev
, void *timing
)
113 struct fimd_context
*ctx
= get_fimd_context(dev
);
115 DRM_DEBUG_KMS("%s\n", __FILE__
);
122 static int fimd_display_power_on(struct device
*dev
, int mode
)
124 struct fimd_context
*ctx
= get_fimd_context(dev
);
126 DRM_DEBUG_KMS("%s\n", __FILE__
);
133 static struct exynos_drm_display fimd_display
= {
134 .type
= EXYNOS_DISPLAY_TYPE_LCD
,
135 .is_connected
= fimd_display_is_connected
,
136 .get_timing
= fimd_get_timing
,
137 .check_timing
= fimd_check_timing
,
138 .power_on
= fimd_display_power_on
,
141 static void fimd_commit(struct device
*dev
)
143 struct fimd_context
*ctx
= get_fimd_context(dev
);
144 struct fb_videomode
*timing
= ctx
->timing
;
147 DRM_DEBUG_KMS("%s\n", __FILE__
);
149 /* setup polarity values from machine code. */
150 writel(ctx
->vidcon1
, ctx
->regs
+ VIDCON1
);
152 /* setup vertical timing values. */
153 val
= VIDTCON0_VBPD(timing
->upper_margin
- 1) |
154 VIDTCON0_VFPD(timing
->lower_margin
- 1) |
155 VIDTCON0_VSPW(timing
->vsync_len
- 1);
156 writel(val
, ctx
->regs
+ VIDTCON0
);
158 /* setup horizontal timing values. */
159 val
= VIDTCON1_HBPD(timing
->left_margin
- 1) |
160 VIDTCON1_HFPD(timing
->right_margin
- 1) |
161 VIDTCON1_HSPW(timing
->hsync_len
- 1);
162 writel(val
, ctx
->regs
+ VIDTCON1
);
164 /* setup horizontal and vertical display size. */
165 val
= VIDTCON2_LINEVAL(timing
->yres
- 1) |
166 VIDTCON2_HOZVAL(timing
->xres
- 1);
167 writel(val
, ctx
->regs
+ VIDTCON2
);
169 /* setup clock source, clock divider, enable dma. */
171 val
&= ~(VIDCON0_CLKVAL_F_MASK
| VIDCON0_CLKDIR
);
174 val
|= VIDCON0_CLKVAL_F(ctx
->clkdiv
- 1) | VIDCON0_CLKDIR
;
176 val
&= ~VIDCON0_CLKDIR
; /* 1:1 clock */
179 * fields of register with prefix '_F' would be updated
180 * at vsync(same as dma start)
182 val
|= VIDCON0_ENVID
| VIDCON0_ENVID_F
;
183 writel(val
, ctx
->regs
+ VIDCON0
);
186 static int fimd_enable_vblank(struct device
*dev
)
188 struct fimd_context
*ctx
= get_fimd_context(dev
);
191 DRM_DEBUG_KMS("%s\n", __FILE__
);
193 if (!test_and_set_bit(0, &ctx
->irq_flags
)) {
194 val
= readl(ctx
->regs
+ VIDINTCON0
);
196 val
|= VIDINTCON0_INT_ENABLE
;
197 val
|= VIDINTCON0_INT_FRAME
;
199 val
&= ~VIDINTCON0_FRAMESEL0_MASK
;
200 val
|= VIDINTCON0_FRAMESEL0_VSYNC
;
201 val
&= ~VIDINTCON0_FRAMESEL1_MASK
;
202 val
|= VIDINTCON0_FRAMESEL1_NONE
;
204 writel(val
, ctx
->regs
+ VIDINTCON0
);
210 static void fimd_disable_vblank(struct device
*dev
)
212 struct fimd_context
*ctx
= get_fimd_context(dev
);
215 DRM_DEBUG_KMS("%s\n", __FILE__
);
217 if (test_and_clear_bit(0, &ctx
->irq_flags
)) {
218 val
= readl(ctx
->regs
+ VIDINTCON0
);
220 val
&= ~VIDINTCON0_INT_FRAME
;
221 val
&= ~VIDINTCON0_INT_ENABLE
;
223 writel(val
, ctx
->regs
+ VIDINTCON0
);
227 static struct exynos_drm_manager_ops fimd_manager_ops
= {
228 .commit
= fimd_commit
,
229 .enable_vblank
= fimd_enable_vblank
,
230 .disable_vblank
= fimd_disable_vblank
,
233 static void fimd_win_mode_set(struct device
*dev
,
234 struct exynos_drm_overlay
*overlay
)
236 struct fimd_context
*ctx
= get_fimd_context(dev
);
237 struct fimd_win_data
*win_data
;
238 unsigned long offset
;
240 DRM_DEBUG_KMS("%s\n", __FILE__
);
243 dev_err(dev
, "overlay is NULL\n");
247 offset
= overlay
->fb_x
* (overlay
->bpp
>> 3);
248 offset
+= overlay
->fb_y
* overlay
->pitch
;
250 DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset
, overlay
->pitch
);
252 win_data
= &ctx
->win_data
[ctx
->default_win
];
254 win_data
->offset_x
= overlay
->crtc_x
;
255 win_data
->offset_y
= overlay
->crtc_y
;
256 win_data
->ovl_width
= overlay
->crtc_width
;
257 win_data
->ovl_height
= overlay
->crtc_height
;
258 win_data
->fb_width
= overlay
->fb_width
;
259 win_data
->fb_height
= overlay
->fb_height
;
260 win_data
->paddr
= overlay
->paddr
+ offset
;
261 win_data
->vaddr
= overlay
->vaddr
+ offset
;
262 win_data
->bpp
= overlay
->bpp
;
263 win_data
->buf_offsize
= (overlay
->fb_width
- overlay
->crtc_width
) *
265 win_data
->line_size
= overlay
->crtc_width
* (overlay
->bpp
>> 3);
267 DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
268 win_data
->offset_x
, win_data
->offset_y
);
269 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
270 win_data
->ovl_width
, win_data
->ovl_height
);
271 DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n",
272 (unsigned long)win_data
->paddr
,
273 (unsigned long)win_data
->vaddr
);
274 DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
275 overlay
->fb_width
, overlay
->crtc_width
);
278 static void fimd_win_set_pixfmt(struct device
*dev
, unsigned int win
)
280 struct fimd_context
*ctx
= get_fimd_context(dev
);
281 struct fimd_win_data
*win_data
= &ctx
->win_data
[win
];
284 DRM_DEBUG_KMS("%s\n", __FILE__
);
288 switch (win_data
->bpp
) {
290 val
|= WINCON0_BPPMODE_1BPP
;
291 val
|= WINCONx_BITSWP
;
292 val
|= WINCONx_BURSTLEN_4WORD
;
295 val
|= WINCON0_BPPMODE_2BPP
;
296 val
|= WINCONx_BITSWP
;
297 val
|= WINCONx_BURSTLEN_8WORD
;
300 val
|= WINCON0_BPPMODE_4BPP
;
301 val
|= WINCONx_BITSWP
;
302 val
|= WINCONx_BURSTLEN_8WORD
;
305 val
|= WINCON0_BPPMODE_8BPP_PALETTE
;
306 val
|= WINCONx_BURSTLEN_8WORD
;
307 val
|= WINCONx_BYTSWP
;
310 val
|= WINCON0_BPPMODE_16BPP_565
;
311 val
|= WINCONx_HAWSWP
;
312 val
|= WINCONx_BURSTLEN_16WORD
;
315 val
|= WINCON0_BPPMODE_24BPP_888
;
317 val
|= WINCONx_BURSTLEN_16WORD
;
320 val
|= WINCON1_BPPMODE_28BPP_A4888
321 | WINCON1_BLD_PIX
| WINCON1_ALPHA_SEL
;
323 val
|= WINCONx_BURSTLEN_16WORD
;
326 DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
328 val
|= WINCON0_BPPMODE_24BPP_888
;
330 val
|= WINCONx_BURSTLEN_16WORD
;
334 DRM_DEBUG_KMS("bpp = %d\n", win_data
->bpp
);
336 writel(val
, ctx
->regs
+ WINCON(win
));
339 static void fimd_win_set_colkey(struct device
*dev
, unsigned int win
)
341 struct fimd_context
*ctx
= get_fimd_context(dev
);
342 unsigned int keycon0
= 0, keycon1
= 0;
344 DRM_DEBUG_KMS("%s\n", __FILE__
);
346 keycon0
= ~(WxKEYCON0_KEYBL_EN
| WxKEYCON0_KEYEN_F
|
347 WxKEYCON0_DIRCON
) | WxKEYCON0_COMPKEY(0);
349 keycon1
= WxKEYCON1_COLVAL(0xffffffff);
351 writel(keycon0
, ctx
->regs
+ WKEYCON0_BASE(win
));
352 writel(keycon1
, ctx
->regs
+ WKEYCON1_BASE(win
));
355 static void fimd_win_commit(struct device
*dev
)
357 struct fimd_context
*ctx
= get_fimd_context(dev
);
358 struct fimd_win_data
*win_data
;
359 int win
= ctx
->default_win
;
360 unsigned long val
, alpha
, size
;
362 DRM_DEBUG_KMS("%s\n", __FILE__
);
364 if (win
< 0 || win
> WINDOWS_NR
)
367 win_data
= &ctx
->win_data
[win
];
370 * SHADOWCON register is used for enabling timing.
372 * for example, once only width value of a register is set,
373 * if the dma is started then fimd hardware could malfunction so
374 * with protect window setting, the register fields with prefix '_F'
375 * wouldn't be updated at vsync also but updated once unprotect window
379 /* protect windows */
380 val
= readl(ctx
->regs
+ SHADOWCON
);
381 val
|= SHADOWCON_WINx_PROTECT(win
);
382 writel(val
, ctx
->regs
+ SHADOWCON
);
384 /* buffer start address */
385 val
= win_data
->paddr
;
386 writel(val
, ctx
->regs
+ VIDWx_BUF_START(win
, 0));
388 /* buffer end address */
389 size
= win_data
->fb_width
* win_data
->ovl_height
* (win_data
->bpp
>> 3);
390 val
= win_data
->paddr
+ size
;
391 writel(val
, ctx
->regs
+ VIDWx_BUF_END(win
, 0));
393 DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
394 (unsigned long)win_data
->paddr
, val
, size
);
395 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
396 win_data
->ovl_width
, win_data
->ovl_height
);
399 val
= VIDW_BUF_SIZE_OFFSET(win_data
->buf_offsize
) |
400 VIDW_BUF_SIZE_PAGEWIDTH(win_data
->line_size
);
401 writel(val
, ctx
->regs
+ VIDWx_BUF_SIZE(win
, 0));
404 val
= VIDOSDxA_TOPLEFT_X(win_data
->offset_x
) |
405 VIDOSDxA_TOPLEFT_Y(win_data
->offset_y
);
406 writel(val
, ctx
->regs
+ VIDOSD_A(win
));
408 val
= VIDOSDxB_BOTRIGHT_X(win_data
->offset_x
+
409 win_data
->ovl_width
- 1) |
410 VIDOSDxB_BOTRIGHT_Y(win_data
->offset_y
+
411 win_data
->ovl_height
- 1);
412 writel(val
, ctx
->regs
+ VIDOSD_B(win
));
414 DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
415 win_data
->offset_x
, win_data
->offset_y
,
416 win_data
->offset_x
+ win_data
->ovl_width
- 1,
417 win_data
->offset_y
+ win_data
->ovl_height
- 1);
419 /* hardware window 0 doesn't support alpha channel. */
422 alpha
= VIDISD14C_ALPHA1_R(0xf) |
423 VIDISD14C_ALPHA1_G(0xf) |
424 VIDISD14C_ALPHA1_B(0xf);
426 writel(alpha
, ctx
->regs
+ VIDOSD_C(win
));
430 if (win
!= 3 && win
!= 4) {
431 u32 offset
= VIDOSD_D(win
);
433 offset
= VIDOSD_C_SIZE_W0
;
434 val
= win_data
->ovl_width
* win_data
->ovl_height
;
435 writel(val
, ctx
->regs
+ offset
);
437 DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val
);
440 fimd_win_set_pixfmt(dev
, win
);
442 /* hardware window 0 doesn't support color key. */
444 fimd_win_set_colkey(dev
, win
);
446 /* Enable DMA channel and unprotect windows */
447 val
= readl(ctx
->regs
+ SHADOWCON
);
448 val
|= SHADOWCON_CHx_ENABLE(win
);
449 val
&= ~SHADOWCON_WINx_PROTECT(win
);
450 writel(val
, ctx
->regs
+ SHADOWCON
);
453 static void fimd_win_disable(struct device
*dev
)
455 struct fimd_context
*ctx
= get_fimd_context(dev
);
456 struct fimd_win_data
*win_data
;
457 int win
= ctx
->default_win
;
460 DRM_DEBUG_KMS("%s\n", __FILE__
);
462 if (win
< 0 || win
> WINDOWS_NR
)
465 win_data
= &ctx
->win_data
[win
];
467 /* protect windows */
468 val
= readl(ctx
->regs
+ SHADOWCON
);
469 val
|= SHADOWCON_WINx_PROTECT(win
);
470 writel(val
, ctx
->regs
+ SHADOWCON
);
473 val
= readl(ctx
->regs
+ WINCON(win
));
474 val
&= ~WINCONx_ENWIN
;
475 writel(val
, ctx
->regs
+ WINCON(win
));
477 /* unprotect windows */
478 val
= readl(ctx
->regs
+ SHADOWCON
);
479 val
&= ~SHADOWCON_CHx_ENABLE(win
);
480 val
&= ~SHADOWCON_WINx_PROTECT(win
);
481 writel(val
, ctx
->regs
+ SHADOWCON
);
484 static struct exynos_drm_overlay_ops fimd_overlay_ops
= {
485 .mode_set
= fimd_win_mode_set
,
486 .commit
= fimd_win_commit
,
487 .disable
= fimd_win_disable
,
490 /* for pageflip event */
491 static void fimd_finish_pageflip(struct drm_device
*drm_dev
, int crtc
)
493 struct exynos_drm_private
*dev_priv
= drm_dev
->dev_private
;
494 struct drm_pending_vblank_event
*e
, *t
;
498 if (!dev_priv
->pageflip_event
)
501 spin_lock_irqsave(&drm_dev
->event_lock
, flags
);
503 list_for_each_entry_safe(e
, t
, &dev_priv
->pageflip_event_list
,
505 do_gettimeofday(&now
);
506 e
->event
.sequence
= 0;
507 e
->event
.tv_sec
= now
.tv_sec
;
508 e
->event
.tv_usec
= now
.tv_usec
;
510 list_move_tail(&e
->base
.link
, &e
->base
.file_priv
->event_list
);
511 wake_up_interruptible(&e
->base
.file_priv
->event_wait
);
514 drm_vblank_put(drm_dev
, crtc
);
515 dev_priv
->pageflip_event
= false;
517 spin_unlock_irqrestore(&drm_dev
->event_lock
, flags
);
520 static irqreturn_t
fimd_irq_handler(int irq
, void *dev_id
)
522 struct fimd_context
*ctx
= (struct fimd_context
*)dev_id
;
523 struct exynos_drm_subdrv
*subdrv
= &ctx
->subdrv
;
524 struct drm_device
*drm_dev
= subdrv
->drm_dev
;
525 struct device
*dev
= subdrv
->manager
.dev
;
526 struct exynos_drm_manager
*manager
= &subdrv
->manager
;
529 val
= readl(ctx
->regs
+ VIDINTCON1
);
531 if (val
& VIDINTCON1_INT_FRAME
)
532 /* VSYNC interrupt */
533 writel(VIDINTCON1_INT_FRAME
, ctx
->regs
+ VIDINTCON1
);
535 drm_handle_vblank(drm_dev
, manager
->pipe
);
536 fimd_finish_pageflip(drm_dev
, manager
->pipe
);
541 static int fimd_subdrv_probe(struct drm_device
*drm_dev
, struct device
*dev
)
543 struct drm_driver
*drm_driver
= drm_dev
->driver
;
545 DRM_DEBUG_KMS("%s\n", __FILE__
);
548 * enable drm irq mode.
549 * - with irq_enabled = 1, we can use the vblank feature.
551 * P.S. note that we wouldn't use drm irq handler but
552 * just specific driver own one instead because
553 * drm framework supports only one irq handler.
555 drm_dev
->irq_enabled
= 1;
558 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
559 * by drm timer once a current process gives up ownership of
560 * vblank event.(drm_vblank_put function was called)
562 drm_dev
->vblank_disable_allowed
= 1;
567 static void fimd_subdrv_remove(struct drm_device
*drm_dev
)
569 struct drm_driver
*drm_driver
= drm_dev
->driver
;
571 DRM_DEBUG_KMS("%s\n", __FILE__
);
576 static int fimd_calc_clkdiv(struct fimd_context
*ctx
,
577 struct fb_videomode
*timing
)
579 unsigned long clk
= clk_get_rate(ctx
->lcd_clk
);
582 u32 best_framerate
= 0;
585 DRM_DEBUG_KMS("%s\n", __FILE__
);
587 retrace
= timing
->left_margin
+ timing
->hsync_len
+
588 timing
->right_margin
+ timing
->xres
;
589 retrace
*= timing
->upper_margin
+ timing
->vsync_len
+
590 timing
->lower_margin
+ timing
->yres
;
592 /* default framerate is 60Hz */
593 if (!timing
->refresh
)
594 timing
->refresh
= 60;
598 for (clkdiv
= 1; clkdiv
< 0x100; clkdiv
++) {
601 /* get best framerate */
602 framerate
= clk
/ clkdiv
;
603 tmp
= timing
->refresh
- framerate
;
605 best_framerate
= framerate
;
609 best_framerate
= framerate
;
610 else if (tmp
< (best_framerate
- framerate
))
611 best_framerate
= framerate
;
619 static void fimd_clear_win(struct fimd_context
*ctx
, int win
)
623 DRM_DEBUG_KMS("%s\n", __FILE__
);
625 writel(0, ctx
->regs
+ WINCON(win
));
626 writel(0, ctx
->regs
+ VIDOSD_A(win
));
627 writel(0, ctx
->regs
+ VIDOSD_B(win
));
628 writel(0, ctx
->regs
+ VIDOSD_C(win
));
630 if (win
== 1 || win
== 2)
631 writel(0, ctx
->regs
+ VIDOSD_D(win
));
633 val
= readl(ctx
->regs
+ SHADOWCON
);
634 val
&= ~SHADOWCON_WINx_PROTECT(win
);
635 writel(val
, ctx
->regs
+ SHADOWCON
);
638 static int __devinit
fimd_probe(struct platform_device
*pdev
)
640 struct device
*dev
= &pdev
->dev
;
641 struct fimd_context
*ctx
;
642 struct exynos_drm_subdrv
*subdrv
;
643 struct exynos_drm_fimd_pdata
*pdata
;
644 struct fb_videomode
*timing
;
645 struct resource
*res
;
649 DRM_DEBUG_KMS("%s\n", __FILE__
);
651 pdata
= pdev
->dev
.platform_data
;
653 dev_err(dev
, "no platform data specified\n");
657 timing
= &pdata
->timing
;
659 dev_err(dev
, "timing is null.\n");
663 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
667 ctx
->bus_clk
= clk_get(dev
, "fimd");
668 if (IS_ERR(ctx
->bus_clk
)) {
669 dev_err(dev
, "failed to get bus clock\n");
670 ret
= PTR_ERR(ctx
->bus_clk
);
674 clk_enable(ctx
->bus_clk
);
676 ctx
->lcd_clk
= clk_get(dev
, "sclk_fimd");
677 if (IS_ERR(ctx
->lcd_clk
)) {
678 dev_err(dev
, "failed to get lcd clock\n");
679 ret
= PTR_ERR(ctx
->lcd_clk
);
683 clk_enable(ctx
->lcd_clk
);
685 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
687 dev_err(dev
, "failed to find registers\n");
692 ctx
->regs_res
= request_mem_region(res
->start
, resource_size(res
),
694 if (!ctx
->regs_res
) {
695 dev_err(dev
, "failed to claim register region\n");
700 ctx
->regs
= ioremap(res
->start
, resource_size(res
));
702 dev_err(dev
, "failed to map registers\n");
704 goto err_req_region_io
;
707 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
709 dev_err(dev
, "irq request failed.\n");
710 goto err_req_region_irq
;
713 ctx
->irq
= res
->start
;
715 for (win
= 0; win
< WINDOWS_NR
; win
++)
716 fimd_clear_win(ctx
, win
);
718 ret
= request_irq(ctx
->irq
, fimd_irq_handler
, 0, "drm_fimd", ctx
);
720 dev_err(dev
, "irq request failed.\n");
724 ctx
->clkdiv
= fimd_calc_clkdiv(ctx
, timing
);
725 ctx
->vidcon0
= pdata
->vidcon0
;
726 ctx
->vidcon1
= pdata
->vidcon1
;
727 ctx
->default_win
= pdata
->default_win
;
728 ctx
->timing
= timing
;
730 timing
->pixclock
= clk_get_rate(ctx
->lcd_clk
) / ctx
->clkdiv
;
732 DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n",
733 timing
->pixclock
, ctx
->clkdiv
);
735 subdrv
= &ctx
->subdrv
;
737 subdrv
->probe
= fimd_subdrv_probe
;
738 subdrv
->remove
= fimd_subdrv_remove
;
739 subdrv
->manager
.pipe
= -1;
740 subdrv
->manager
.ops
= &fimd_manager_ops
;
741 subdrv
->manager
.overlay_ops
= &fimd_overlay_ops
;
742 subdrv
->manager
.display
= &fimd_display
;
743 subdrv
->manager
.dev
= dev
;
745 platform_set_drvdata(pdev
, ctx
);
746 exynos_drm_subdrv_register(subdrv
);
755 release_resource(ctx
->regs_res
);
756 kfree(ctx
->regs_res
);
759 clk_disable(ctx
->lcd_clk
);
760 clk_put(ctx
->lcd_clk
);
763 clk_disable(ctx
->bus_clk
);
764 clk_put(ctx
->bus_clk
);
771 static int __devexit
fimd_remove(struct platform_device
*pdev
)
773 struct fimd_context
*ctx
= platform_get_drvdata(pdev
);
775 DRM_DEBUG_KMS("%s\n", __FILE__
);
777 exynos_drm_subdrv_unregister(&ctx
->subdrv
);
779 clk_disable(ctx
->lcd_clk
);
780 clk_disable(ctx
->bus_clk
);
781 clk_put(ctx
->lcd_clk
);
782 clk_put(ctx
->bus_clk
);
785 release_resource(ctx
->regs_res
);
786 kfree(ctx
->regs_res
);
787 free_irq(ctx
->irq
, ctx
);
794 static struct platform_driver fimd_driver
= {
796 .remove
= __devexit_p(fimd_remove
),
798 .name
= "exynos4-fb",
799 .owner
= THIS_MODULE
,
803 static int __init
fimd_init(void)
805 return platform_driver_register(&fimd_driver
);
808 static void __exit
fimd_exit(void)
810 platform_driver_unregister(&fimd_driver
);
813 module_init(fimd_init
);
814 module_exit(fimd_exit
);
816 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
817 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
818 MODULE_DESCRIPTION("Samsung DRM FIMD Driver");
819 MODULE_LICENSE("GPL");