]> git.openfabrics.org - ~shefty/rdma-dev.git/blob - drivers/video/s3c-fb.c
video: s3c-fb: add runtime_get/put to suspend/resume
[~shefty/rdma-dev.git] / drivers / video / s3c-fb.c
1 /* linux/drivers/video/s3c-fb.c
2  *
3  * Copyright 2008 Openmoko Inc.
4  * Copyright 2008-2010 Simtec Electronics
5  *      Ben Dooks <ben@simtec.co.uk>
6  *      http://armlinux.simtec.co.uk/
7  *
8  * Samsung SoC Framebuffer driver
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software FoundatIon.
13 */
14
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/dma-mapping.h>
19 #include <linux/slab.h>
20 #include <linux/init.h>
21 #include <linux/clk.h>
22 #include <linux/fb.h>
23 #include <linux/io.h>
24 #include <linux/uaccess.h>
25 #include <linux/interrupt.h>
26 #include <linux/pm_runtime.h>
27
28 #include <mach/map.h>
29 #include <plat/regs-fb-v4.h>
30 #include <plat/fb.h>
31
32 /* This driver will export a number of framebuffer interfaces depending
33  * on the configuration passed in via the platform data. Each fb instance
34  * maps to a hardware window. Currently there is no support for runtime
35  * setting of the alpha-blending functions that each window has, so only
36  * window 0 is actually useful.
37  *
38  * Window 0 is treated specially, it is used for the basis of the LCD
39  * output timings and as the control for the output power-down state.
40 */
41
42 /* note, the previous use of <mach/regs-fb.h> to get platform specific data
43  * has been replaced by using the platform device name to pick the correct
44  * configuration data for the system.
45 */
46
47 #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
48 #undef writel
49 #define writel(v, r) do { \
50         printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \
51         __raw_writel(v, r); \
52 } while (0)
53 #endif /* FB_S3C_DEBUG_REGWRITE */
54
55 /* irq_flags bits */
56 #define S3C_FB_VSYNC_IRQ_EN     0
57
58 #define VSYNC_TIMEOUT_MSEC 50
59
60 struct s3c_fb;
61
62 #define VALID_BPP(x) (1 << ((x) - 1))
63
64 #define OSD_BASE(win, variant) ((variant).osd + ((win) * (variant).osd_stride))
65 #define VIDOSD_A(win, variant) (OSD_BASE(win, variant) + 0x00)
66 #define VIDOSD_B(win, variant) (OSD_BASE(win, variant) + 0x04)
67 #define VIDOSD_C(win, variant) (OSD_BASE(win, variant) + 0x08)
68 #define VIDOSD_D(win, variant) (OSD_BASE(win, variant) + 0x0C)
69
70 /**
71  * struct s3c_fb_variant - fb variant information
72  * @is_2443: Set if S3C2443/S3C2416 style hardware.
73  * @nr_windows: The number of windows.
74  * @vidtcon: The base for the VIDTCONx registers
75  * @wincon: The base for the WINxCON registers.
76  * @winmap: The base for the WINxMAP registers.
77  * @keycon: The abse for the WxKEYCON registers.
78  * @buf_start: Offset of buffer start registers.
79  * @buf_size: Offset of buffer size registers.
80  * @buf_end: Offset of buffer end registers.
81  * @osd: The base for the OSD registers.
82  * @palette: Address of palette memory, or 0 if none.
83  * @has_prtcon: Set if has PRTCON register.
84  * @has_shadowcon: Set if has SHADOWCON register.
85  * @has_blendcon: Set if has BLENDCON register.
86  * @has_clksel: Set if VIDCON0 register has CLKSEL bit.
87  * @has_fixvclk: Set if VIDCON1 register has FIXVCLK bits.
88  */
89 struct s3c_fb_variant {
90         unsigned int    is_2443:1;
91         unsigned short  nr_windows;
92         unsigned int    vidtcon;
93         unsigned short  wincon;
94         unsigned short  winmap;
95         unsigned short  keycon;
96         unsigned short  buf_start;
97         unsigned short  buf_end;
98         unsigned short  buf_size;
99         unsigned short  osd;
100         unsigned short  osd_stride;
101         unsigned short  palette[S3C_FB_MAX_WIN];
102
103         unsigned int    has_prtcon:1;
104         unsigned int    has_shadowcon:1;
105         unsigned int    has_blendcon:1;
106         unsigned int    has_clksel:1;
107         unsigned int    has_fixvclk:1;
108 };
109
110 /**
111  * struct s3c_fb_win_variant
112  * @has_osd_c: Set if has OSD C register.
113  * @has_osd_d: Set if has OSD D register.
114  * @has_osd_alpha: Set if can change alpha transparency for a window.
115  * @palette_sz: Size of palette in entries.
116  * @palette_16bpp: Set if palette is 16bits wide.
117  * @osd_size_off: If != 0, supports setting up OSD for a window; the appropriate
118  *                register is located at the given offset from OSD_BASE.
119  * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel.
120  *
121  * valid_bpp bit x is set if (x+1)BPP is supported.
122  */
123 struct s3c_fb_win_variant {
124         unsigned int    has_osd_c:1;
125         unsigned int    has_osd_d:1;
126         unsigned int    has_osd_alpha:1;
127         unsigned int    palette_16bpp:1;
128         unsigned short  osd_size_off;
129         unsigned short  palette_sz;
130         u32             valid_bpp;
131 };
132
133 /**
134  * struct s3c_fb_driverdata - per-device type driver data for init time.
135  * @variant: The variant information for this driver.
136  * @win: The window information for each window.
137  */
138 struct s3c_fb_driverdata {
139         struct s3c_fb_variant   variant;
140         struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN];
141 };
142
143 /**
144  * struct s3c_fb_palette - palette information
145  * @r: Red bitfield.
146  * @g: Green bitfield.
147  * @b: Blue bitfield.
148  * @a: Alpha bitfield.
149  */
150 struct s3c_fb_palette {
151         struct fb_bitfield      r;
152         struct fb_bitfield      g;
153         struct fb_bitfield      b;
154         struct fb_bitfield      a;
155 };
156
157 /**
158  * struct s3c_fb_win - per window private data for each framebuffer.
159  * @windata: The platform data supplied for the window configuration.
160  * @parent: The hardware that this window is part of.
161  * @fbinfo: Pointer pack to the framebuffer info for this window.
162  * @varint: The variant information for this window.
163  * @palette_buffer: Buffer/cache to hold palette entries.
164  * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
165  * @index: The window number of this window.
166  * @palette: The bitfields for changing r/g/b into a hardware palette entry.
167  */
168 struct s3c_fb_win {
169         struct s3c_fb_pd_win    *windata;
170         struct s3c_fb           *parent;
171         struct fb_info          *fbinfo;
172         struct s3c_fb_palette    palette;
173         struct s3c_fb_win_variant variant;
174
175         u32                     *palette_buffer;
176         u32                      pseudo_palette[16];
177         unsigned int             index;
178 };
179
180 /**
181  * struct s3c_fb_vsync - vsync information
182  * @wait:       a queue for processes waiting for vsync
183  * @count:      vsync interrupt count
184  */
185 struct s3c_fb_vsync {
186         wait_queue_head_t       wait;
187         unsigned int            count;
188 };
189
190 /**
191  * struct s3c_fb - overall hardware state of the hardware
192  * @slock: The spinlock protection for this data sturcture.
193  * @dev: The device that we bound to, for printing, etc.
194  * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
195  * @lcd_clk: The clk (sclk) feeding pixclk.
196  * @regs: The mapped hardware registers.
197  * @variant: Variant information for this hardware.
198  * @enabled: A bitmask of enabled hardware windows.
199  * @output_on: Flag if the physical output is enabled.
200  * @pdata: The platform configuration data passed with the device.
201  * @windows: The hardware windows that have been claimed.
202  * @irq_no: IRQ line number
203  * @irq_flags: irq flags
204  * @vsync_info: VSYNC-related information (count, queues...)
205  */
206 struct s3c_fb {
207         spinlock_t              slock;
208         struct device           *dev;
209         struct clk              *bus_clk;
210         struct clk              *lcd_clk;
211         void __iomem            *regs;
212         struct s3c_fb_variant    variant;
213
214         unsigned char            enabled;
215         bool                     output_on;
216
217         struct s3c_fb_platdata  *pdata;
218         struct s3c_fb_win       *windows[S3C_FB_MAX_WIN];
219
220         int                      irq_no;
221         unsigned long            irq_flags;
222         struct s3c_fb_vsync      vsync_info;
223 };
224
225 /**
226  * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode.
227  * @win: The device window.
228  * @bpp: The bit depth.
229  */
230 static bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp)
231 {
232         return win->variant.valid_bpp & VALID_BPP(bpp);
233 }
234
235 /**
236  * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
237  * @var: The screen information to verify.
238  * @info: The framebuffer device.
239  *
240  * Framebuffer layer call to verify the given information and allow us to
241  * update various information depending on the hardware capabilities.
242  */
243 static int s3c_fb_check_var(struct fb_var_screeninfo *var,
244                             struct fb_info *info)
245 {
246         struct s3c_fb_win *win = info->par;
247         struct s3c_fb *sfb = win->parent;
248
249         dev_dbg(sfb->dev, "checking parameters\n");
250
251         var->xres_virtual = max(var->xres_virtual, var->xres);
252         var->yres_virtual = max(var->yres_virtual, var->yres);
253
254         if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) {
255                 dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n",
256                         win->index, var->bits_per_pixel);
257                 return -EINVAL;
258         }
259
260         /* always ensure these are zero, for drop through cases below */
261         var->transp.offset = 0;
262         var->transp.length = 0;
263
264         switch (var->bits_per_pixel) {
265         case 1:
266         case 2:
267         case 4:
268         case 8:
269                 if (sfb->variant.palette[win->index] != 0) {
270                         /* non palletised, A:1,R:2,G:3,B:2 mode */
271                         var->red.offset         = 4;
272                         var->green.offset       = 2;
273                         var->blue.offset        = 0;
274                         var->red.length         = 5;
275                         var->green.length       = 3;
276                         var->blue.length        = 2;
277                         var->transp.offset      = 7;
278                         var->transp.length      = 1;
279                 } else {
280                         var->red.offset = 0;
281                         var->red.length = var->bits_per_pixel;
282                         var->green      = var->red;
283                         var->blue       = var->red;
284                 }
285                 break;
286
287         case 19:
288                 /* 666 with one bit alpha/transparency */
289                 var->transp.offset      = 18;
290                 var->transp.length      = 1;
291         case 18:
292                 var->bits_per_pixel     = 32;
293
294                 /* 666 format */
295                 var->red.offset         = 12;
296                 var->green.offset       = 6;
297                 var->blue.offset        = 0;
298                 var->red.length         = 6;
299                 var->green.length       = 6;
300                 var->blue.length        = 6;
301                 break;
302
303         case 16:
304                 /* 16 bpp, 565 format */
305                 var->red.offset         = 11;
306                 var->green.offset       = 5;
307                 var->blue.offset        = 0;
308                 var->red.length         = 5;
309                 var->green.length       = 6;
310                 var->blue.length        = 5;
311                 break;
312
313         case 32:
314         case 28:
315         case 25:
316                 var->transp.length      = var->bits_per_pixel - 24;
317                 var->transp.offset      = 24;
318                 /* drop through */
319         case 24:
320                 /* our 24bpp is unpacked, so 32bpp */
321                 var->bits_per_pixel     = 32;
322                 var->red.offset         = 16;
323                 var->red.length         = 8;
324                 var->green.offset       = 8;
325                 var->green.length       = 8;
326                 var->blue.offset        = 0;
327                 var->blue.length        = 8;
328                 break;
329
330         default:
331                 dev_err(sfb->dev, "invalid bpp\n");
332         }
333
334         dev_dbg(sfb->dev, "%s: verified parameters\n", __func__);
335         return 0;
336 }
337
338 /**
339  * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
340  * @sfb: The hardware state.
341  * @pixclock: The pixel clock wanted, in picoseconds.
342  *
343  * Given the specified pixel clock, work out the necessary divider to get
344  * close to the output frequency.
345  */
346 static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
347 {
348         unsigned long clk;
349         unsigned long long tmp;
350         unsigned int result;
351
352         if (sfb->variant.has_clksel)
353                 clk = clk_get_rate(sfb->bus_clk);
354         else
355                 clk = clk_get_rate(sfb->lcd_clk);
356
357         tmp = (unsigned long long)clk;
358         tmp *= pixclk;
359
360         do_div(tmp, 1000000000UL);
361         result = (unsigned int)tmp / 1000;
362
363         dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
364                 pixclk, clk, result, clk / result);
365
366         return result;
367 }
368
369 /**
370  * s3c_fb_align_word() - align pixel count to word boundary
371  * @bpp: The number of bits per pixel
372  * @pix: The value to be aligned.
373  *
374  * Align the given pixel count so that it will start on an 32bit word
375  * boundary.
376  */
377 static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
378 {
379         int pix_per_word;
380
381         if (bpp > 16)
382                 return pix;
383
384         pix_per_word = (8 * 32) / bpp;
385         return ALIGN(pix, pix_per_word);
386 }
387
388 /**
389  * vidosd_set_size() - set OSD size for a window
390  *
391  * @win: the window to set OSD size for
392  * @size: OSD size register value
393  */
394 static void vidosd_set_size(struct s3c_fb_win *win, u32 size)
395 {
396         struct s3c_fb *sfb = win->parent;
397
398         /* OSD can be set up if osd_size_off != 0 for this window */
399         if (win->variant.osd_size_off)
400                 writel(size, sfb->regs + OSD_BASE(win->index, sfb->variant)
401                                 + win->variant.osd_size_off);
402 }
403
404 /**
405  * vidosd_set_alpha() - set alpha transparency for a window
406  *
407  * @win: the window to set OSD size for
408  * @alpha: alpha register value
409  */
410 static void vidosd_set_alpha(struct s3c_fb_win *win, u32 alpha)
411 {
412         struct s3c_fb *sfb = win->parent;
413
414         if (win->variant.has_osd_alpha)
415                 writel(alpha, sfb->regs + VIDOSD_C(win->index, sfb->variant));
416 }
417
418 /**
419  * shadow_protect_win() - disable updating values from shadow registers at vsync
420  *
421  * @win: window to protect registers for
422  * @protect: 1 to protect (disable updates)
423  */
424 static void shadow_protect_win(struct s3c_fb_win *win, bool protect)
425 {
426         struct s3c_fb *sfb = win->parent;
427         u32 reg;
428
429         if (protect) {
430                 if (sfb->variant.has_prtcon) {
431                         writel(PRTCON_PROTECT, sfb->regs + PRTCON);
432                 } else if (sfb->variant.has_shadowcon) {
433                         reg = readl(sfb->regs + SHADOWCON);
434                         writel(reg | SHADOWCON_WINx_PROTECT(win->index),
435                                 sfb->regs + SHADOWCON);
436                 }
437         } else {
438                 if (sfb->variant.has_prtcon) {
439                         writel(0, sfb->regs + PRTCON);
440                 } else if (sfb->variant.has_shadowcon) {
441                         reg = readl(sfb->regs + SHADOWCON);
442                         writel(reg & ~SHADOWCON_WINx_PROTECT(win->index),
443                                 sfb->regs + SHADOWCON);
444                 }
445         }
446 }
447
448 /**
449  * s3c_fb_enable() - Set the state of the main LCD output
450  * @sfb: The main framebuffer state.
451  * @enable: The state to set.
452  */
453 static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
454 {
455         u32 vidcon0 = readl(sfb->regs + VIDCON0);
456
457         if (enable && !sfb->output_on)
458                 pm_runtime_get_sync(sfb->dev);
459
460         if (enable) {
461                 vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
462         } else {
463                 /* see the note in the framebuffer datasheet about
464                  * why you cannot take both of these bits down at the
465                  * same time. */
466
467                 if (vidcon0 & VIDCON0_ENVID) {
468                         vidcon0 |= VIDCON0_ENVID;
469                         vidcon0 &= ~VIDCON0_ENVID_F;
470                 }
471         }
472
473         writel(vidcon0, sfb->regs + VIDCON0);
474
475         if (!enable && sfb->output_on)
476                 pm_runtime_put_sync(sfb->dev);
477
478         sfb->output_on = enable;
479 }
480
481 /**
482  * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
483  * @info: The framebuffer to change.
484  *
485  * Framebuffer layer request to set a new mode for the specified framebuffer
486  */
487 static int s3c_fb_set_par(struct fb_info *info)
488 {
489         struct fb_var_screeninfo *var = &info->var;
490         struct s3c_fb_win *win = info->par;
491         struct s3c_fb *sfb = win->parent;
492         void __iomem *regs = sfb->regs;
493         void __iomem *buf = regs;
494         int win_no = win->index;
495         u32 alpha = 0;
496         u32 data;
497         u32 pagewidth;
498
499         dev_dbg(sfb->dev, "setting framebuffer parameters\n");
500
501         pm_runtime_get_sync(sfb->dev);
502
503         shadow_protect_win(win, 1);
504
505         switch (var->bits_per_pixel) {
506         case 32:
507         case 24:
508         case 16:
509         case 12:
510                 info->fix.visual = FB_VISUAL_TRUECOLOR;
511                 break;
512         case 8:
513                 if (win->variant.palette_sz >= 256)
514                         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
515                 else
516                         info->fix.visual = FB_VISUAL_TRUECOLOR;
517                 break;
518         case 1:
519                 info->fix.visual = FB_VISUAL_MONO01;
520                 break;
521         default:
522                 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
523                 break;
524         }
525
526         info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
527
528         info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
529         info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
530
531         /* disable the window whilst we update it */
532         writel(0, regs + WINCON(win_no));
533
534         if (!sfb->output_on)
535                 s3c_fb_enable(sfb, 1);
536
537         /* write the buffer address */
538
539         /* start and end registers stride is 8 */
540         buf = regs + win_no * 8;
541
542         writel(info->fix.smem_start, buf + sfb->variant.buf_start);
543
544         data = info->fix.smem_start + info->fix.line_length * var->yres;
545         writel(data, buf + sfb->variant.buf_end);
546
547         pagewidth = (var->xres * var->bits_per_pixel) >> 3;
548         data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
549                VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) |
550                VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) |
551                VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth);
552         writel(data, regs + sfb->variant.buf_size + (win_no * 4));
553
554         /* write 'OSD' registers to control position of framebuffer */
555
556         data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) |
557                VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0);
558         writel(data, regs + VIDOSD_A(win_no, sfb->variant));
559
560         data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
561                                                      var->xres - 1)) |
562                VIDOSDxB_BOTRIGHT_Y(var->yres - 1) |
563                VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel,
564                                                      var->xres - 1)) |
565                VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1);
566
567         writel(data, regs + VIDOSD_B(win_no, sfb->variant));
568
569         data = var->xres * var->yres;
570
571         alpha = VIDISD14C_ALPHA1_R(0xf) |
572                 VIDISD14C_ALPHA1_G(0xf) |
573                 VIDISD14C_ALPHA1_B(0xf);
574
575         vidosd_set_alpha(win, alpha);
576         vidosd_set_size(win, data);
577
578         /* Enable DMA channel for this window */
579         if (sfb->variant.has_shadowcon) {
580                 data = readl(sfb->regs + SHADOWCON);
581                 data |= SHADOWCON_CHx_ENABLE(win_no);
582                 writel(data, sfb->regs + SHADOWCON);
583         }
584
585         data = WINCONx_ENWIN;
586         sfb->enabled |= (1 << win->index);
587
588         /* note, since we have to round up the bits-per-pixel, we end up
589          * relying on the bitfield information for r/g/b/a to work out
590          * exactly which mode of operation is intended. */
591
592         switch (var->bits_per_pixel) {
593         case 1:
594                 data |= WINCON0_BPPMODE_1BPP;
595                 data |= WINCONx_BITSWP;
596                 data |= WINCONx_BURSTLEN_4WORD;
597                 break;
598         case 2:
599                 data |= WINCON0_BPPMODE_2BPP;
600                 data |= WINCONx_BITSWP;
601                 data |= WINCONx_BURSTLEN_8WORD;
602                 break;
603         case 4:
604                 data |= WINCON0_BPPMODE_4BPP;
605                 data |= WINCONx_BITSWP;
606                 data |= WINCONx_BURSTLEN_8WORD;
607                 break;
608         case 8:
609                 if (var->transp.length != 0)
610                         data |= WINCON1_BPPMODE_8BPP_1232;
611                 else
612                         data |= WINCON0_BPPMODE_8BPP_PALETTE;
613                 data |= WINCONx_BURSTLEN_8WORD;
614                 data |= WINCONx_BYTSWP;
615                 break;
616         case 16:
617                 if (var->transp.length != 0)
618                         data |= WINCON1_BPPMODE_16BPP_A1555;
619                 else
620                         data |= WINCON0_BPPMODE_16BPP_565;
621                 data |= WINCONx_HAWSWP;
622                 data |= WINCONx_BURSTLEN_16WORD;
623                 break;
624         case 24:
625         case 32:
626                 if (var->red.length == 6) {
627                         if (var->transp.length != 0)
628                                 data |= WINCON1_BPPMODE_19BPP_A1666;
629                         else
630                                 data |= WINCON1_BPPMODE_18BPP_666;
631                 } else if (var->transp.length == 1)
632                         data |= WINCON1_BPPMODE_25BPP_A1888
633                                 | WINCON1_BLD_PIX;
634                 else if ((var->transp.length == 4) ||
635                         (var->transp.length == 8))
636                         data |= WINCON1_BPPMODE_28BPP_A4888
637                                 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
638                 else
639                         data |= WINCON0_BPPMODE_24BPP_888;
640
641                 data |= WINCONx_WSWP;
642                 data |= WINCONx_BURSTLEN_16WORD;
643                 break;
644         }
645
646         /* Enable the colour keying for the window below this one */
647         if (win_no > 0) {
648                 u32 keycon0_data = 0, keycon1_data = 0;
649                 void __iomem *keycon = regs + sfb->variant.keycon;
650
651                 keycon0_data = ~(WxKEYCON0_KEYBL_EN |
652                                 WxKEYCON0_KEYEN_F |
653                                 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
654
655                 keycon1_data = WxKEYCON1_COLVAL(0xffffff);
656
657                 keycon += (win_no - 1) * 8;
658
659                 writel(keycon0_data, keycon + WKEYCON0);
660                 writel(keycon1_data, keycon + WKEYCON1);
661         }
662
663         writel(data, regs + sfb->variant.wincon + (win_no * 4));
664         writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
665
666         /* Set alpha value width */
667         if (sfb->variant.has_blendcon) {
668                 data = readl(sfb->regs + BLENDCON);
669                 data &= ~BLENDCON_NEW_MASK;
670                 if (var->transp.length > 4)
671                         data |= BLENDCON_NEW_8BIT_ALPHA_VALUE;
672                 else
673                         data |= BLENDCON_NEW_4BIT_ALPHA_VALUE;
674                 writel(data, sfb->regs + BLENDCON);
675         }
676
677         shadow_protect_win(win, 0);
678
679         pm_runtime_put_sync(sfb->dev);
680
681         return 0;
682 }
683
684 /**
685  * s3c_fb_update_palette() - set or schedule a palette update.
686  * @sfb: The hardware information.
687  * @win: The window being updated.
688  * @reg: The palette index being changed.
689  * @value: The computed palette value.
690  *
691  * Change the value of a palette register, either by directly writing to
692  * the palette (this requires the palette RAM to be disconnected from the
693  * hardware whilst this is in progress) or schedule the update for later.
694  *
695  * At the moment, since we have no VSYNC interrupt support, we simply set
696  * the palette entry directly.
697  */
698 static void s3c_fb_update_palette(struct s3c_fb *sfb,
699                                   struct s3c_fb_win *win,
700                                   unsigned int reg,
701                                   u32 value)
702 {
703         void __iomem *palreg;
704         u32 palcon;
705
706         palreg = sfb->regs + sfb->variant.palette[win->index];
707
708         dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n",
709                 __func__, win->index, reg, palreg, value);
710
711         win->palette_buffer[reg] = value;
712
713         palcon = readl(sfb->regs + WPALCON);
714         writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON);
715
716         if (win->variant.palette_16bpp)
717                 writew(value, palreg + (reg * 2));
718         else
719                 writel(value, palreg + (reg * 4));
720
721         writel(palcon, sfb->regs + WPALCON);
722 }
723
724 static inline unsigned int chan_to_field(unsigned int chan,
725                                          struct fb_bitfield *bf)
726 {
727         chan &= 0xffff;
728         chan >>= 16 - bf->length;
729         return chan << bf->offset;
730 }
731
732 /**
733  * s3c_fb_setcolreg() - framebuffer layer request to change palette.
734  * @regno: The palette index to change.
735  * @red: The red field for the palette data.
736  * @green: The green field for the palette data.
737  * @blue: The blue field for the palette data.
738  * @trans: The transparency (alpha) field for the palette data.
739  * @info: The framebuffer being changed.
740  */
741 static int s3c_fb_setcolreg(unsigned regno,
742                             unsigned red, unsigned green, unsigned blue,
743                             unsigned transp, struct fb_info *info)
744 {
745         struct s3c_fb_win *win = info->par;
746         struct s3c_fb *sfb = win->parent;
747         unsigned int val;
748
749         dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
750                 __func__, win->index, regno, red, green, blue);
751
752         pm_runtime_get_sync(sfb->dev);
753
754         switch (info->fix.visual) {
755         case FB_VISUAL_TRUECOLOR:
756                 /* true-colour, use pseudo-palette */
757
758                 if (regno < 16) {
759                         u32 *pal = info->pseudo_palette;
760
761                         val  = chan_to_field(red,   &info->var.red);
762                         val |= chan_to_field(green, &info->var.green);
763                         val |= chan_to_field(blue,  &info->var.blue);
764
765                         pal[regno] = val;
766                 }
767                 break;
768
769         case FB_VISUAL_PSEUDOCOLOR:
770                 if (regno < win->variant.palette_sz) {
771                         val  = chan_to_field(red, &win->palette.r);
772                         val |= chan_to_field(green, &win->palette.g);
773                         val |= chan_to_field(blue, &win->palette.b);
774
775                         s3c_fb_update_palette(sfb, win, regno, val);
776                 }
777
778                 break;
779
780         default:
781                 pm_runtime_put_sync(sfb->dev);
782                 return 1;       /* unknown type */
783         }
784
785         pm_runtime_put_sync(sfb->dev);
786         return 0;
787 }
788
789 /**
790  * s3c_fb_blank() - blank or unblank the given window
791  * @blank_mode: The blank state from FB_BLANK_*
792  * @info: The framebuffer to blank.
793  *
794  * Framebuffer layer request to change the power state.
795  */
796 static int s3c_fb_blank(int blank_mode, struct fb_info *info)
797 {
798         struct s3c_fb_win *win = info->par;
799         struct s3c_fb *sfb = win->parent;
800         unsigned int index = win->index;
801         u32 wincon;
802         u32 output_on = sfb->output_on;
803
804         dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
805
806         pm_runtime_get_sync(sfb->dev);
807
808         wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
809
810         switch (blank_mode) {
811         case FB_BLANK_POWERDOWN:
812                 wincon &= ~WINCONx_ENWIN;
813                 sfb->enabled &= ~(1 << index);
814                 /* fall through to FB_BLANK_NORMAL */
815
816         case FB_BLANK_NORMAL:
817                 /* disable the DMA and display 0x0 (black) */
818                 shadow_protect_win(win, 1);
819                 writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
820                        sfb->regs + sfb->variant.winmap + (index * 4));
821                 shadow_protect_win(win, 0);
822                 break;
823
824         case FB_BLANK_UNBLANK:
825                 shadow_protect_win(win, 1);
826                 writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
827                 shadow_protect_win(win, 0);
828                 wincon |= WINCONx_ENWIN;
829                 sfb->enabled |= (1 << index);
830                 break;
831
832         case FB_BLANK_VSYNC_SUSPEND:
833         case FB_BLANK_HSYNC_SUSPEND:
834         default:
835                 pm_runtime_put_sync(sfb->dev);
836                 return 1;
837         }
838
839         shadow_protect_win(win, 1);
840         writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
841
842         /* Check the enabled state to see if we need to be running the
843          * main LCD interface, as if there are no active windows then
844          * it is highly likely that we also do not need to output
845          * anything.
846          */
847         s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
848         shadow_protect_win(win, 0);
849
850         pm_runtime_put_sync(sfb->dev);
851
852         return output_on == sfb->output_on;
853 }
854
855 /**
856  * s3c_fb_pan_display() - Pan the display.
857  *
858  * Note that the offsets can be written to the device at any time, as their
859  * values are latched at each vsync automatically. This also means that only
860  * the last call to this function will have any effect on next vsync, but
861  * there is no need to sleep waiting for it to prevent tearing.
862  *
863  * @var: The screen information to verify.
864  * @info: The framebuffer device.
865  */
866 static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
867                               struct fb_info *info)
868 {
869         struct s3c_fb_win *win  = info->par;
870         struct s3c_fb *sfb      = win->parent;
871         void __iomem *buf       = sfb->regs + win->index * 8;
872         unsigned int start_boff, end_boff;
873
874         pm_runtime_get_sync(sfb->dev);
875
876         /* Offset in bytes to the start of the displayed area */
877         start_boff = var->yoffset * info->fix.line_length;
878         /* X offset depends on the current bpp */
879         if (info->var.bits_per_pixel >= 8) {
880                 start_boff += var->xoffset * (info->var.bits_per_pixel >> 3);
881         } else {
882                 switch (info->var.bits_per_pixel) {
883                 case 4:
884                         start_boff += var->xoffset >> 1;
885                         break;
886                 case 2:
887                         start_boff += var->xoffset >> 2;
888                         break;
889                 case 1:
890                         start_boff += var->xoffset >> 3;
891                         break;
892                 default:
893                         dev_err(sfb->dev, "invalid bpp\n");
894                         pm_runtime_put_sync(sfb->dev);
895                         return -EINVAL;
896                 }
897         }
898         /* Offset in bytes to the end of the displayed area */
899         end_boff = start_boff + info->var.yres * info->fix.line_length;
900
901         /* Temporarily turn off per-vsync update from shadow registers until
902          * both start and end addresses are updated to prevent corruption */
903         shadow_protect_win(win, 1);
904
905         writel(info->fix.smem_start + start_boff, buf + sfb->variant.buf_start);
906         writel(info->fix.smem_start + end_boff, buf + sfb->variant.buf_end);
907
908         shadow_protect_win(win, 0);
909
910         pm_runtime_put_sync(sfb->dev);
911         return 0;
912 }
913
914 /**
915  * s3c_fb_enable_irq() - enable framebuffer interrupts
916  * @sfb: main hardware state
917  */
918 static void s3c_fb_enable_irq(struct s3c_fb *sfb)
919 {
920         void __iomem *regs = sfb->regs;
921         u32 irq_ctrl_reg;
922
923         if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
924                 /* IRQ disabled, enable it */
925                 irq_ctrl_reg = readl(regs + VIDINTCON0);
926
927                 irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
928                 irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
929
930                 irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
931                 irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
932                 irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
933                 irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
934
935                 writel(irq_ctrl_reg, regs + VIDINTCON0);
936         }
937 }
938
939 /**
940  * s3c_fb_disable_irq() - disable framebuffer interrupts
941  * @sfb: main hardware state
942  */
943 static void s3c_fb_disable_irq(struct s3c_fb *sfb)
944 {
945         void __iomem *regs = sfb->regs;
946         u32 irq_ctrl_reg;
947
948         if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
949                 /* IRQ enabled, disable it */
950                 irq_ctrl_reg = readl(regs + VIDINTCON0);
951
952                 irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
953                 irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
954
955                 writel(irq_ctrl_reg, regs + VIDINTCON0);
956         }
957 }
958
959 static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
960 {
961         struct s3c_fb *sfb = dev_id;
962         void __iomem  *regs = sfb->regs;
963         u32 irq_sts_reg;
964
965         spin_lock(&sfb->slock);
966
967         irq_sts_reg = readl(regs + VIDINTCON1);
968
969         if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
970
971                 /* VSYNC interrupt, accept it */
972                 writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
973
974                 sfb->vsync_info.count++;
975                 wake_up_interruptible(&sfb->vsync_info.wait);
976         }
977
978         /* We only support waiting for VSYNC for now, so it's safe
979          * to always disable irqs here.
980          */
981         s3c_fb_disable_irq(sfb);
982
983         spin_unlock(&sfb->slock);
984         return IRQ_HANDLED;
985 }
986
987 /**
988  * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
989  * @sfb: main hardware state
990  * @crtc: head index.
991  */
992 static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
993 {
994         unsigned long count;
995         int ret;
996
997         if (crtc != 0)
998                 return -ENODEV;
999
1000         pm_runtime_get_sync(sfb->dev);
1001
1002         count = sfb->vsync_info.count;
1003         s3c_fb_enable_irq(sfb);
1004         ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
1005                                        count != sfb->vsync_info.count,
1006                                        msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
1007
1008         pm_runtime_put_sync(sfb->dev);
1009
1010         if (ret == 0)
1011                 return -ETIMEDOUT;
1012
1013         return 0;
1014 }
1015
1016 static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
1017                         unsigned long arg)
1018 {
1019         struct s3c_fb_win *win = info->par;
1020         struct s3c_fb *sfb = win->parent;
1021         int ret;
1022         u32 crtc;
1023
1024         switch (cmd) {
1025         case FBIO_WAITFORVSYNC:
1026                 if (get_user(crtc, (u32 __user *)arg)) {
1027                         ret = -EFAULT;
1028                         break;
1029                 }
1030
1031                 ret = s3c_fb_wait_for_vsync(sfb, crtc);
1032                 break;
1033         default:
1034                 ret = -ENOTTY;
1035         }
1036
1037         return ret;
1038 }
1039
1040 static struct fb_ops s3c_fb_ops = {
1041         .owner          = THIS_MODULE,
1042         .fb_check_var   = s3c_fb_check_var,
1043         .fb_set_par     = s3c_fb_set_par,
1044         .fb_blank       = s3c_fb_blank,
1045         .fb_setcolreg   = s3c_fb_setcolreg,
1046         .fb_fillrect    = cfb_fillrect,
1047         .fb_copyarea    = cfb_copyarea,
1048         .fb_imageblit   = cfb_imageblit,
1049         .fb_pan_display = s3c_fb_pan_display,
1050         .fb_ioctl       = s3c_fb_ioctl,
1051 };
1052
1053 /**
1054  * s3c_fb_missing_pixclock() - calculates pixel clock
1055  * @mode: The video mode to change.
1056  *
1057  * Calculate the pixel clock when none has been given through platform data.
1058  */
1059 static void __devinit s3c_fb_missing_pixclock(struct fb_videomode *mode)
1060 {
1061         u64 pixclk = 1000000000000ULL;
1062         u32 div;
1063
1064         div  = mode->left_margin + mode->hsync_len + mode->right_margin +
1065                mode->xres;
1066         div *= mode->upper_margin + mode->vsync_len + mode->lower_margin +
1067                mode->yres;
1068         div *= mode->refresh ? : 60;
1069
1070         do_div(pixclk, div);
1071
1072         mode->pixclock = pixclk;
1073 }
1074
1075 /**
1076  * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
1077  * @sfb: The base resources for the hardware.
1078  * @win: The window to initialise memory for.
1079  *
1080  * Allocate memory for the given framebuffer.
1081  */
1082 static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
1083                                          struct s3c_fb_win *win)
1084 {
1085         struct s3c_fb_pd_win *windata = win->windata;
1086         unsigned int real_size, virt_size, size;
1087         struct fb_info *fbi = win->fbinfo;
1088         dma_addr_t map_dma;
1089
1090         dev_dbg(sfb->dev, "allocating memory for display\n");
1091
1092         real_size = windata->xres * windata->yres;
1093         virt_size = windata->virtual_x * windata->virtual_y;
1094
1095         dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
1096                 real_size, windata->xres, windata->yres,
1097                 virt_size, windata->virtual_x, windata->virtual_y);
1098
1099         size = (real_size > virt_size) ? real_size : virt_size;
1100         size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
1101         size /= 8;
1102
1103         fbi->fix.smem_len = size;
1104         size = PAGE_ALIGN(size);
1105
1106         dev_dbg(sfb->dev, "want %u bytes for window\n", size);
1107
1108         fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
1109                                                   &map_dma, GFP_KERNEL);
1110         if (!fbi->screen_base)
1111                 return -ENOMEM;
1112
1113         dev_dbg(sfb->dev, "mapped %x to %p\n",
1114                 (unsigned int)map_dma, fbi->screen_base);
1115
1116         memset(fbi->screen_base, 0x0, size);
1117         fbi->fix.smem_start = map_dma;
1118
1119         return 0;
1120 }
1121
1122 /**
1123  * s3c_fb_free_memory() - free the display memory for the given window
1124  * @sfb: The base resources for the hardware.
1125  * @win: The window to free the display memory for.
1126  *
1127  * Free the display memory allocated by s3c_fb_alloc_memory().
1128  */
1129 static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
1130 {
1131         struct fb_info *fbi = win->fbinfo;
1132
1133         if (fbi->screen_base)
1134                 dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
1135                               fbi->screen_base, fbi->fix.smem_start);
1136 }
1137
1138 /**
1139  * s3c_fb_release_win() - release resources for a framebuffer window.
1140  * @win: The window to cleanup the resources for.
1141  *
1142  * Release the resources that where claimed for the hardware window,
1143  * such as the framebuffer instance and any memory claimed for it.
1144  */
1145 static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
1146 {
1147         u32 data;
1148
1149         if (win->fbinfo) {
1150                 if (sfb->variant.has_shadowcon) {
1151                         data = readl(sfb->regs + SHADOWCON);
1152                         data &= ~SHADOWCON_CHx_ENABLE(win->index);
1153                         data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index);
1154                         writel(data, sfb->regs + SHADOWCON);
1155                 }
1156                 unregister_framebuffer(win->fbinfo);
1157                 if (win->fbinfo->cmap.len)
1158                         fb_dealloc_cmap(&win->fbinfo->cmap);
1159                 s3c_fb_free_memory(sfb, win);
1160                 framebuffer_release(win->fbinfo);
1161         }
1162 }
1163
1164 /**
1165  * s3c_fb_probe_win() - register an hardware window
1166  * @sfb: The base resources for the hardware
1167  * @variant: The variant information for this window.
1168  * @res: Pointer to where to place the resultant window.
1169  *
1170  * Allocate and do the basic initialisation for one of the hardware's graphics
1171  * windows.
1172  */
1173 static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
1174                                       struct s3c_fb_win_variant *variant,
1175                                       struct s3c_fb_win **res)
1176 {
1177         struct fb_var_screeninfo *var;
1178         struct fb_videomode initmode;
1179         struct s3c_fb_pd_win *windata;
1180         struct s3c_fb_win *win;
1181         struct fb_info *fbinfo;
1182         int palette_size;
1183         int ret;
1184
1185         dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
1186
1187         init_waitqueue_head(&sfb->vsync_info.wait);
1188
1189         palette_size = variant->palette_sz * 4;
1190
1191         fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
1192                                    palette_size * sizeof(u32), sfb->dev);
1193         if (!fbinfo) {
1194                 dev_err(sfb->dev, "failed to allocate framebuffer\n");
1195                 return -ENOENT;
1196         }
1197
1198         windata = sfb->pdata->win[win_no];
1199         initmode = *sfb->pdata->vtiming;
1200
1201         WARN_ON(windata->max_bpp == 0);
1202         WARN_ON(windata->xres == 0);
1203         WARN_ON(windata->yres == 0);
1204
1205         win = fbinfo->par;
1206         *res = win;
1207         var = &fbinfo->var;
1208         win->variant = *variant;
1209         win->fbinfo = fbinfo;
1210         win->parent = sfb;
1211         win->windata = windata;
1212         win->index = win_no;
1213         win->palette_buffer = (u32 *)(win + 1);
1214
1215         ret = s3c_fb_alloc_memory(sfb, win);
1216         if (ret) {
1217                 dev_err(sfb->dev, "failed to allocate display memory\n");
1218                 return ret;
1219         }
1220
1221         /* setup the r/b/g positions for the window's palette */
1222         if (win->variant.palette_16bpp) {
1223                 /* Set RGB 5:6:5 as default */
1224                 win->palette.r.offset = 11;
1225                 win->palette.r.length = 5;
1226                 win->palette.g.offset = 5;
1227                 win->palette.g.length = 6;
1228                 win->palette.b.offset = 0;
1229                 win->palette.b.length = 5;
1230
1231         } else {
1232                 /* Set 8bpp or 8bpp and 1bit alpha */
1233                 win->palette.r.offset = 16;
1234                 win->palette.r.length = 8;
1235                 win->palette.g.offset = 8;
1236                 win->palette.g.length = 8;
1237                 win->palette.b.offset = 0;
1238                 win->palette.b.length = 8;
1239         }
1240
1241         /* setup the initial video mode from the window */
1242         initmode.xres = windata->xres;
1243         initmode.yres = windata->yres;
1244         fb_videomode_to_var(&fbinfo->var, &initmode);
1245
1246         fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
1247         fbinfo->fix.accel       = FB_ACCEL_NONE;
1248         fbinfo->var.activate    = FB_ACTIVATE_NOW;
1249         fbinfo->var.vmode       = FB_VMODE_NONINTERLACED;
1250         fbinfo->var.bits_per_pixel = windata->default_bpp;
1251         fbinfo->fbops           = &s3c_fb_ops;
1252         fbinfo->flags           = FBINFO_FLAG_DEFAULT;
1253         fbinfo->pseudo_palette  = &win->pseudo_palette;
1254
1255         /* prepare to actually start the framebuffer */
1256
1257         ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
1258         if (ret < 0) {
1259                 dev_err(sfb->dev, "check_var failed on initial video params\n");
1260                 return ret;
1261         }
1262
1263         /* create initial colour map */
1264
1265         ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
1266         if (ret == 0)
1267                 fb_set_cmap(&fbinfo->cmap, fbinfo);
1268         else
1269                 dev_err(sfb->dev, "failed to allocate fb cmap\n");
1270
1271         s3c_fb_set_par(fbinfo);
1272
1273         dev_dbg(sfb->dev, "about to register framebuffer\n");
1274
1275         /* run the check_var and set_par on our configuration. */
1276
1277         ret = register_framebuffer(fbinfo);
1278         if (ret < 0) {
1279                 dev_err(sfb->dev, "failed to register framebuffer\n");
1280                 return ret;
1281         }
1282
1283         dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
1284
1285         return 0;
1286 }
1287
1288 /**
1289  * s3c_fb_set_rgb_timing() - set video timing for rgb interface.
1290  * @sfb: The base resources for the hardware.
1291  *
1292  * Set horizontal and vertical lcd rgb interface timing.
1293  */
1294 static void s3c_fb_set_rgb_timing(struct s3c_fb *sfb)
1295 {
1296         struct fb_videomode *vmode = sfb->pdata->vtiming;
1297         void __iomem *regs = sfb->regs;
1298         int clkdiv;
1299         u32 data;
1300
1301         if (!vmode->pixclock)
1302                 s3c_fb_missing_pixclock(vmode);
1303
1304         clkdiv = s3c_fb_calc_pixclk(sfb, vmode->pixclock);
1305
1306         data = sfb->pdata->vidcon0;
1307         data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
1308
1309         if (clkdiv > 1)
1310                 data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
1311         else
1312                 data &= ~VIDCON0_CLKDIR;        /* 1:1 clock */
1313
1314         if (sfb->variant.is_2443)
1315                 data |= (1 << 5);
1316         writel(data, regs + VIDCON0);
1317
1318         data = VIDTCON0_VBPD(vmode->upper_margin - 1) |
1319                VIDTCON0_VFPD(vmode->lower_margin - 1) |
1320                VIDTCON0_VSPW(vmode->vsync_len - 1);
1321         writel(data, regs + sfb->variant.vidtcon);
1322
1323         data = VIDTCON1_HBPD(vmode->left_margin - 1) |
1324                VIDTCON1_HFPD(vmode->right_margin - 1) |
1325                VIDTCON1_HSPW(vmode->hsync_len - 1);
1326         writel(data, regs + sfb->variant.vidtcon + 4);
1327
1328         data = VIDTCON2_LINEVAL(vmode->yres - 1) |
1329                VIDTCON2_HOZVAL(vmode->xres - 1) |
1330                VIDTCON2_LINEVAL_E(vmode->yres - 1) |
1331                VIDTCON2_HOZVAL_E(vmode->xres - 1);
1332         writel(data, regs + sfb->variant.vidtcon + 8);
1333 }
1334
1335 /**
1336  * s3c_fb_clear_win() - clear hardware window registers.
1337  * @sfb: The base resources for the hardware.
1338  * @win: The window to process.
1339  *
1340  * Reset the specific window registers to a known state.
1341  */
1342 static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
1343 {
1344         void __iomem *regs = sfb->regs;
1345         u32 reg;
1346
1347         writel(0, regs + sfb->variant.wincon + (win * 4));
1348         writel(0, regs + VIDOSD_A(win, sfb->variant));
1349         writel(0, regs + VIDOSD_B(win, sfb->variant));
1350         writel(0, regs + VIDOSD_C(win, sfb->variant));
1351         reg = readl(regs + SHADOWCON);
1352         writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON);
1353 }
1354
1355 static int __devinit s3c_fb_probe(struct platform_device *pdev)
1356 {
1357         const struct platform_device_id *platid;
1358         struct s3c_fb_driverdata *fbdrv;
1359         struct device *dev = &pdev->dev;
1360         struct s3c_fb_platdata *pd;
1361         struct s3c_fb *sfb;
1362         struct resource *res;
1363         int win;
1364         int ret = 0;
1365         u32 reg;
1366
1367         platid = platform_get_device_id(pdev);
1368         fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;
1369
1370         if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
1371                 dev_err(dev, "too many windows, cannot attach\n");
1372                 return -EINVAL;
1373         }
1374
1375         pd = pdev->dev.platform_data;
1376         if (!pd) {
1377                 dev_err(dev, "no platform data specified\n");
1378                 return -EINVAL;
1379         }
1380
1381         sfb = devm_kzalloc(dev, sizeof(struct s3c_fb), GFP_KERNEL);
1382         if (!sfb) {
1383                 dev_err(dev, "no memory for framebuffers\n");
1384                 return -ENOMEM;
1385         }
1386
1387         dev_dbg(dev, "allocate new framebuffer %p\n", sfb);
1388
1389         sfb->dev = dev;
1390         sfb->pdata = pd;
1391         sfb->variant = fbdrv->variant;
1392
1393         spin_lock_init(&sfb->slock);
1394
1395         sfb->bus_clk = clk_get(dev, "lcd");
1396         if (IS_ERR(sfb->bus_clk)) {
1397                 dev_err(dev, "failed to get bus clock\n");
1398                 ret = PTR_ERR(sfb->bus_clk);
1399                 goto err_sfb;
1400         }
1401
1402         clk_enable(sfb->bus_clk);
1403
1404         if (!sfb->variant.has_clksel) {
1405                 sfb->lcd_clk = clk_get(dev, "sclk_fimd");
1406                 if (IS_ERR(sfb->lcd_clk)) {
1407                         dev_err(dev, "failed to get lcd clock\n");
1408                         ret = PTR_ERR(sfb->lcd_clk);
1409                         goto err_bus_clk;
1410                 }
1411
1412                 clk_enable(sfb->lcd_clk);
1413         }
1414
1415         pm_runtime_enable(sfb->dev);
1416
1417         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1418         if (!res) {
1419                 dev_err(dev, "failed to find registers\n");
1420                 ret = -ENOENT;
1421                 goto err_lcd_clk;
1422         }
1423
1424         sfb->regs = devm_request_and_ioremap(dev, res);
1425         if (!sfb->regs) {
1426                 dev_err(dev, "failed to map registers\n");
1427                 ret = -ENXIO;
1428                 goto err_lcd_clk;
1429         }
1430
1431         res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1432         if (!res) {
1433                 dev_err(dev, "failed to acquire irq resource\n");
1434                 ret = -ENOENT;
1435                 goto err_lcd_clk;
1436         }
1437         sfb->irq_no = res->start;
1438         ret = devm_request_irq(dev, sfb->irq_no, s3c_fb_irq,
1439                           0, "s3c_fb", sfb);
1440         if (ret) {
1441                 dev_err(dev, "irq request failed\n");
1442                 goto err_lcd_clk;
1443         }
1444
1445         dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
1446
1447         platform_set_drvdata(pdev, sfb);
1448         pm_runtime_get_sync(sfb->dev);
1449
1450         /* setup gpio and output polarity controls */
1451
1452         pd->setup_gpio();
1453
1454         writel(pd->vidcon1, sfb->regs + VIDCON1);
1455
1456         /* set video clock running at under-run */
1457         if (sfb->variant.has_fixvclk) {
1458                 reg = readl(sfb->regs + VIDCON1);
1459                 reg &= ~VIDCON1_VCLK_MASK;
1460                 reg |= VIDCON1_VCLK_RUN;
1461                 writel(reg, sfb->regs + VIDCON1);
1462         }
1463
1464         /* zero all windows before we do anything */
1465
1466         for (win = 0; win < fbdrv->variant.nr_windows; win++)
1467                 s3c_fb_clear_win(sfb, win);
1468
1469         /* initialise colour key controls */
1470         for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
1471                 void __iomem *regs = sfb->regs + sfb->variant.keycon;
1472
1473                 regs += (win * 8);
1474                 writel(0xffffff, regs + WKEYCON0);
1475                 writel(0xffffff, regs + WKEYCON1);
1476         }
1477
1478         s3c_fb_set_rgb_timing(sfb);
1479
1480         /* we have the register setup, start allocating framebuffers */
1481
1482         for (win = 0; win < fbdrv->variant.nr_windows; win++) {
1483                 if (!pd->win[win])
1484                         continue;
1485
1486                 ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
1487                                        &sfb->windows[win]);
1488                 if (ret < 0) {
1489                         dev_err(dev, "failed to create window %d\n", win);
1490                         for (; win >= 0; win--)
1491                                 s3c_fb_release_win(sfb, sfb->windows[win]);
1492                         goto err_pm_runtime;
1493                 }
1494         }
1495
1496         platform_set_drvdata(pdev, sfb);
1497         pm_runtime_put_sync(sfb->dev);
1498
1499         return 0;
1500
1501 err_pm_runtime:
1502         pm_runtime_put_sync(sfb->dev);
1503
1504 err_lcd_clk:
1505         pm_runtime_disable(sfb->dev);
1506
1507         if (!sfb->variant.has_clksel) {
1508                 clk_disable(sfb->lcd_clk);
1509                 clk_put(sfb->lcd_clk);
1510         }
1511
1512 err_bus_clk:
1513         clk_disable(sfb->bus_clk);
1514         clk_put(sfb->bus_clk);
1515
1516 err_sfb:
1517         return ret;
1518 }
1519
1520 /**
1521  * s3c_fb_remove() - Cleanup on module finalisation
1522  * @pdev: The platform device we are bound to.
1523  *
1524  * Shutdown and then release all the resources that the driver allocated
1525  * on initialisation.
1526  */
1527 static int __devexit s3c_fb_remove(struct platform_device *pdev)
1528 {
1529         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1530         int win;
1531
1532         pm_runtime_get_sync(sfb->dev);
1533
1534         for (win = 0; win < S3C_FB_MAX_WIN; win++)
1535                 if (sfb->windows[win])
1536                         s3c_fb_release_win(sfb, sfb->windows[win]);
1537
1538         if (!sfb->variant.has_clksel) {
1539                 clk_disable(sfb->lcd_clk);
1540                 clk_put(sfb->lcd_clk);
1541         }
1542
1543         clk_disable(sfb->bus_clk);
1544         clk_put(sfb->bus_clk);
1545
1546         pm_runtime_put_sync(sfb->dev);
1547         pm_runtime_disable(sfb->dev);
1548
1549         return 0;
1550 }
1551
1552 #ifdef CONFIG_PM_SLEEP
1553 static int s3c_fb_suspend(struct device *dev)
1554 {
1555         struct platform_device *pdev = to_platform_device(dev);
1556         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1557         struct s3c_fb_win *win;
1558         int win_no;
1559
1560         pm_runtime_get_sync(sfb->dev);
1561
1562         for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
1563                 win = sfb->windows[win_no];
1564                 if (!win)
1565                         continue;
1566
1567                 /* use the blank function to push into power-down */
1568                 s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
1569         }
1570
1571         if (!sfb->variant.has_clksel)
1572                 clk_disable(sfb->lcd_clk);
1573
1574         clk_disable(sfb->bus_clk);
1575
1576         pm_runtime_put_sync(sfb->dev);
1577
1578         return 0;
1579 }
1580
1581 static int s3c_fb_resume(struct device *dev)
1582 {
1583         struct platform_device *pdev = to_platform_device(dev);
1584         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1585         struct s3c_fb_platdata *pd = sfb->pdata;
1586         struct s3c_fb_win *win;
1587         int win_no;
1588         u32 reg;
1589
1590         pm_runtime_get_sync(sfb->dev);
1591
1592         clk_enable(sfb->bus_clk);
1593
1594         if (!sfb->variant.has_clksel)
1595                 clk_enable(sfb->lcd_clk);
1596
1597         /* setup gpio and output polarity controls */
1598         pd->setup_gpio();
1599         writel(pd->vidcon1, sfb->regs + VIDCON1);
1600
1601         /* set video clock running at under-run */
1602         if (sfb->variant.has_fixvclk) {
1603                 reg = readl(sfb->regs + VIDCON1);
1604                 reg &= ~VIDCON1_VCLK_MASK;
1605                 reg |= VIDCON1_VCLK_RUN;
1606                 writel(reg, sfb->regs + VIDCON1);
1607         }
1608
1609         /* zero all windows before we do anything */
1610         for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
1611                 s3c_fb_clear_win(sfb, win_no);
1612
1613         for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
1614                 void __iomem *regs = sfb->regs + sfb->variant.keycon;
1615                 win = sfb->windows[win_no];
1616                 if (!win)
1617                         continue;
1618
1619                 shadow_protect_win(win, 1);
1620                 regs += (win_no * 8);
1621                 writel(0xffffff, regs + WKEYCON0);
1622                 writel(0xffffff, regs + WKEYCON1);
1623                 shadow_protect_win(win, 0);
1624         }
1625
1626         s3c_fb_set_rgb_timing(sfb);
1627
1628         /* restore framebuffers */
1629         for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
1630                 win = sfb->windows[win_no];
1631                 if (!win)
1632                         continue;
1633
1634                 dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
1635                 s3c_fb_set_par(win->fbinfo);
1636         }
1637
1638         pm_runtime_put_sync(sfb->dev);
1639
1640         return 0;
1641 }
1642 #endif
1643
1644 #ifdef CONFIG_PM_RUNTIME
1645 static int s3c_fb_runtime_suspend(struct device *dev)
1646 {
1647         struct platform_device *pdev = to_platform_device(dev);
1648         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1649
1650         if (!sfb->variant.has_clksel)
1651                 clk_disable(sfb->lcd_clk);
1652
1653         clk_disable(sfb->bus_clk);
1654
1655         return 0;
1656 }
1657
1658 static int s3c_fb_runtime_resume(struct device *dev)
1659 {
1660         struct platform_device *pdev = to_platform_device(dev);
1661         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1662         struct s3c_fb_platdata *pd = sfb->pdata;
1663
1664         clk_enable(sfb->bus_clk);
1665
1666         if (!sfb->variant.has_clksel)
1667                 clk_enable(sfb->lcd_clk);
1668
1669         /* setup gpio and output polarity controls */
1670         pd->setup_gpio();
1671         writel(pd->vidcon1, sfb->regs + VIDCON1);
1672
1673         return 0;
1674 }
1675 #endif
1676
1677 #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
1678 #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
1679
1680 static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
1681         [0] = {
1682                 .has_osd_c      = 1,
1683                 .osd_size_off   = 0x8,
1684                 .palette_sz     = 256,
1685                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
1686                                    VALID_BPP(18) | VALID_BPP(24)),
1687         },
1688         [1] = {
1689                 .has_osd_c      = 1,
1690                 .has_osd_d      = 1,
1691                 .osd_size_off   = 0xc,
1692                 .has_osd_alpha  = 1,
1693                 .palette_sz     = 256,
1694                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
1695                                    VALID_BPP(18) | VALID_BPP(19) |
1696                                    VALID_BPP(24) | VALID_BPP(25) |
1697                                    VALID_BPP(28)),
1698         },
1699         [2] = {
1700                 .has_osd_c      = 1,
1701                 .has_osd_d      = 1,
1702                 .osd_size_off   = 0xc,
1703                 .has_osd_alpha  = 1,
1704                 .palette_sz     = 16,
1705                 .palette_16bpp  = 1,
1706                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
1707                                    VALID_BPP(18) | VALID_BPP(19) |
1708                                    VALID_BPP(24) | VALID_BPP(25) |
1709                                    VALID_BPP(28)),
1710         },
1711         [3] = {
1712                 .has_osd_c      = 1,
1713                 .has_osd_alpha  = 1,
1714                 .palette_sz     = 16,
1715                 .palette_16bpp  = 1,
1716                 .valid_bpp      = (VALID_BPP124  | VALID_BPP(16) |
1717                                    VALID_BPP(18) | VALID_BPP(19) |
1718                                    VALID_BPP(24) | VALID_BPP(25) |
1719                                    VALID_BPP(28)),
1720         },
1721         [4] = {
1722                 .has_osd_c      = 1,
1723                 .has_osd_alpha  = 1,
1724                 .palette_sz     = 4,
1725                 .palette_16bpp  = 1,
1726                 .valid_bpp      = (VALID_BPP(1) | VALID_BPP(2) |
1727                                    VALID_BPP(16) | VALID_BPP(18) |
1728                                    VALID_BPP(19) | VALID_BPP(24) |
1729                                    VALID_BPP(25) | VALID_BPP(28)),
1730         },
1731 };
1732
1733 static struct s3c_fb_win_variant s3c_fb_data_s5p_wins[] = {
1734         [0] = {
1735                 .has_osd_c      = 1,
1736                 .osd_size_off   = 0x8,
1737                 .palette_sz     = 256,
1738                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
1739                                    VALID_BPP(15) | VALID_BPP(16) |
1740                                    VALID_BPP(18) | VALID_BPP(19) |
1741                                    VALID_BPP(24) | VALID_BPP(25) |
1742                                    VALID_BPP(32)),
1743         },
1744         [1] = {
1745                 .has_osd_c      = 1,
1746                 .has_osd_d      = 1,
1747                 .osd_size_off   = 0xc,
1748                 .has_osd_alpha  = 1,
1749                 .palette_sz     = 256,
1750                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
1751                                    VALID_BPP(15) | VALID_BPP(16) |
1752                                    VALID_BPP(18) | VALID_BPP(19) |
1753                                    VALID_BPP(24) | VALID_BPP(25) |
1754                                    VALID_BPP(32)),
1755         },
1756         [2] = {
1757                 .has_osd_c      = 1,
1758                 .has_osd_d      = 1,
1759                 .osd_size_off   = 0xc,
1760                 .has_osd_alpha  = 1,
1761                 .palette_sz     = 256,
1762                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
1763                                    VALID_BPP(15) | VALID_BPP(16) |
1764                                    VALID_BPP(18) | VALID_BPP(19) |
1765                                    VALID_BPP(24) | VALID_BPP(25) |
1766                                    VALID_BPP(32)),
1767         },
1768         [3] = {
1769                 .has_osd_c      = 1,
1770                 .has_osd_alpha  = 1,
1771                 .palette_sz     = 256,
1772                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
1773                                    VALID_BPP(15) | VALID_BPP(16) |
1774                                    VALID_BPP(18) | VALID_BPP(19) |
1775                                    VALID_BPP(24) | VALID_BPP(25) |
1776                                    VALID_BPP(32)),
1777         },
1778         [4] = {
1779                 .has_osd_c      = 1,
1780                 .has_osd_alpha  = 1,
1781                 .palette_sz     = 256,
1782                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
1783                                    VALID_BPP(15) | VALID_BPP(16) |
1784                                    VALID_BPP(18) | VALID_BPP(19) |
1785                                    VALID_BPP(24) | VALID_BPP(25) |
1786                                    VALID_BPP(32)),
1787         },
1788 };
1789
1790 static struct s3c_fb_driverdata s3c_fb_data_64xx = {
1791         .variant = {
1792                 .nr_windows     = 5,
1793                 .vidtcon        = VIDTCON0,
1794                 .wincon         = WINCON(0),
1795                 .winmap         = WINxMAP(0),
1796                 .keycon         = WKEYCON,
1797                 .osd            = VIDOSD_BASE,
1798                 .osd_stride     = 16,
1799                 .buf_start      = VIDW_BUF_START(0),
1800                 .buf_size       = VIDW_BUF_SIZE(0),
1801                 .buf_end        = VIDW_BUF_END(0),
1802
1803                 .palette = {
1804                         [0] = 0x400,
1805                         [1] = 0x800,
1806                         [2] = 0x300,
1807                         [3] = 0x320,
1808                         [4] = 0x340,
1809                 },
1810
1811                 .has_prtcon     = 1,
1812                 .has_clksel     = 1,
1813         },
1814         .win[0] = &s3c_fb_data_64xx_wins[0],
1815         .win[1] = &s3c_fb_data_64xx_wins[1],
1816         .win[2] = &s3c_fb_data_64xx_wins[2],
1817         .win[3] = &s3c_fb_data_64xx_wins[3],
1818         .win[4] = &s3c_fb_data_64xx_wins[4],
1819 };
1820
1821 static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
1822         .variant = {
1823                 .nr_windows     = 5,
1824                 .vidtcon        = VIDTCON0,
1825                 .wincon         = WINCON(0),
1826                 .winmap         = WINxMAP(0),
1827                 .keycon         = WKEYCON,
1828                 .osd            = VIDOSD_BASE,
1829                 .osd_stride     = 16,
1830                 .buf_start      = VIDW_BUF_START(0),
1831                 .buf_size       = VIDW_BUF_SIZE(0),
1832                 .buf_end        = VIDW_BUF_END(0),
1833
1834                 .palette = {
1835                         [0] = 0x2400,
1836                         [1] = 0x2800,
1837                         [2] = 0x2c00,
1838                         [3] = 0x3000,
1839                         [4] = 0x3400,
1840                 },
1841
1842                 .has_prtcon     = 1,
1843                 .has_blendcon   = 1,
1844                 .has_clksel     = 1,
1845         },
1846         .win[0] = &s3c_fb_data_s5p_wins[0],
1847         .win[1] = &s3c_fb_data_s5p_wins[1],
1848         .win[2] = &s3c_fb_data_s5p_wins[2],
1849         .win[3] = &s3c_fb_data_s5p_wins[3],
1850         .win[4] = &s3c_fb_data_s5p_wins[4],
1851 };
1852
1853 static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
1854         .variant = {
1855                 .nr_windows     = 5,
1856                 .vidtcon        = VIDTCON0,
1857                 .wincon         = WINCON(0),
1858                 .winmap         = WINxMAP(0),
1859                 .keycon         = WKEYCON,
1860                 .osd            = VIDOSD_BASE,
1861                 .osd_stride     = 16,
1862                 .buf_start      = VIDW_BUF_START(0),
1863                 .buf_size       = VIDW_BUF_SIZE(0),
1864                 .buf_end        = VIDW_BUF_END(0),
1865
1866                 .palette = {
1867                         [0] = 0x2400,
1868                         [1] = 0x2800,
1869                         [2] = 0x2c00,
1870                         [3] = 0x3000,
1871                         [4] = 0x3400,
1872                 },
1873
1874                 .has_shadowcon  = 1,
1875                 .has_blendcon   = 1,
1876                 .has_clksel     = 1,
1877                 .has_fixvclk    = 1,
1878         },
1879         .win[0] = &s3c_fb_data_s5p_wins[0],
1880         .win[1] = &s3c_fb_data_s5p_wins[1],
1881         .win[2] = &s3c_fb_data_s5p_wins[2],
1882         .win[3] = &s3c_fb_data_s5p_wins[3],
1883         .win[4] = &s3c_fb_data_s5p_wins[4],
1884 };
1885
1886 static struct s3c_fb_driverdata s3c_fb_data_exynos4 = {
1887         .variant = {
1888                 .nr_windows     = 5,
1889                 .vidtcon        = VIDTCON0,
1890                 .wincon         = WINCON(0),
1891                 .winmap         = WINxMAP(0),
1892                 .keycon         = WKEYCON,
1893                 .osd            = VIDOSD_BASE,
1894                 .osd_stride     = 16,
1895                 .buf_start      = VIDW_BUF_START(0),
1896                 .buf_size       = VIDW_BUF_SIZE(0),
1897                 .buf_end        = VIDW_BUF_END(0),
1898
1899                 .palette = {
1900                         [0] = 0x2400,
1901                         [1] = 0x2800,
1902                         [2] = 0x2c00,
1903                         [3] = 0x3000,
1904                         [4] = 0x3400,
1905                 },
1906
1907                 .has_shadowcon  = 1,
1908                 .has_blendcon   = 1,
1909                 .has_fixvclk    = 1,
1910         },
1911         .win[0] = &s3c_fb_data_s5p_wins[0],
1912         .win[1] = &s3c_fb_data_s5p_wins[1],
1913         .win[2] = &s3c_fb_data_s5p_wins[2],
1914         .win[3] = &s3c_fb_data_s5p_wins[3],
1915         .win[4] = &s3c_fb_data_s5p_wins[4],
1916 };
1917
1918 static struct s3c_fb_driverdata s3c_fb_data_exynos5 = {
1919         .variant = {
1920                 .nr_windows     = 5,
1921                 .vidtcon        = VIDTCON0,
1922                 .wincon         = WINCON(0),
1923                 .winmap         = WINxMAP(0),
1924                 .keycon         = WKEYCON,
1925                 .osd            = VIDOSD_BASE,
1926                 .osd_stride     = 16,
1927                 .buf_start      = VIDW_BUF_START(0),
1928                 .buf_size       = VIDW_BUF_SIZE(0),
1929                 .buf_end        = VIDW_BUF_END(0),
1930
1931                 .palette = {
1932                         [0] = 0x2400,
1933                         [1] = 0x2800,
1934                         [2] = 0x2c00,
1935                         [3] = 0x3000,
1936                         [4] = 0x3400,
1937                 },
1938                 .has_shadowcon  = 1,
1939                 .has_blendcon   = 1,
1940                 .has_fixvclk    = 1,
1941         },
1942         .win[0] = &s3c_fb_data_s5p_wins[0],
1943         .win[1] = &s3c_fb_data_s5p_wins[1],
1944         .win[2] = &s3c_fb_data_s5p_wins[2],
1945         .win[3] = &s3c_fb_data_s5p_wins[3],
1946         .win[4] = &s3c_fb_data_s5p_wins[4],
1947 };
1948
1949 /* S3C2443/S3C2416 style hardware */
1950 static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
1951         .variant = {
1952                 .nr_windows     = 2,
1953                 .is_2443        = 1,
1954
1955                 .vidtcon        = 0x08,
1956                 .wincon         = 0x14,
1957                 .winmap         = 0xd0,
1958                 .keycon         = 0xb0,
1959                 .osd            = 0x28,
1960                 .osd_stride     = 12,
1961                 .buf_start      = 0x64,
1962                 .buf_size       = 0x94,
1963                 .buf_end        = 0x7c,
1964
1965                 .palette = {
1966                         [0] = 0x400,
1967                         [1] = 0x800,
1968                 },
1969                 .has_clksel     = 1,
1970         },
1971         .win[0] = &(struct s3c_fb_win_variant) {
1972                 .palette_sz     = 256,
1973                 .valid_bpp      = VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
1974         },
1975         .win[1] = &(struct s3c_fb_win_variant) {
1976                 .has_osd_c      = 1,
1977                 .has_osd_alpha  = 1,
1978                 .palette_sz     = 256,
1979                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
1980                                    VALID_BPP(18) | VALID_BPP(19) |
1981                                    VALID_BPP(24) | VALID_BPP(25) |
1982                                    VALID_BPP(28)),
1983         },
1984 };
1985
1986 static struct s3c_fb_driverdata s3c_fb_data_s5p64x0 = {
1987         .variant = {
1988                 .nr_windows     = 3,
1989                 .vidtcon        = VIDTCON0,
1990                 .wincon         = WINCON(0),
1991                 .winmap         = WINxMAP(0),
1992                 .keycon         = WKEYCON,
1993                 .osd            = VIDOSD_BASE,
1994                 .osd_stride     = 16,
1995                 .buf_start      = VIDW_BUF_START(0),
1996                 .buf_size       = VIDW_BUF_SIZE(0),
1997                 .buf_end        = VIDW_BUF_END(0),
1998
1999                 .palette = {
2000                         [0] = 0x2400,
2001                         [1] = 0x2800,
2002                         [2] = 0x2c00,
2003                 },
2004
2005                 .has_blendcon   = 1,
2006                 .has_fixvclk    = 1,
2007         },
2008         .win[0] = &s3c_fb_data_s5p_wins[0],
2009         .win[1] = &s3c_fb_data_s5p_wins[1],
2010         .win[2] = &s3c_fb_data_s5p_wins[2],
2011 };
2012
2013 static struct platform_device_id s3c_fb_driver_ids[] = {
2014         {
2015                 .name           = "s3c-fb",
2016                 .driver_data    = (unsigned long)&s3c_fb_data_64xx,
2017         }, {
2018                 .name           = "s5pc100-fb",
2019                 .driver_data    = (unsigned long)&s3c_fb_data_s5pc100,
2020         }, {
2021                 .name           = "s5pv210-fb",
2022                 .driver_data    = (unsigned long)&s3c_fb_data_s5pv210,
2023         }, {
2024                 .name           = "exynos4-fb",
2025                 .driver_data    = (unsigned long)&s3c_fb_data_exynos4,
2026         }, {
2027                 .name           = "exynos5-fb",
2028                 .driver_data    = (unsigned long)&s3c_fb_data_exynos5,
2029         }, {
2030                 .name           = "s3c2443-fb",
2031                 .driver_data    = (unsigned long)&s3c_fb_data_s3c2443,
2032         }, {
2033                 .name           = "s5p64x0-fb",
2034                 .driver_data    = (unsigned long)&s3c_fb_data_s5p64x0,
2035         },
2036         {},
2037 };
2038 MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
2039
2040 static const struct dev_pm_ops s3cfb_pm_ops = {
2041         SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume)
2042         SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume,
2043                            NULL)
2044 };
2045
2046 static struct platform_driver s3c_fb_driver = {
2047         .probe          = s3c_fb_probe,
2048         .remove         = __devexit_p(s3c_fb_remove),
2049         .id_table       = s3c_fb_driver_ids,
2050         .driver         = {
2051                 .name   = "s3c-fb",
2052                 .owner  = THIS_MODULE,
2053                 .pm     = &s3cfb_pm_ops,
2054         },
2055 };
2056
2057 module_platform_driver(s3c_fb_driver);
2058
2059 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
2060 MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
2061 MODULE_LICENSE("GPL");
2062 MODULE_ALIAS("platform:s3c-fb");