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 DRM_DEBUG_KMS("%s\n", __FILE__
);
100 static void *fimd_get_timing(struct device
*dev
)
102 struct fimd_context
*ctx
= get_fimd_context(dev
);
104 DRM_DEBUG_KMS("%s\n", __FILE__
);
109 static int fimd_check_timing(struct device
*dev
, void *timing
)
111 DRM_DEBUG_KMS("%s\n", __FILE__
);
118 static int fimd_display_power_on(struct device
*dev
, int mode
)
120 DRM_DEBUG_KMS("%s\n", __FILE__
);
127 static struct exynos_drm_display fimd_display
= {
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
,
135 static void fimd_commit(struct device
*dev
)
137 struct fimd_context
*ctx
= get_fimd_context(dev
);
138 struct fb_videomode
*timing
= ctx
->timing
;
141 DRM_DEBUG_KMS("%s\n", __FILE__
);
143 /* setup polarity values from machine code. */
144 writel(ctx
->vidcon1
, ctx
->regs
+ VIDCON1
);
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
);
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
);
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
);
163 /* setup clock source, clock divider, enable dma. */
165 val
&= ~(VIDCON0_CLKVAL_F_MASK
| VIDCON0_CLKDIR
);
168 val
|= VIDCON0_CLKVAL_F(ctx
->clkdiv
- 1) | VIDCON0_CLKDIR
;
170 val
&= ~VIDCON0_CLKDIR
; /* 1:1 clock */
173 * fields of register with prefix '_F' would be updated
174 * at vsync(same as dma start)
176 val
|= VIDCON0_ENVID
| VIDCON0_ENVID_F
;
177 writel(val
, ctx
->regs
+ VIDCON0
);
180 static int fimd_enable_vblank(struct device
*dev
)
182 struct fimd_context
*ctx
= get_fimd_context(dev
);
185 DRM_DEBUG_KMS("%s\n", __FILE__
);
187 if (!test_and_set_bit(0, &ctx
->irq_flags
)) {
188 val
= readl(ctx
->regs
+ VIDINTCON0
);
190 val
|= VIDINTCON0_INT_ENABLE
;
191 val
|= VIDINTCON0_INT_FRAME
;
193 val
&= ~VIDINTCON0_FRAMESEL0_MASK
;
194 val
|= VIDINTCON0_FRAMESEL0_VSYNC
;
195 val
&= ~VIDINTCON0_FRAMESEL1_MASK
;
196 val
|= VIDINTCON0_FRAMESEL1_NONE
;
198 writel(val
, ctx
->regs
+ VIDINTCON0
);
204 static void fimd_disable_vblank(struct device
*dev
)
206 struct fimd_context
*ctx
= get_fimd_context(dev
);
209 DRM_DEBUG_KMS("%s\n", __FILE__
);
211 if (test_and_clear_bit(0, &ctx
->irq_flags
)) {
212 val
= readl(ctx
->regs
+ VIDINTCON0
);
214 val
&= ~VIDINTCON0_INT_FRAME
;
215 val
&= ~VIDINTCON0_INT_ENABLE
;
217 writel(val
, ctx
->regs
+ VIDINTCON0
);
221 static struct exynos_drm_manager_ops fimd_manager_ops
= {
222 .commit
= fimd_commit
,
223 .enable_vblank
= fimd_enable_vblank
,
224 .disable_vblank
= fimd_disable_vblank
,
227 static void fimd_win_mode_set(struct device
*dev
,
228 struct exynos_drm_overlay
*overlay
)
230 struct fimd_context
*ctx
= get_fimd_context(dev
);
231 struct fimd_win_data
*win_data
;
232 unsigned long offset
;
234 DRM_DEBUG_KMS("%s\n", __FILE__
);
237 dev_err(dev
, "overlay is NULL\n");
241 offset
= overlay
->fb_x
* (overlay
->bpp
>> 3);
242 offset
+= overlay
->fb_y
* overlay
->pitch
;
244 DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset
, overlay
->pitch
);
246 win_data
= &ctx
->win_data
[ctx
->default_win
];
248 win_data
->offset_x
= overlay
->crtc_x
;
249 win_data
->offset_y
= overlay
->crtc_y
;
250 win_data
->ovl_width
= overlay
->crtc_width
;
251 win_data
->ovl_height
= overlay
->crtc_height
;
252 win_data
->fb_width
= overlay
->fb_width
;
253 win_data
->fb_height
= overlay
->fb_height
;
254 win_data
->paddr
= overlay
->paddr
+ offset
;
255 win_data
->vaddr
= overlay
->vaddr
+ offset
;
256 win_data
->bpp
= overlay
->bpp
;
257 win_data
->buf_offsize
= (overlay
->fb_width
- overlay
->crtc_width
) *
259 win_data
->line_size
= overlay
->crtc_width
* (overlay
->bpp
>> 3);
261 DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
262 win_data
->offset_x
, win_data
->offset_y
);
263 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
264 win_data
->ovl_width
, win_data
->ovl_height
);
265 DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n",
266 (unsigned long)win_data
->paddr
,
267 (unsigned long)win_data
->vaddr
);
268 DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
269 overlay
->fb_width
, overlay
->crtc_width
);
272 static void fimd_win_set_pixfmt(struct device
*dev
, unsigned int win
)
274 struct fimd_context
*ctx
= get_fimd_context(dev
);
275 struct fimd_win_data
*win_data
= &ctx
->win_data
[win
];
278 DRM_DEBUG_KMS("%s\n", __FILE__
);
282 switch (win_data
->bpp
) {
284 val
|= WINCON0_BPPMODE_1BPP
;
285 val
|= WINCONx_BITSWP
;
286 val
|= WINCONx_BURSTLEN_4WORD
;
289 val
|= WINCON0_BPPMODE_2BPP
;
290 val
|= WINCONx_BITSWP
;
291 val
|= WINCONx_BURSTLEN_8WORD
;
294 val
|= WINCON0_BPPMODE_4BPP
;
295 val
|= WINCONx_BITSWP
;
296 val
|= WINCONx_BURSTLEN_8WORD
;
299 val
|= WINCON0_BPPMODE_8BPP_PALETTE
;
300 val
|= WINCONx_BURSTLEN_8WORD
;
301 val
|= WINCONx_BYTSWP
;
304 val
|= WINCON0_BPPMODE_16BPP_565
;
305 val
|= WINCONx_HAWSWP
;
306 val
|= WINCONx_BURSTLEN_16WORD
;
309 val
|= WINCON0_BPPMODE_24BPP_888
;
311 val
|= WINCONx_BURSTLEN_16WORD
;
314 val
|= WINCON1_BPPMODE_28BPP_A4888
315 | WINCON1_BLD_PIX
| WINCON1_ALPHA_SEL
;
317 val
|= WINCONx_BURSTLEN_16WORD
;
320 DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
322 val
|= WINCON0_BPPMODE_24BPP_888
;
324 val
|= WINCONx_BURSTLEN_16WORD
;
328 DRM_DEBUG_KMS("bpp = %d\n", win_data
->bpp
);
330 writel(val
, ctx
->regs
+ WINCON(win
));
333 static void fimd_win_set_colkey(struct device
*dev
, unsigned int win
)
335 struct fimd_context
*ctx
= get_fimd_context(dev
);
336 unsigned int keycon0
= 0, keycon1
= 0;
338 DRM_DEBUG_KMS("%s\n", __FILE__
);
340 keycon0
= ~(WxKEYCON0_KEYBL_EN
| WxKEYCON0_KEYEN_F
|
341 WxKEYCON0_DIRCON
) | WxKEYCON0_COMPKEY(0);
343 keycon1
= WxKEYCON1_COLVAL(0xffffffff);
345 writel(keycon0
, ctx
->regs
+ WKEYCON0_BASE(win
));
346 writel(keycon1
, ctx
->regs
+ WKEYCON1_BASE(win
));
349 static void fimd_win_commit(struct device
*dev
)
351 struct fimd_context
*ctx
= get_fimd_context(dev
);
352 struct fimd_win_data
*win_data
;
353 int win
= ctx
->default_win
;
354 unsigned long val
, alpha
, size
;
356 DRM_DEBUG_KMS("%s\n", __FILE__
);
358 if (win
< 0 || win
> WINDOWS_NR
)
361 win_data
= &ctx
->win_data
[win
];
364 * SHADOWCON register is used for enabling timing.
366 * for example, once only width value of a register is set,
367 * if the dma is started then fimd hardware could malfunction so
368 * with protect window setting, the register fields with prefix '_F'
369 * wouldn't be updated at vsync also but updated once unprotect window
373 /* protect windows */
374 val
= readl(ctx
->regs
+ SHADOWCON
);
375 val
|= SHADOWCON_WINx_PROTECT(win
);
376 writel(val
, ctx
->regs
+ SHADOWCON
);
378 /* buffer start address */
379 val
= win_data
->paddr
;
380 writel(val
, ctx
->regs
+ VIDWx_BUF_START(win
, 0));
382 /* buffer end address */
383 size
= win_data
->fb_width
* win_data
->ovl_height
* (win_data
->bpp
>> 3);
384 val
= win_data
->paddr
+ size
;
385 writel(val
, ctx
->regs
+ VIDWx_BUF_END(win
, 0));
387 DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
388 (unsigned long)win_data
->paddr
, val
, size
);
389 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
390 win_data
->ovl_width
, win_data
->ovl_height
);
393 val
= VIDW_BUF_SIZE_OFFSET(win_data
->buf_offsize
) |
394 VIDW_BUF_SIZE_PAGEWIDTH(win_data
->line_size
);
395 writel(val
, ctx
->regs
+ VIDWx_BUF_SIZE(win
, 0));
398 val
= VIDOSDxA_TOPLEFT_X(win_data
->offset_x
) |
399 VIDOSDxA_TOPLEFT_Y(win_data
->offset_y
);
400 writel(val
, ctx
->regs
+ VIDOSD_A(win
));
402 val
= VIDOSDxB_BOTRIGHT_X(win_data
->offset_x
+
403 win_data
->ovl_width
- 1) |
404 VIDOSDxB_BOTRIGHT_Y(win_data
->offset_y
+
405 win_data
->ovl_height
- 1);
406 writel(val
, ctx
->regs
+ VIDOSD_B(win
));
408 DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
409 win_data
->offset_x
, win_data
->offset_y
,
410 win_data
->offset_x
+ win_data
->ovl_width
- 1,
411 win_data
->offset_y
+ win_data
->ovl_height
- 1);
413 /* hardware window 0 doesn't support alpha channel. */
416 alpha
= VIDISD14C_ALPHA1_R(0xf) |
417 VIDISD14C_ALPHA1_G(0xf) |
418 VIDISD14C_ALPHA1_B(0xf);
420 writel(alpha
, ctx
->regs
+ VIDOSD_C(win
));
424 if (win
!= 3 && win
!= 4) {
425 u32 offset
= VIDOSD_D(win
);
427 offset
= VIDOSD_C_SIZE_W0
;
428 val
= win_data
->ovl_width
* win_data
->ovl_height
;
429 writel(val
, ctx
->regs
+ offset
);
431 DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val
);
434 fimd_win_set_pixfmt(dev
, win
);
436 /* hardware window 0 doesn't support color key. */
438 fimd_win_set_colkey(dev
, win
);
440 /* Enable DMA channel and unprotect windows */
441 val
= readl(ctx
->regs
+ SHADOWCON
);
442 val
|= SHADOWCON_CHx_ENABLE(win
);
443 val
&= ~SHADOWCON_WINx_PROTECT(win
);
444 writel(val
, ctx
->regs
+ SHADOWCON
);
447 static void fimd_win_disable(struct device
*dev
)
449 struct fimd_context
*ctx
= get_fimd_context(dev
);
450 struct fimd_win_data
*win_data
;
451 int win
= ctx
->default_win
;
454 DRM_DEBUG_KMS("%s\n", __FILE__
);
456 if (win
< 0 || win
> WINDOWS_NR
)
459 win_data
= &ctx
->win_data
[win
];
461 /* protect windows */
462 val
= readl(ctx
->regs
+ SHADOWCON
);
463 val
|= SHADOWCON_WINx_PROTECT(win
);
464 writel(val
, ctx
->regs
+ SHADOWCON
);
467 val
= readl(ctx
->regs
+ WINCON(win
));
468 val
&= ~WINCONx_ENWIN
;
469 writel(val
, ctx
->regs
+ WINCON(win
));
471 /* unprotect windows */
472 val
= readl(ctx
->regs
+ SHADOWCON
);
473 val
&= ~SHADOWCON_CHx_ENABLE(win
);
474 val
&= ~SHADOWCON_WINx_PROTECT(win
);
475 writel(val
, ctx
->regs
+ SHADOWCON
);
478 static struct exynos_drm_overlay_ops fimd_overlay_ops
= {
479 .mode_set
= fimd_win_mode_set
,
480 .commit
= fimd_win_commit
,
481 .disable
= fimd_win_disable
,
484 static void fimd_finish_pageflip(struct drm_device
*drm_dev
, int crtc
)
486 struct exynos_drm_private
*dev_priv
= drm_dev
->dev_private
;
487 struct drm_pending_vblank_event
*e
, *t
;
490 bool is_checked
= false;
492 spin_lock_irqsave(&drm_dev
->event_lock
, flags
);
494 list_for_each_entry_safe(e
, t
, &dev_priv
->pageflip_event_list
,
496 /* if event's pipe isn't same as crtc then ignore it. */
502 do_gettimeofday(&now
);
503 e
->event
.sequence
= 0;
504 e
->event
.tv_sec
= now
.tv_sec
;
505 e
->event
.tv_usec
= now
.tv_usec
;
507 list_move_tail(&e
->base
.link
, &e
->base
.file_priv
->event_list
);
508 wake_up_interruptible(&e
->base
.file_priv
->event_wait
);
512 drm_vblank_put(drm_dev
, crtc
);
514 spin_unlock_irqrestore(&drm_dev
->event_lock
, flags
);
517 static irqreturn_t
fimd_irq_handler(int irq
, void *dev_id
)
519 struct fimd_context
*ctx
= (struct fimd_context
*)dev_id
;
520 struct exynos_drm_subdrv
*subdrv
= &ctx
->subdrv
;
521 struct drm_device
*drm_dev
= subdrv
->drm_dev
;
522 struct exynos_drm_manager
*manager
= &subdrv
->manager
;
525 val
= readl(ctx
->regs
+ VIDINTCON1
);
527 if (val
& VIDINTCON1_INT_FRAME
)
528 /* VSYNC interrupt */
529 writel(VIDINTCON1_INT_FRAME
, ctx
->regs
+ VIDINTCON1
);
531 drm_handle_vblank(drm_dev
, manager
->pipe
);
532 fimd_finish_pageflip(drm_dev
, manager
->pipe
);
537 static int fimd_subdrv_probe(struct drm_device
*drm_dev
, struct device
*dev
)
539 DRM_DEBUG_KMS("%s\n", __FILE__
);
542 * enable drm irq mode.
543 * - with irq_enabled = 1, we can use the vblank feature.
545 * P.S. note that we wouldn't use drm irq handler but
546 * just specific driver own one instead because
547 * drm framework supports only one irq handler.
549 drm_dev
->irq_enabled
= 1;
552 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
553 * by drm timer once a current process gives up ownership of
554 * vblank event.(drm_vblank_put function was called)
556 drm_dev
->vblank_disable_allowed
= 1;
561 static void fimd_subdrv_remove(struct drm_device
*drm_dev
)
563 DRM_DEBUG_KMS("%s\n", __FILE__
);
568 static int fimd_calc_clkdiv(struct fimd_context
*ctx
,
569 struct fb_videomode
*timing
)
571 unsigned long clk
= clk_get_rate(ctx
->lcd_clk
);
574 u32 best_framerate
= 0;
577 DRM_DEBUG_KMS("%s\n", __FILE__
);
579 retrace
= timing
->left_margin
+ timing
->hsync_len
+
580 timing
->right_margin
+ timing
->xres
;
581 retrace
*= timing
->upper_margin
+ timing
->vsync_len
+
582 timing
->lower_margin
+ timing
->yres
;
584 /* default framerate is 60Hz */
585 if (!timing
->refresh
)
586 timing
->refresh
= 60;
590 for (clkdiv
= 1; clkdiv
< 0x100; clkdiv
++) {
593 /* get best framerate */
594 framerate
= clk
/ clkdiv
;
595 tmp
= timing
->refresh
- framerate
;
597 best_framerate
= framerate
;
601 best_framerate
= framerate
;
602 else if (tmp
< (best_framerate
- framerate
))
603 best_framerate
= framerate
;
611 static void fimd_clear_win(struct fimd_context
*ctx
, int win
)
615 DRM_DEBUG_KMS("%s\n", __FILE__
);
617 writel(0, ctx
->regs
+ WINCON(win
));
618 writel(0, ctx
->regs
+ VIDOSD_A(win
));
619 writel(0, ctx
->regs
+ VIDOSD_B(win
));
620 writel(0, ctx
->regs
+ VIDOSD_C(win
));
622 if (win
== 1 || win
== 2)
623 writel(0, ctx
->regs
+ VIDOSD_D(win
));
625 val
= readl(ctx
->regs
+ SHADOWCON
);
626 val
&= ~SHADOWCON_WINx_PROTECT(win
);
627 writel(val
, ctx
->regs
+ SHADOWCON
);
630 static int __devinit
fimd_probe(struct platform_device
*pdev
)
632 struct device
*dev
= &pdev
->dev
;
633 struct fimd_context
*ctx
;
634 struct exynos_drm_subdrv
*subdrv
;
635 struct exynos_drm_fimd_pdata
*pdata
;
636 struct fb_videomode
*timing
;
637 struct resource
*res
;
641 DRM_DEBUG_KMS("%s\n", __FILE__
);
643 pdata
= pdev
->dev
.platform_data
;
645 dev_err(dev
, "no platform data specified\n");
649 timing
= &pdata
->timing
;
651 dev_err(dev
, "timing is null.\n");
655 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
659 ctx
->bus_clk
= clk_get(dev
, "fimd");
660 if (IS_ERR(ctx
->bus_clk
)) {
661 dev_err(dev
, "failed to get bus clock\n");
662 ret
= PTR_ERR(ctx
->bus_clk
);
666 clk_enable(ctx
->bus_clk
);
668 ctx
->lcd_clk
= clk_get(dev
, "sclk_fimd");
669 if (IS_ERR(ctx
->lcd_clk
)) {
670 dev_err(dev
, "failed to get lcd clock\n");
671 ret
= PTR_ERR(ctx
->lcd_clk
);
675 clk_enable(ctx
->lcd_clk
);
677 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
679 dev_err(dev
, "failed to find registers\n");
684 ctx
->regs_res
= request_mem_region(res
->start
, resource_size(res
),
686 if (!ctx
->regs_res
) {
687 dev_err(dev
, "failed to claim register region\n");
692 ctx
->regs
= ioremap(res
->start
, resource_size(res
));
694 dev_err(dev
, "failed to map registers\n");
696 goto err_req_region_io
;
699 res
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
701 dev_err(dev
, "irq request failed.\n");
702 goto err_req_region_irq
;
705 ctx
->irq
= res
->start
;
707 for (win
= 0; win
< WINDOWS_NR
; win
++)
708 fimd_clear_win(ctx
, win
);
710 ret
= request_irq(ctx
->irq
, fimd_irq_handler
, 0, "drm_fimd", ctx
);
712 dev_err(dev
, "irq request failed.\n");
716 ctx
->clkdiv
= fimd_calc_clkdiv(ctx
, timing
);
717 ctx
->vidcon0
= pdata
->vidcon0
;
718 ctx
->vidcon1
= pdata
->vidcon1
;
719 ctx
->default_win
= pdata
->default_win
;
720 ctx
->timing
= timing
;
722 timing
->pixclock
= clk_get_rate(ctx
->lcd_clk
) / ctx
->clkdiv
;
724 DRM_DEBUG_KMS("pixel clock = %d, clkdiv = %d\n",
725 timing
->pixclock
, ctx
->clkdiv
);
727 subdrv
= &ctx
->subdrv
;
729 subdrv
->probe
= fimd_subdrv_probe
;
730 subdrv
->remove
= fimd_subdrv_remove
;
731 subdrv
->manager
.pipe
= -1;
732 subdrv
->manager
.ops
= &fimd_manager_ops
;
733 subdrv
->manager
.overlay_ops
= &fimd_overlay_ops
;
734 subdrv
->manager
.display
= &fimd_display
;
735 subdrv
->manager
.dev
= dev
;
737 platform_set_drvdata(pdev
, ctx
);
738 exynos_drm_subdrv_register(subdrv
);
747 release_resource(ctx
->regs_res
);
748 kfree(ctx
->regs_res
);
751 clk_disable(ctx
->lcd_clk
);
752 clk_put(ctx
->lcd_clk
);
755 clk_disable(ctx
->bus_clk
);
756 clk_put(ctx
->bus_clk
);
763 static int __devexit
fimd_remove(struct platform_device
*pdev
)
765 struct fimd_context
*ctx
= platform_get_drvdata(pdev
);
767 DRM_DEBUG_KMS("%s\n", __FILE__
);
769 exynos_drm_subdrv_unregister(&ctx
->subdrv
);
771 clk_disable(ctx
->lcd_clk
);
772 clk_disable(ctx
->bus_clk
);
773 clk_put(ctx
->lcd_clk
);
774 clk_put(ctx
->bus_clk
);
777 release_resource(ctx
->regs_res
);
778 kfree(ctx
->regs_res
);
779 free_irq(ctx
->irq
, ctx
);
786 static struct platform_driver fimd_driver
= {
788 .remove
= __devexit_p(fimd_remove
),
790 .name
= "exynos4-fb",
791 .owner
= THIS_MODULE
,
795 static int __init
fimd_init(void)
797 return platform_driver_register(&fimd_driver
);
800 static void __exit
fimd_exit(void)
802 platform_driver_unregister(&fimd_driver
);
805 module_init(fimd_init
);
806 module_exit(fimd_exit
);
808 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
809 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
810 MODULE_DESCRIPTION("Samsung DRM FIMD Driver");
811 MODULE_LICENSE("GPL");