e81ee85484330df1ea4102b4893b1554209848d5
[cascardo/linux.git] / drivers / gpu / drm / exynos / exynos_drm_fimd.c
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_dp_core.h"
25 #include "exynos_drm_drv.h"
26 #include "exynos_drm_crtc.h"
27 #include "exynos_drm_fbdev.h"
28 #include "exynos_drm_display.h"
29
30 /*
31  * FIMD is stand for Fully Interactive Mobile Display and
32  * as a display controller, it transfers contents drawn on memory
33  * to a LCD Panel through Display Interfaces such as RGB or
34  * CPU Interface.
35  */
36
37 /* position control register for hardware window 0, 2 ~ 4.*/
38 #define VIDOSD_A(win)           (VIDOSD_BASE + 0x00 + (win) * 16)
39 #define VIDOSD_B(win)           (VIDOSD_BASE + 0x04 + (win) * 16)
40 /* size control register for hardware window 0. */
41 #define VIDOSD_C_SIZE_W0        (VIDOSD_BASE + 0x08)
42 /* alpha control register for hardware window 1 ~ 4. */
43 #define VIDOSD_C(win)           (VIDOSD_BASE + 0x18 + (win) * 16)
44 /* size control register for hardware window 1 ~ 4. */
45 #define VIDOSD_D(win)           (VIDOSD_BASE + 0x0C + (win) * 16)
46
47 #define VIDWx_BUF_START(win, buf)       (VIDW_BUF_START(buf) + (win) * 8)
48 #define VIDWx_BUF_END(win, buf)         (VIDW_BUF_END(buf) + (win) * 8)
49 #define VIDWx_BUF_SIZE(win, buf)        (VIDW_BUF_SIZE(buf) + (win) * 4)
50
51 /* color key control register for hardware window 1 ~ 4. */
52 #define WKEYCON0_BASE(x)                ((WKEYCON0 + 0x140) + (x * 8))
53 /* color key value register for hardware window 1 ~ 4. */
54 #define WKEYCON1_BASE(x)                ((WKEYCON1 + 0x140) + (x * 8))
55
56 /* FIMD has totally five hardware windows. */
57 #define WINDOWS_NR      5
58
59 #define get_fimd_context(dev)   platform_get_drvdata(to_platform_device(dev))
60
61 struct fimd_win_data {
62         unsigned int            offset_x;
63         unsigned int            offset_y;
64         unsigned int            ovl_width;
65         unsigned int            ovl_height;
66         unsigned int            fb_width;
67         unsigned int            fb_height;
68         unsigned int            fb_pitch;
69         unsigned int            bpp;
70
71         /*
72          * TODO(seanpaul): These fields only really make sense for the 'default
73          * window', but we go through the same path for updating a plane as we
74          * do for setting the crtc mode. If/when/once these are decoupled, this
75          * code should be refactored to seperate plane/overlay/window settings
76          * with crtc settings.
77          */
78         unsigned int            hsync_len;
79         unsigned int            hmargin;
80         unsigned int            vsync_len;
81         unsigned int            vmargin;
82
83         dma_addr_t              dma_addr;
84         void __iomem            *vaddr;
85         unsigned int            buf_offsize;
86         unsigned int            line_size;      /* bytes */
87         bool                    enabled;
88         bool                    win_suspended;
89 };
90
91 struct fimd_context {
92         struct drm_device               *drm_dev;
93         enum disp_panel_type            panel_type;
94         int                             pipe;
95         int                             irq;
96         struct drm_crtc                 *crtc;
97         struct clk                      *bus_clk;
98         struct clk                      *lcd_clk;
99         struct resource                 *regs_res;
100         void __iomem                    *regs;
101         void __iomem                    *regs_mie;
102         struct fimd_win_data            win_data[WINDOWS_NR];
103         unsigned int                    default_win;
104         unsigned long                   irq_flags;
105         u32                             vidcon0;
106         u32                             vidcon1;
107         bool                            suspended;
108         struct mutex                    lock;
109         u32                             clkdiv;
110
111         struct exynos_drm_panel_info *panel;
112 };
113
114 static struct exynos_drm_panel_info *fimd_get_panel(void *ctx)
115 {
116         struct fimd_context *fimd_ctx = ctx;
117
118         DRM_DEBUG_KMS("%s\n", __FILE__);
119
120         return fimd_ctx->panel;
121 }
122
123 static int fimd_power_on(struct fimd_context *ctx, bool enable);
124
125 static int fimd_power(void *ctx, int mode)
126 {
127         struct fimd_context *fimd_ctx = ctx;
128         bool enable;
129
130         DRM_DEBUG_KMS("%s\n", __FILE__);
131
132         switch (mode) {
133         case DRM_MODE_DPMS_ON:
134                 enable = true;
135                 break;
136         case DRM_MODE_DPMS_STANDBY:
137         case DRM_MODE_DPMS_SUSPEND:
138         case DRM_MODE_DPMS_OFF:
139                 enable = false;
140                 break;
141         default:
142                 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
143                 return -EINVAL;
144         }
145
146         fimd_power_on(fimd_ctx, enable);
147
148         return 0;
149 }
150
151 static void fimd_commit(void *ctx)
152 {
153         struct fimd_context *fimd_ctx = ctx;
154         struct fimd_win_data *win_data;
155         u32 val;
156
157         if (fimd_ctx->suspended)
158                 return;
159         win_data = &fimd_ctx->win_data[fimd_ctx->default_win];
160
161         if (!win_data->ovl_width || !win_data->ovl_height)
162                 return;
163
164         DRM_DEBUG_KMS("%s\n", __FILE__);
165
166         /* setup polarity values from machine code. */
167         writel(fimd_ctx->vidcon1, fimd_ctx->regs + VIDCON1);
168
169         /* setup vertical timing values. */
170         val = VIDTCON0_VBPD(win_data->vmargin - 1) |
171                 VIDTCON0_VFPD(win_data->vmargin - 1) |
172                 VIDTCON0_VSPW(win_data->vsync_len - 1);
173         writel(val, fimd_ctx->regs + VIDTCON0);
174
175         /* setup horizontal timing values.  */
176         val = VIDTCON1_HBPD(win_data->hmargin - 1) |
177                 VIDTCON1_HFPD(win_data->hmargin - 1) |
178                 VIDTCON1_HSPW(win_data->hsync_len - 1);
179         writel(val, fimd_ctx->regs + VIDTCON1);
180
181         /* setup horizontal and vertical display size. */
182         val = VIDTCON2_LINEVAL(win_data->ovl_height - 1) |
183                VIDTCON2_HOZVAL(win_data->ovl_width - 1);
184         writel(val, fimd_ctx->regs + VIDTCON2);
185
186         /* setup clock source, clock divider, enable dma. */
187         val = fimd_ctx->vidcon0;
188         val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
189
190         if (fimd_ctx->clkdiv)
191                 val |= VIDCON0_CLKVAL_F(fimd_ctx->clkdiv - 1) | VIDCON0_CLKDIR;
192         else
193                 val &= ~VIDCON0_CLKDIR; /* 1:1 clock */
194
195         /*
196          * fields of register with prefix '_F' would be updated
197          * at vsync(same as dma start)
198          */
199         val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
200         writel(val, fimd_ctx->regs + VIDCON0);
201 }
202
203 static int fimd_enable_vblank(void *ctx, int pipe)
204 {
205         struct fimd_context *fimd_ctx = ctx;
206         u32 val;
207
208         DRM_DEBUG_KMS("%s\n", __FILE__);
209
210         fimd_ctx->pipe = pipe;
211
212         if (fimd_ctx->suspended)
213                 return -EPERM;
214
215         if (!test_and_set_bit(0, &fimd_ctx->irq_flags)) {
216                 val = readl(fimd_ctx->regs + VIDINTCON0);
217
218                 val |= VIDINTCON0_INT_ENABLE;
219                 val |= VIDINTCON0_INT_FRAME;
220
221                 val &= ~VIDINTCON0_FRAMESEL0_MASK;
222                 val |= VIDINTCON0_FRAMESEL0_VSYNC;
223                 val &= ~VIDINTCON0_FRAMESEL1_MASK;
224                 val |= VIDINTCON0_FRAMESEL1_NONE;
225
226                 writel(val, fimd_ctx->regs + VIDINTCON0);
227         }
228
229         return 0;
230 }
231
232 static void fimd_disable_vblank(void *ctx)
233 {
234         struct fimd_context *fimd_ctx = ctx;
235         u32 val;
236
237         DRM_DEBUG_KMS("%s\n", __FILE__);
238
239         if (fimd_ctx->suspended)
240                 return;
241
242         if (test_and_clear_bit(0, &fimd_ctx->irq_flags)) {
243                 val = readl(fimd_ctx->regs + VIDINTCON0);
244
245                 val &= ~VIDINTCON0_INT_FRAME;
246                 val &= ~VIDINTCON0_INT_ENABLE;
247
248                 writel(val, fimd_ctx->regs + VIDINTCON0);
249         }
250 }
251
252 static int fimd_calc_clkdiv(struct fimd_context *fimd_ctx,
253                             struct fimd_win_data *win_data,
254                             int refresh)
255 {
256         unsigned long clk = clk_get_rate(fimd_ctx->lcd_clk);
257         u32 retrace;
258         u32 clkdiv;
259         u32 best_framerate = 0;
260         u32 framerate;
261
262         DRM_DEBUG_KMS("%s\n", __FILE__);
263
264         retrace = win_data->hmargin * 2 + win_data->hsync_len +
265                                 win_data->ovl_width;
266         retrace *= win_data->vmargin * 2 + win_data->vsync_len +
267                                 win_data->ovl_height;
268
269         /* default framerate is 60Hz */
270         if (!refresh)
271                 refresh = 60;
272
273         clk /= retrace;
274
275         for (clkdiv = 1; clkdiv < 0x100; clkdiv++) {
276                 int tmp;
277
278                 /* get best framerate */
279                 framerate = clk / clkdiv;
280                 tmp = refresh - framerate;
281                 if (tmp < 0) {
282                         best_framerate = framerate;
283                         continue;
284                 } else {
285                         if (!best_framerate)
286                                 best_framerate = framerate;
287                         else if (tmp < (best_framerate - framerate))
288                                 best_framerate = framerate;
289                         break;
290                 }
291         }
292         return clkdiv;
293 }
294
295 static void fimd_win_mode_set(void *ctx, struct exynos_drm_overlay *overlay)
296 {
297         struct fimd_context *fimd_ctx = ctx;
298         struct fimd_win_data *win_data;
299         int win;
300         unsigned long offset;
301
302         DRM_DEBUG_KMS("%s\n", __FILE__);
303
304         if (!overlay) {
305                 DRM_ERROR("overlay is NULL\n");
306                 return;
307         }
308
309         win = overlay->zpos;
310         if (win == DEFAULT_ZPOS)
311                 win = fimd_ctx->default_win;
312
313         if (win < 0 || win > WINDOWS_NR)
314                 return;
315
316         offset = overlay->fb_x * (overlay->bpp >> 3);
317         offset += overlay->fb_y * overlay->fb_pitch;
318
319         DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n",
320                 offset, overlay->fb_pitch);
321
322         win_data = &fimd_ctx->win_data[win];
323
324         win_data->offset_x = overlay->crtc_x;
325         win_data->offset_y = overlay->crtc_y;
326         win_data->ovl_width = overlay->crtc_width;
327         win_data->ovl_height = overlay->crtc_height;
328         win_data->fb_width = overlay->fb_width;
329         win_data->fb_height = overlay->fb_height;
330         win_data->fb_pitch = overlay->fb_pitch;
331         win_data->hsync_len = overlay->crtc_hsync_len;
332         win_data->hmargin = (overlay->crtc_htotal - overlay->crtc_width -
333                                 overlay->crtc_hsync_len) / 2;
334         win_data->vsync_len = overlay->crtc_vsync_len;
335         win_data->vmargin = (overlay->crtc_vtotal - overlay->crtc_height -
336                                 overlay->crtc_vsync_len) / 2;
337         win_data->dma_addr = overlay->dma_addr[0] + offset;
338         win_data->vaddr = overlay->vaddr[0] + offset;
339         win_data->bpp = overlay->bpp;
340         win_data->buf_offsize = overlay->fb_pitch -
341                 (overlay->fb_width * (overlay->bpp >> 3));
342         win_data->line_size = overlay->fb_width * (overlay->bpp >> 3);
343
344         if (win == fimd_ctx->default_win)
345                 fimd_ctx->clkdiv = fimd_calc_clkdiv(fimd_ctx, win_data,
346                                         overlay->refresh);
347
348         DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
349                         win_data->offset_x, win_data->offset_y);
350         DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
351                         win_data->ovl_width, win_data->ovl_height);
352         DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n",
353                         (unsigned long)win_data->dma_addr,
354                         (unsigned long)win_data->vaddr);
355         DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
356                         overlay->fb_width, overlay->crtc_width);
357 }
358
359 static void fimd_win_set_pixfmt(struct fimd_context *fimd_ctx, unsigned int win)
360 {
361         struct fimd_win_data *win_data = &fimd_ctx->win_data[win];
362         unsigned long val;
363         unsigned long bytes;
364
365         DRM_DEBUG_KMS("%s\n", __FILE__);
366
367         val = WINCONx_ENWIN;
368
369         switch (win_data->bpp) {
370         case 1:
371                 val |= WINCON0_BPPMODE_1BPP;
372                 val |= WINCONx_BITSWP;
373                 bytes = win_data->fb_width >> 3;
374                 break;
375         case 2:
376                 val |= WINCON0_BPPMODE_2BPP;
377                 val |= WINCONx_BITSWP;
378                 bytes = win_data->fb_width >> 2;
379                 break;
380         case 4:
381                 val |= WINCON0_BPPMODE_4BPP;
382                 val |= WINCONx_BITSWP;
383                 bytes = win_data->fb_width >> 1;
384                 break;
385         case 8:
386                 val |= WINCON0_BPPMODE_8BPP_PALETTE;
387                 val |= WINCONx_BYTSWP;
388                 bytes = win_data->fb_width;
389                 break;
390         case 16:
391                 val |= WINCON0_BPPMODE_16BPP_565;
392                 val |= WINCONx_HAWSWP;
393                 bytes = win_data->fb_width << 1;
394                 break;
395         case 24:
396                 val |= WINCON0_BPPMODE_24BPP_888;
397                 val |= WINCONx_WSWP;
398                 bytes = win_data->fb_width * 3;
399                 break;
400         case 32:
401                 val |= WINCON1_BPPMODE_28BPP_A4888
402                         | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
403                 val |= WINCONx_WSWP;
404                 bytes = win_data->fb_width << 2;
405                 break;
406         default:
407                 DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
408                 bytes = win_data->fb_width * 3;
409                 val |= WINCON0_BPPMODE_24BPP_888;
410                 val |= WINCONx_WSWP;
411                 break;
412         }
413
414         /*
415          * Adjust the burst size based on the number of bytes to be read.
416          * Each WORD of the BURST is 8 bytes long. There are 3 BURST sizes
417          * supported by fimd.
418          * WINCONx_BURSTLEN_4WORD = 32 bytes
419          * WINCONx_BURSTLEN_8WORD = 64 bytes
420          * WINCONx_BURSTLEN_16WORD = 128 bytes
421          */
422         if (win_data->fb_width <= 64)
423                 val |= WINCONx_BURSTLEN_4WORD;
424         else
425                 val |= WINCONx_BURSTLEN_16WORD;
426
427         DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
428
429         writel(val, fimd_ctx->regs + WINCON(win));
430 }
431
432 static void fimd_win_set_colkey(struct fimd_context *fimd_ctx, unsigned int win)
433 {
434         unsigned int keycon0 = 0, keycon1 = 0;
435
436         DRM_DEBUG_KMS("%s\n", __FILE__);
437
438         keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
439                         WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
440
441         keycon1 = WxKEYCON1_COLVAL(0xffffffff);
442
443         writel(keycon0, fimd_ctx->regs + WKEYCON0_BASE(win));
444         writel(keycon1, fimd_ctx->regs + WKEYCON1_BASE(win));
445 }
446
447 static void mie_set_6bit_dithering(struct fimd_context *ctx, int win)
448 {
449         struct fimd_win_data *win_data = &ctx->win_data[win];
450         unsigned long val;
451         unsigned int width, height;
452         int i;
453
454         width = win_data->ovl_width;
455         height = win_data->ovl_height;
456
457         writel(MIE_HRESOL(width) | MIE_VRESOL(height) | MIE_MODE_UI,
458                         ctx->regs_mie + MIE_CTRL1);
459
460         writel(MIE_WINHADDR0(0) | MIE_WINHADDR1(width),
461                         ctx->regs_mie + MIE_WINHADDR);
462         writel(MIE_WINVADDR0(0) | MIE_WINVADDR1(height),
463                         ctx->regs_mie + MIE_WINVADDR);
464
465         val = (width + win_data->hmargin * 2 + win_data->hsync_len) *
466                         (height + win_data->vmargin * 2 + win_data->vsync_len) /
467                         (MIE_PWMCLKVAL + 1);
468
469         writel(PWMCLKCNT(val), ctx->regs_mie + MIE_PWMCLKCNT);
470
471         writel((MIE_VBPD(win_data->vmargin)) | MIE_VFPD(win_data->vmargin) |
472                 MIE_VSPW(win_data->vsync_len), ctx->regs_mie + MIE_PWMVIDTCON1);
473
474         writel(MIE_HBPD(win_data->hmargin) | MIE_HFPD(win_data->hmargin) |
475                 MIE_HSPW(win_data->hsync_len), ctx->regs_mie + MIE_PWMVIDTCON2);
476
477         writel(MIE_DITHCON_EN | MIE_RGB6MODE, ctx->regs_mie + MIE_AUXCON);
478
479         /* Bypass MIE image brightness enhancement */
480         for (i = 0; i <= 0x30; i += 4) {
481                 writel(0, ctx->regs_mie + 0x100 + i);
482                 writel(0, ctx->regs_mie + 0x200 + i);
483         }
484 }
485
486 static void fimd_win_commit(void *ctx, int zpos)
487 {
488         struct fimd_context *fimd_ctx = ctx;
489         struct fimd_win_data *win_data;
490         int win = zpos;
491         unsigned long val, alpha, size;
492
493         DRM_DEBUG_KMS("%s\n", __FILE__);
494
495         if (fimd_ctx->suspended)
496                 return;
497
498         if (win == DEFAULT_ZPOS)
499                 win = fimd_ctx->default_win;
500
501         if (win < 0 || win > WINDOWS_NR)
502                 return;
503
504         win_data = &fimd_ctx->win_data[win];
505
506         /*
507          * SHADOWCON register is used for enabling timing.
508          *
509          * for example, once only width value of a register is set,
510          * if the dma is started then fimd hardware could malfunction so
511          * with protect window setting, the register fields with prefix '_F'
512          * wouldn't be updated at vsync also but updated once unprotect window
513          * is set.
514          */
515
516         /* protect windows */
517         val = readl(fimd_ctx->regs + SHADOWCON);
518         val |= SHADOWCON_WINx_PROTECT(win);
519         writel(val, fimd_ctx->regs + SHADOWCON);
520
521         /* buffer start address */
522         val = (unsigned long)win_data->dma_addr;
523         writel(val, fimd_ctx->regs + VIDWx_BUF_START(win, 0));
524
525         /* buffer end address */
526         size = win_data->fb_height * win_data->fb_pitch;
527         val = (unsigned long)(win_data->dma_addr + size);
528         writel(val, fimd_ctx->regs + VIDWx_BUF_END(win, 0));
529
530         DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
531                         (unsigned long)win_data->dma_addr, val, size);
532         DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
533                         win_data->ovl_width, win_data->ovl_height);
534
535         /* buffer size */
536         val = VIDW_BUF_SIZE_OFFSET(win_data->buf_offsize) |
537                 VIDW_BUF_SIZE_PAGEWIDTH(win_data->line_size);
538         writel(val, fimd_ctx->regs + VIDWx_BUF_SIZE(win, 0));
539
540         /* OSD position */
541         val = VIDOSDxA_TOPLEFT_X(win_data->offset_x) |
542                 VIDOSDxA_TOPLEFT_Y(win_data->offset_y);
543         writel(val, fimd_ctx->regs + VIDOSD_A(win));
544
545         val = VIDOSDxB_BOTRIGHT_X(win_data->offset_x +
546                                         win_data->ovl_width - 1) |
547                 VIDOSDxB_BOTRIGHT_Y(win_data->offset_y +
548                                         win_data->ovl_height - 1);
549         writel(val, fimd_ctx->regs + VIDOSD_B(win));
550
551         DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
552                         win_data->offset_x, win_data->offset_y,
553                         win_data->offset_x + win_data->ovl_width - 1,
554                         win_data->offset_y + win_data->ovl_height - 1);
555
556         /* hardware window 0 doesn't support alpha channel. */
557         if (win != 0) {
558                 /* OSD alpha */
559                 alpha = VIDISD14C_ALPHA1_R(0xf) |
560                         VIDISD14C_ALPHA1_G(0xf) |
561                         VIDISD14C_ALPHA1_B(0xf);
562
563                 writel(alpha, fimd_ctx->regs + VIDOSD_C(win));
564         }
565
566         /* OSD size */
567         if (win != 3 && win != 4) {
568                 u32 offset = VIDOSD_D(win);
569                 if (win == 0)
570                         offset = VIDOSD_C_SIZE_W0;
571                 val = win_data->ovl_width * win_data->ovl_height;
572                 writel(val, fimd_ctx->regs + offset);
573
574                 DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
575         }
576
577         fimd_win_set_pixfmt(fimd_ctx, win);
578
579         /* hardware window 0 doesn't support color key. */
580         if (win != 0)
581                 fimd_win_set_colkey(fimd_ctx, win);
582
583         /* wincon */
584         val = readl(fimd_ctx->regs + WINCON(win));
585         val |= WINCONx_ENWIN;
586         writel(val, fimd_ctx->regs + WINCON(win));
587
588         /* only apply dithering on hardware window 0. */
589         if (win == 0)
590                 mie_set_6bit_dithering(fimd_ctx, win);
591
592         /* Enable DMA channel and unprotect windows */
593         val = readl(fimd_ctx->regs + SHADOWCON);
594         val |= SHADOWCON_CHx_ENABLE(win);
595         val &= ~SHADOWCON_WINx_PROTECT(win);
596         writel(val, fimd_ctx->regs + SHADOWCON);
597
598         win_data->enabled = true;
599 }
600
601 static void fimd_win_disable(void *ctx, int zpos)
602 {
603         struct fimd_context *fimd_ctx = ctx;
604         struct fimd_win_data *win_data;
605         int win = zpos;
606         u32 val;
607
608         DRM_DEBUG_KMS("%s\n", __FILE__);
609         if (fimd_ctx->suspended)
610                 return;
611
612         if (win == DEFAULT_ZPOS)
613                 win = fimd_ctx->default_win;
614
615         if (win < 0 || win > WINDOWS_NR)
616                 return;
617
618         win_data = &fimd_ctx->win_data[win];
619
620         /* protect windows */
621         val = readl(fimd_ctx->regs + SHADOWCON);
622         val |= SHADOWCON_WINx_PROTECT(win);
623         writel(val, fimd_ctx->regs + SHADOWCON);
624
625         /* wincon */
626         val = readl(fimd_ctx->regs + WINCON(win));
627         val &= ~WINCONx_ENWIN;
628         writel(val, fimd_ctx->regs + WINCON(win));
629
630         /* unprotect windows */
631         val = readl(fimd_ctx->regs + SHADOWCON);
632         val &= ~SHADOWCON_CHx_ENABLE(win);
633         val &= ~SHADOWCON_WINx_PROTECT(win);
634         writel(val, fimd_ctx->regs + SHADOWCON);
635
636         win_data->enabled = false;
637 }
638
639 static void fimd_apply(void *ctx)
640 {
641         struct fimd_context *fimd_ctx = ctx;
642         struct fimd_win_data *win_data;
643         int i;
644
645         for (i = 0; i < WINDOWS_NR; i++) {
646                 win_data = &fimd_ctx->win_data[i];
647                 if (win_data->enabled)
648                         fimd_win_commit(ctx, i);
649         }
650 }
651
652 static irqreturn_t fimd_irq_handler(int irq, void *arg)
653 {
654         struct fimd_context *fimd_ctx = (struct fimd_context *)arg;
655         u32 val;
656
657         val = readl(fimd_ctx->regs + VIDINTCON1);
658
659         if (val & VIDINTCON1_INT_FRAME)
660                 /* VSYNC interrupt */
661                 writel(VIDINTCON1_INT_FRAME, fimd_ctx->regs + VIDINTCON1);
662
663         /* check the crtc is detached already from encoder */
664         if (fimd_ctx->pipe < 0)
665                 goto out;
666
667         drm_handle_vblank(fimd_ctx->drm_dev, fimd_ctx->pipe);
668         exynos_drm_crtc_finish_pageflip(fimd_ctx->drm_dev, fimd_ctx->pipe);
669
670 out:
671         return IRQ_HANDLED;
672 }
673
674 static int fimd_subdrv_probe(void *ctx, struct drm_device *drm_dev)
675 {
676         struct fimd_context *fimd_ctx = ctx;
677         DRM_DEBUG_KMS("%s\n", __FILE__);
678
679         /*
680          * enable drm irq mode.
681          * - with irq_enabled = 1, we can use the vblank feature.
682          *
683          * P.S. note that we wouldn't use drm irq handler but
684          *      just specific driver own one instead because
685          *      drm framework supports only one irq handler.
686          */
687         drm_dev->irq_enabled = 1;
688
689         /*
690          * with vblank_disable_allowed = 1, vblank interrupt will be disabled
691          * by drm timer once a current process gives up ownership of
692          * vblank event.(after drm_vblank_put function is called)
693          */
694         drm_dev->vblank_disable_allowed = 1;
695
696         fimd_ctx->drm_dev = drm_dev;
697
698         return 0;
699 }
700
701 static struct exynos_controller_ops fimd_controller_ops = {
702         .subdrv_probe = fimd_subdrv_probe,
703         .get_panel = fimd_get_panel,
704         .enable_vblank = fimd_enable_vblank,
705         .disable_vblank = fimd_disable_vblank,
706         .power = fimd_power,
707         .mode_set = fimd_win_mode_set,
708         .commit = fimd_commit,
709         .apply = fimd_apply,
710         .win_commit = fimd_win_commit,
711         .win_disable = fimd_win_disable,
712 };
713
714 static void fimd_clear_win(struct fimd_context *ctx, int win)
715 {
716         u32 val;
717
718         DRM_DEBUG_KMS("%s\n", __FILE__);
719
720         writel(0, ctx->regs + WINCON(win));
721         writel(0, ctx->regs + VIDOSD_A(win));
722         writel(0, ctx->regs + VIDOSD_B(win));
723         writel(0, ctx->regs + VIDOSD_C(win));
724
725         if (win == 1 || win == 2)
726                 writel(0, ctx->regs + VIDOSD_D(win));
727
728         val = readl(ctx->regs + SHADOWCON);
729         val &= ~SHADOWCON_WINx_PROTECT(win);
730         writel(val, ctx->regs + SHADOWCON);
731 }
732
733 /*
734  * Disables all windows for suspend, keeps track of which ones were enabled.
735  */
736 static void fimd_window_suspend(struct fimd_context *fimd_ctx)
737 {
738         struct fimd_win_data *win_data;
739         int i;
740
741         for(i = 0; i < WINDOWS_NR; i++)
742         {
743                 win_data = &fimd_ctx->win_data[i];
744                 win_data->win_suspended = win_data->enabled;
745                 fimd_win_disable(fimd_ctx, i);
746         }
747 }
748
749 /*
750  * Resumes the suspended windows.
751  */
752 static void fimd_window_resume(struct fimd_context *fimd_ctx)
753 {
754         struct fimd_win_data *win_data;
755         int i;
756
757         for(i = 0; i < WINDOWS_NR; i++)
758         {
759                 win_data = &fimd_ctx->win_data[i];
760                 if (win_data->win_suspended) {
761                         fimd_win_commit(fimd_ctx, i);
762                         win_data->win_suspended = false;
763                 }
764         }
765 }
766
767 static int fimd_power_on(struct fimd_context *fimd_ctx, bool enable)
768 {
769         DRM_DEBUG_KMS("%s\n", __FILE__);
770
771         if (enable) {
772                 int ret;
773
774                 ret = clk_enable(fimd_ctx->bus_clk);
775                 if (ret < 0)
776                         return ret;
777
778                 ret = clk_enable(fimd_ctx->lcd_clk);
779                 if  (ret < 0) {
780                         clk_disable(fimd_ctx->bus_clk);
781                         return ret;
782                 }
783
784                 fimd_ctx->suspended = false;
785
786                 /* if vblank was enabled status, enable it again. */
787                 if (test_and_clear_bit(0, &fimd_ctx->irq_flags))
788                         fimd_enable_vblank(fimd_ctx, fimd_ctx->pipe);
789
790                 fimd_apply(fimd_ctx);
791                 fimd_commit(fimd_ctx);
792
793                 if (fimd_ctx->panel_type == DP_LCD)
794                         writel(MIE_CLK_ENABLE, fimd_ctx->regs + DPCLKCON);
795
796                 fimd_window_resume(fimd_ctx);
797         } else {
798                 /*
799                  * We need to make sure that all windows are disabled before we
800                  * suspend that connector. Otherwise we might try to scan from
801                  * a destroyed buffer later.
802                  */
803                 fimd_window_suspend(fimd_ctx);
804
805                 if (fimd_ctx->panel_type == DP_LCD)
806                         writel(0, fimd_ctx->regs + DPCLKCON);
807
808                 clk_disable(fimd_ctx->lcd_clk);
809                 clk_disable(fimd_ctx->bus_clk);
810
811                 fimd_ctx->suspended = true;
812         }
813
814         return 0;
815 }
816
817 #ifdef CONFIG_EXYNOS_IOMMU
818 static int iommu_init(struct platform_device *pdev)
819 {
820         struct platform_device *pds;
821
822         pds = find_sysmmu_dt(pdev, "sysmmu");
823         if (pds==NULL) {
824                 printk(KERN_ERR "No sysmmu found\n");
825                 return -1;
826         }
827
828         platform_set_sysmmu(&pds->dev, &pdev->dev);
829         /*
830          * Due to the ordering in Makefile, this should be called first
831          * (before exynos_drm_drv.c and exynos_mixer.c and actually create
832          * the common mapping instead of reusing it. Ensure this assumption
833          * holds.
834          */
835         WARN_ON(exynos_drm_common_mapping);
836         exynos_drm_common_mapping = s5p_create_iommu_mapping(&pdev->dev,
837                                         0x20000000, SZ_256M, 4,
838                                         exynos_drm_common_mapping);
839
840         if (!exynos_drm_common_mapping) {
841                 printk(KERN_ERR "IOMMU mapping not created\n");
842                 return -1;
843         }
844
845         return 0;
846 }
847
848 static void iommu_deinit(struct platform_device *pdev)
849 {
850         s5p_destroy_iommu_mapping(&pdev->dev);
851         DRM_DEBUG("released the IOMMU mapping\n");
852 }
853 #endif
854
855 static int __devinit fimd_probe(struct platform_device *pdev)
856 {
857         struct device *dev = &pdev->dev;
858         struct fimd_context *fimd_ctx;
859         struct exynos_drm_fimd_pdata *pdata;
860         struct resource *res;
861         struct clk *clk_parent;
862         int win;
863         int ret = -EINVAL;
864
865 #ifdef CONFIG_EXYNOS_IOMMU
866         ret = iommu_init(pdev);
867         if (ret < 0) {
868                 dev_err(dev, "failed to initialize IOMMU\n");
869                 return -ENODEV;
870         }
871 #endif
872         DRM_DEBUG_KMS("%s\n", __FILE__);
873
874         pdata = pdev->dev.platform_data;
875         if (!pdata) {
876                 dev_err(dev, "no platform data specified\n");
877                 return -EINVAL;
878         }
879
880         fimd_ctx = kzalloc(sizeof(*fimd_ctx), GFP_KERNEL);
881         if (!fimd_ctx)
882                 return -ENOMEM;
883
884         fimd_ctx->panel_type = pdata->panel_type;
885         fimd_ctx->pipe = -1;
886
887         fimd_ctx->bus_clk = clk_get(dev, "fimd");
888         if (IS_ERR(fimd_ctx->bus_clk)) {
889                 dev_err(dev, "failed to get bus clock\n");
890                 ret = PTR_ERR(fimd_ctx->bus_clk);
891                 goto err_clk_get;
892         }
893
894         fimd_ctx->lcd_clk = clk_get(dev, "sclk_fimd");
895         if (IS_ERR(fimd_ctx->lcd_clk)) {
896                 dev_err(dev, "failed to get lcd clock\n");
897                 ret = PTR_ERR(fimd_ctx->lcd_clk);
898                 goto err_bus_clk;
899         }
900
901         clk_parent = clk_get(NULL, "sclk_vpll");
902         if (IS_ERR(clk_parent)) {
903                 ret = PTR_ERR(clk_parent);
904                 goto err_clk;
905         }
906
907         if (clk_set_parent(fimd_ctx->lcd_clk, clk_parent)) {
908                 ret = PTR_ERR(fimd_ctx->lcd_clk);
909                 goto err_clk;
910         }
911
912         if (clk_set_rate(fimd_ctx->lcd_clk, pdata->clock_rate)) {
913                 ret = PTR_ERR(fimd_ctx->lcd_clk);
914                 goto err_clk;
915         }
916
917         clk_put(clk_parent);
918
919         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
920         if (!res) {
921                 dev_err(dev, "failed to find registers\n");
922                 ret = -ENOENT;
923                 goto err_clk;
924         }
925
926         fimd_ctx->regs_res = request_mem_region(res->start, resource_size(res),
927                                            dev_name(dev));
928         if (!fimd_ctx->regs_res) {
929                 dev_err(dev, "failed to claim register region\n");
930                 ret = -ENOENT;
931                 goto err_clk;
932         }
933
934         fimd_ctx->regs = ioremap(res->start, resource_size(res));
935         if (!fimd_ctx->regs) {
936                 dev_err(dev, "failed to map registers\n");
937                 ret = -ENXIO;
938                 goto err_req_region_io;
939         }
940
941         fimd_ctx->regs_mie = ioremap(MIE_BASE_ADDRESS, 0x400);
942         if (!fimd_ctx->regs_mie) {
943                 dev_err(dev, "failed to map registers\n");
944                 ret = -ENXIO;
945                 goto err_req_region_io_mie;
946         }
947
948         res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
949         if (!res) {
950                 dev_err(dev, "irq request failed.\n");
951                 goto err_req_region_irq;
952         }
953
954         fimd_ctx->irq = res->start;
955
956         ret = request_irq(fimd_ctx->irq, fimd_irq_handler, 0, "drm_fimd",
957                         fimd_ctx);
958         if (ret < 0) {
959                 dev_err(dev, "irq request failed.\n");
960                 goto err_req_irq;
961         }
962
963         fimd_ctx->vidcon0 = pdata->vidcon0;
964         fimd_ctx->vidcon1 = pdata->vidcon1;
965         fimd_ctx->default_win = pdata->default_win;
966         fimd_ctx->panel = &pdata->panel;
967
968         mutex_init(&fimd_ctx->lock);
969
970         platform_set_drvdata(pdev, fimd_ctx);
971
972         fimd_power(fimd_ctx, DRM_MODE_DPMS_ON);
973
974         for (win = 0; win < WINDOWS_NR; win++)
975                 fimd_clear_win(fimd_ctx, win);
976
977         if (fimd_ctx->panel_type == DP_LCD)
978                 writel(MIE_CLK_ENABLE, fimd_ctx->regs + DPCLKCON);
979
980         exynos_display_attach_controller(EXYNOS_DRM_DISPLAY_TYPE_FIMD,
981                         &fimd_controller_ops, fimd_ctx);
982
983         return 0;
984
985 err_req_irq:
986 err_req_region_irq:
987         iounmap(fimd_ctx->regs_mie);
988
989 err_req_region_io_mie:
990         iounmap(fimd_ctx->regs);
991
992 err_req_region_io:
993         release_resource(fimd_ctx->regs_res);
994         kfree(fimd_ctx->regs_res);
995
996 err_clk:
997         clk_disable(fimd_ctx->lcd_clk);
998         clk_put(fimd_ctx->lcd_clk);
999
1000 err_bus_clk:
1001         clk_disable(fimd_ctx->bus_clk);
1002         clk_put(fimd_ctx->bus_clk);
1003
1004 err_clk_get:
1005 #ifdef CONFIG_EXYNOS_IOMMU
1006         iommu_deinit(pdev);
1007 #endif
1008         kfree(fimd_ctx);
1009         return ret;
1010 }
1011
1012 static int __devexit fimd_remove(struct platform_device *pdev)
1013 {
1014         struct fimd_context *ctx = platform_get_drvdata(pdev);
1015
1016         DRM_DEBUG_KMS("%s\n", __FILE__);
1017
1018         if (ctx->suspended)
1019                 goto out;
1020
1021         clk_disable(ctx->lcd_clk);
1022         clk_disable(ctx->bus_clk);
1023
1024         fimd_power(ctx, DRM_MODE_DPMS_OFF);
1025
1026 out:
1027         clk_put(ctx->lcd_clk);
1028         clk_put(ctx->bus_clk);
1029
1030         iounmap(ctx->regs_mie);
1031         iounmap(ctx->regs);
1032         release_resource(ctx->regs_res);
1033         kfree(ctx->regs_res);
1034         free_irq(ctx->irq, ctx);
1035 #ifdef CONFIG_EXYNOS_IOMMU
1036         iommu_deinit(pdev);
1037 #endif
1038         kfree(ctx);
1039
1040         return 0;
1041 }
1042
1043 static struct platform_device_id exynos_drm_driver_ids[] = {
1044         {
1045                 .name           = "exynos4-fb",
1046         }, {
1047                 .name           = "exynos5-fb",
1048         },
1049         {},
1050 };
1051 MODULE_DEVICE_TABLE(platform, exynos_drm_driver_ids);
1052
1053 struct platform_driver fimd_driver = {
1054         .probe          = fimd_probe,
1055         .remove         = __devexit_p(fimd_remove),
1056         .id_table       = exynos_drm_driver_ids,
1057         .driver         = {
1058                 .name   = "exynos-drm-fimd",
1059                 .owner  = THIS_MODULE,
1060         },
1061 };