Merge branch 'for_3.4/fixes/pm' of git://git.kernel.org/pub/scm/linux/kernel/git...
[pandora-kernel.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         int clkdiv;
499
500         dev_dbg(sfb->dev, "setting framebuffer parameters\n");
501
502         pm_runtime_get_sync(sfb->dev);
503
504         shadow_protect_win(win, 1);
505
506         switch (var->bits_per_pixel) {
507         case 32:
508         case 24:
509         case 16:
510         case 12:
511                 info->fix.visual = FB_VISUAL_TRUECOLOR;
512                 break;
513         case 8:
514                 if (win->variant.palette_sz >= 256)
515                         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
516                 else
517                         info->fix.visual = FB_VISUAL_TRUECOLOR;
518                 break;
519         case 1:
520                 info->fix.visual = FB_VISUAL_MONO01;
521                 break;
522         default:
523                 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
524                 break;
525         }
526
527         info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
528
529         info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
530         info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
531
532         /* disable the window whilst we update it */
533         writel(0, regs + WINCON(win_no));
534
535         /* use platform specified window as the basis for the lcd timings */
536
537         if (win_no == sfb->pdata->default_win) {
538                 clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
539
540                 data = sfb->pdata->vidcon0;
541                 data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
542
543                 if (clkdiv > 1)
544                         data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
545                 else
546                         data &= ~VIDCON0_CLKDIR;        /* 1:1 clock */
547
548                 /* write the timing data to the panel */
549
550                 if (sfb->variant.is_2443)
551                         data |= (1 << 5);
552
553                 writel(data, regs + VIDCON0);
554
555                 s3c_fb_enable(sfb, 1);
556
557                 data = VIDTCON0_VBPD(var->upper_margin - 1) |
558                        VIDTCON0_VFPD(var->lower_margin - 1) |
559                        VIDTCON0_VSPW(var->vsync_len - 1);
560
561                 writel(data, regs + sfb->variant.vidtcon);
562
563                 data = VIDTCON1_HBPD(var->left_margin - 1) |
564                        VIDTCON1_HFPD(var->right_margin - 1) |
565                        VIDTCON1_HSPW(var->hsync_len - 1);
566
567                 /* VIDTCON1 */
568                 writel(data, regs + sfb->variant.vidtcon + 4);
569
570                 data = VIDTCON2_LINEVAL(var->yres - 1) |
571                        VIDTCON2_HOZVAL(var->xres - 1) |
572                        VIDTCON2_LINEVAL_E(var->yres - 1) |
573                        VIDTCON2_HOZVAL_E(var->xres - 1);
574                 writel(data, regs + sfb->variant.vidtcon + 8);
575         }
576
577         /* write the buffer address */
578
579         /* start and end registers stride is 8 */
580         buf = regs + win_no * 8;
581
582         writel(info->fix.smem_start, buf + sfb->variant.buf_start);
583
584         data = info->fix.smem_start + info->fix.line_length * var->yres;
585         writel(data, buf + sfb->variant.buf_end);
586
587         pagewidth = (var->xres * var->bits_per_pixel) >> 3;
588         data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
589                VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) |
590                VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) |
591                VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth);
592         writel(data, regs + sfb->variant.buf_size + (win_no * 4));
593
594         /* write 'OSD' registers to control position of framebuffer */
595
596         data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) |
597                VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0);
598         writel(data, regs + VIDOSD_A(win_no, sfb->variant));
599
600         data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
601                                                      var->xres - 1)) |
602                VIDOSDxB_BOTRIGHT_Y(var->yres - 1) |
603                VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel,
604                                                      var->xres - 1)) |
605                VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1);
606
607         writel(data, regs + VIDOSD_B(win_no, sfb->variant));
608
609         data = var->xres * var->yres;
610
611         alpha = VIDISD14C_ALPHA1_R(0xf) |
612                 VIDISD14C_ALPHA1_G(0xf) |
613                 VIDISD14C_ALPHA1_B(0xf);
614
615         vidosd_set_alpha(win, alpha);
616         vidosd_set_size(win, data);
617
618         /* Enable DMA channel for this window */
619         if (sfb->variant.has_shadowcon) {
620                 data = readl(sfb->regs + SHADOWCON);
621                 data |= SHADOWCON_CHx_ENABLE(win_no);
622                 writel(data, sfb->regs + SHADOWCON);
623         }
624
625         data = WINCONx_ENWIN;
626         sfb->enabled |= (1 << win->index);
627
628         /* note, since we have to round up the bits-per-pixel, we end up
629          * relying on the bitfield information for r/g/b/a to work out
630          * exactly which mode of operation is intended. */
631
632         switch (var->bits_per_pixel) {
633         case 1:
634                 data |= WINCON0_BPPMODE_1BPP;
635                 data |= WINCONx_BITSWP;
636                 data |= WINCONx_BURSTLEN_4WORD;
637                 break;
638         case 2:
639                 data |= WINCON0_BPPMODE_2BPP;
640                 data |= WINCONx_BITSWP;
641                 data |= WINCONx_BURSTLEN_8WORD;
642                 break;
643         case 4:
644                 data |= WINCON0_BPPMODE_4BPP;
645                 data |= WINCONx_BITSWP;
646                 data |= WINCONx_BURSTLEN_8WORD;
647                 break;
648         case 8:
649                 if (var->transp.length != 0)
650                         data |= WINCON1_BPPMODE_8BPP_1232;
651                 else
652                         data |= WINCON0_BPPMODE_8BPP_PALETTE;
653                 data |= WINCONx_BURSTLEN_8WORD;
654                 data |= WINCONx_BYTSWP;
655                 break;
656         case 16:
657                 if (var->transp.length != 0)
658                         data |= WINCON1_BPPMODE_16BPP_A1555;
659                 else
660                         data |= WINCON0_BPPMODE_16BPP_565;
661                 data |= WINCONx_HAWSWP;
662                 data |= WINCONx_BURSTLEN_16WORD;
663                 break;
664         case 24:
665         case 32:
666                 if (var->red.length == 6) {
667                         if (var->transp.length != 0)
668                                 data |= WINCON1_BPPMODE_19BPP_A1666;
669                         else
670                                 data |= WINCON1_BPPMODE_18BPP_666;
671                 } else if (var->transp.length == 1)
672                         data |= WINCON1_BPPMODE_25BPP_A1888
673                                 | WINCON1_BLD_PIX;
674                 else if ((var->transp.length == 4) ||
675                         (var->transp.length == 8))
676                         data |= WINCON1_BPPMODE_28BPP_A4888
677                                 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
678                 else
679                         data |= WINCON0_BPPMODE_24BPP_888;
680
681                 data |= WINCONx_WSWP;
682                 data |= WINCONx_BURSTLEN_16WORD;
683                 break;
684         }
685
686         /* Enable the colour keying for the window below this one */
687         if (win_no > 0) {
688                 u32 keycon0_data = 0, keycon1_data = 0;
689                 void __iomem *keycon = regs + sfb->variant.keycon;
690
691                 keycon0_data = ~(WxKEYCON0_KEYBL_EN |
692                                 WxKEYCON0_KEYEN_F |
693                                 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
694
695                 keycon1_data = WxKEYCON1_COLVAL(0xffffff);
696
697                 keycon += (win_no - 1) * 8;
698
699                 writel(keycon0_data, keycon + WKEYCON0);
700                 writel(keycon1_data, keycon + WKEYCON1);
701         }
702
703         writel(data, regs + sfb->variant.wincon + (win_no * 4));
704         writel(0x0, regs + sfb->variant.winmap + (win_no * 4));
705
706         /* Set alpha value width */
707         if (sfb->variant.has_blendcon) {
708                 data = readl(sfb->regs + BLENDCON);
709                 data &= ~BLENDCON_NEW_MASK;
710                 if (var->transp.length > 4)
711                         data |= BLENDCON_NEW_8BIT_ALPHA_VALUE;
712                 else
713                         data |= BLENDCON_NEW_4BIT_ALPHA_VALUE;
714                 writel(data, sfb->regs + BLENDCON);
715         }
716
717         shadow_protect_win(win, 0);
718
719         pm_runtime_put_sync(sfb->dev);
720
721         return 0;
722 }
723
724 /**
725  * s3c_fb_update_palette() - set or schedule a palette update.
726  * @sfb: The hardware information.
727  * @win: The window being updated.
728  * @reg: The palette index being changed.
729  * @value: The computed palette value.
730  *
731  * Change the value of a palette register, either by directly writing to
732  * the palette (this requires the palette RAM to be disconnected from the
733  * hardware whilst this is in progress) or schedule the update for later.
734  *
735  * At the moment, since we have no VSYNC interrupt support, we simply set
736  * the palette entry directly.
737  */
738 static void s3c_fb_update_palette(struct s3c_fb *sfb,
739                                   struct s3c_fb_win *win,
740                                   unsigned int reg,
741                                   u32 value)
742 {
743         void __iomem *palreg;
744         u32 palcon;
745
746         palreg = sfb->regs + sfb->variant.palette[win->index];
747
748         dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n",
749                 __func__, win->index, reg, palreg, value);
750
751         win->palette_buffer[reg] = value;
752
753         palcon = readl(sfb->regs + WPALCON);
754         writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON);
755
756         if (win->variant.palette_16bpp)
757                 writew(value, palreg + (reg * 2));
758         else
759                 writel(value, palreg + (reg * 4));
760
761         writel(palcon, sfb->regs + WPALCON);
762 }
763
764 static inline unsigned int chan_to_field(unsigned int chan,
765                                          struct fb_bitfield *bf)
766 {
767         chan &= 0xffff;
768         chan >>= 16 - bf->length;
769         return chan << bf->offset;
770 }
771
772 /**
773  * s3c_fb_setcolreg() - framebuffer layer request to change palette.
774  * @regno: The palette index to change.
775  * @red: The red field for the palette data.
776  * @green: The green field for the palette data.
777  * @blue: The blue field for the palette data.
778  * @trans: The transparency (alpha) field for the palette data.
779  * @info: The framebuffer being changed.
780  */
781 static int s3c_fb_setcolreg(unsigned regno,
782                             unsigned red, unsigned green, unsigned blue,
783                             unsigned transp, struct fb_info *info)
784 {
785         struct s3c_fb_win *win = info->par;
786         struct s3c_fb *sfb = win->parent;
787         unsigned int val;
788
789         dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
790                 __func__, win->index, regno, red, green, blue);
791
792         pm_runtime_get_sync(sfb->dev);
793
794         switch (info->fix.visual) {
795         case FB_VISUAL_TRUECOLOR:
796                 /* true-colour, use pseudo-palette */
797
798                 if (regno < 16) {
799                         u32 *pal = info->pseudo_palette;
800
801                         val  = chan_to_field(red,   &info->var.red);
802                         val |= chan_to_field(green, &info->var.green);
803                         val |= chan_to_field(blue,  &info->var.blue);
804
805                         pal[regno] = val;
806                 }
807                 break;
808
809         case FB_VISUAL_PSEUDOCOLOR:
810                 if (regno < win->variant.palette_sz) {
811                         val  = chan_to_field(red, &win->palette.r);
812                         val |= chan_to_field(green, &win->palette.g);
813                         val |= chan_to_field(blue, &win->palette.b);
814
815                         s3c_fb_update_palette(sfb, win, regno, val);
816                 }
817
818                 break;
819
820         default:
821                 pm_runtime_put_sync(sfb->dev);
822                 return 1;       /* unknown type */
823         }
824
825         pm_runtime_put_sync(sfb->dev);
826         return 0;
827 }
828
829 /**
830  * s3c_fb_blank() - blank or unblank the given window
831  * @blank_mode: The blank state from FB_BLANK_*
832  * @info: The framebuffer to blank.
833  *
834  * Framebuffer layer request to change the power state.
835  */
836 static int s3c_fb_blank(int blank_mode, struct fb_info *info)
837 {
838         struct s3c_fb_win *win = info->par;
839         struct s3c_fb *sfb = win->parent;
840         unsigned int index = win->index;
841         u32 wincon;
842
843         dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
844
845         pm_runtime_get_sync(sfb->dev);
846
847         wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4));
848
849         switch (blank_mode) {
850         case FB_BLANK_POWERDOWN:
851                 wincon &= ~WINCONx_ENWIN;
852                 sfb->enabled &= ~(1 << index);
853                 /* fall through to FB_BLANK_NORMAL */
854
855         case FB_BLANK_NORMAL:
856                 /* disable the DMA and display 0x0 (black) */
857                 shadow_protect_win(win, 1);
858                 writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
859                        sfb->regs + sfb->variant.winmap + (index * 4));
860                 shadow_protect_win(win, 0);
861                 break;
862
863         case FB_BLANK_UNBLANK:
864                 shadow_protect_win(win, 1);
865                 writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4));
866                 shadow_protect_win(win, 0);
867                 wincon |= WINCONx_ENWIN;
868                 sfb->enabled |= (1 << index);
869                 break;
870
871         case FB_BLANK_VSYNC_SUSPEND:
872         case FB_BLANK_HSYNC_SUSPEND:
873         default:
874                 pm_runtime_put_sync(sfb->dev);
875                 return 1;
876         }
877
878         shadow_protect_win(win, 1);
879         writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4));
880         shadow_protect_win(win, 0);
881
882         /* Check the enabled state to see if we need to be running the
883          * main LCD interface, as if there are no active windows then
884          * it is highly likely that we also do not need to output
885          * anything.
886          */
887
888         /* We could do something like the following code, but the current
889          * system of using framebuffer events means that we cannot make
890          * the distinction between just window 0 being inactive and all
891          * the windows being down.
892          *
893          * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
894         */
895
896         /* we're stuck with this until we can do something about overriding
897          * the power control using the blanking event for a single fb.
898          */
899         if (index == sfb->pdata->default_win) {
900                 shadow_protect_win(win, 1);
901                 s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
902                 shadow_protect_win(win, 0);
903         }
904
905         pm_runtime_put_sync(sfb->dev);
906
907         return 0;
908 }
909
910 /**
911  * s3c_fb_pan_display() - Pan the display.
912  *
913  * Note that the offsets can be written to the device at any time, as their
914  * values are latched at each vsync automatically. This also means that only
915  * the last call to this function will have any effect on next vsync, but
916  * there is no need to sleep waiting for it to prevent tearing.
917  *
918  * @var: The screen information to verify.
919  * @info: The framebuffer device.
920  */
921 static int s3c_fb_pan_display(struct fb_var_screeninfo *var,
922                               struct fb_info *info)
923 {
924         struct s3c_fb_win *win  = info->par;
925         struct s3c_fb *sfb      = win->parent;
926         void __iomem *buf       = sfb->regs + win->index * 8;
927         unsigned int start_boff, end_boff;
928
929         pm_runtime_get_sync(sfb->dev);
930
931         /* Offset in bytes to the start of the displayed area */
932         start_boff = var->yoffset * info->fix.line_length;
933         /* X offset depends on the current bpp */
934         if (info->var.bits_per_pixel >= 8) {
935                 start_boff += var->xoffset * (info->var.bits_per_pixel >> 3);
936         } else {
937                 switch (info->var.bits_per_pixel) {
938                 case 4:
939                         start_boff += var->xoffset >> 1;
940                         break;
941                 case 2:
942                         start_boff += var->xoffset >> 2;
943                         break;
944                 case 1:
945                         start_boff += var->xoffset >> 3;
946                         break;
947                 default:
948                         dev_err(sfb->dev, "invalid bpp\n");
949                         pm_runtime_put_sync(sfb->dev);
950                         return -EINVAL;
951                 }
952         }
953         /* Offset in bytes to the end of the displayed area */
954         end_boff = start_boff + info->var.yres * info->fix.line_length;
955
956         /* Temporarily turn off per-vsync update from shadow registers until
957          * both start and end addresses are updated to prevent corruption */
958         shadow_protect_win(win, 1);
959
960         writel(info->fix.smem_start + start_boff, buf + sfb->variant.buf_start);
961         writel(info->fix.smem_start + end_boff, buf + sfb->variant.buf_end);
962
963         shadow_protect_win(win, 0);
964
965         pm_runtime_put_sync(sfb->dev);
966         return 0;
967 }
968
969 /**
970  * s3c_fb_enable_irq() - enable framebuffer interrupts
971  * @sfb: main hardware state
972  */
973 static void s3c_fb_enable_irq(struct s3c_fb *sfb)
974 {
975         void __iomem *regs = sfb->regs;
976         u32 irq_ctrl_reg;
977
978         if (!test_and_set_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
979                 /* IRQ disabled, enable it */
980                 irq_ctrl_reg = readl(regs + VIDINTCON0);
981
982                 irq_ctrl_reg |= VIDINTCON0_INT_ENABLE;
983                 irq_ctrl_reg |= VIDINTCON0_INT_FRAME;
984
985                 irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL0_MASK;
986                 irq_ctrl_reg |= VIDINTCON0_FRAMESEL0_VSYNC;
987                 irq_ctrl_reg &= ~VIDINTCON0_FRAMESEL1_MASK;
988                 irq_ctrl_reg |= VIDINTCON0_FRAMESEL1_NONE;
989
990                 writel(irq_ctrl_reg, regs + VIDINTCON0);
991         }
992 }
993
994 /**
995  * s3c_fb_disable_irq() - disable framebuffer interrupts
996  * @sfb: main hardware state
997  */
998 static void s3c_fb_disable_irq(struct s3c_fb *sfb)
999 {
1000         void __iomem *regs = sfb->regs;
1001         u32 irq_ctrl_reg;
1002
1003         if (test_and_clear_bit(S3C_FB_VSYNC_IRQ_EN, &sfb->irq_flags)) {
1004                 /* IRQ enabled, disable it */
1005                 irq_ctrl_reg = readl(regs + VIDINTCON0);
1006
1007                 irq_ctrl_reg &= ~VIDINTCON0_INT_FRAME;
1008                 irq_ctrl_reg &= ~VIDINTCON0_INT_ENABLE;
1009
1010                 writel(irq_ctrl_reg, regs + VIDINTCON0);
1011         }
1012 }
1013
1014 static irqreturn_t s3c_fb_irq(int irq, void *dev_id)
1015 {
1016         struct s3c_fb *sfb = dev_id;
1017         void __iomem  *regs = sfb->regs;
1018         u32 irq_sts_reg;
1019
1020         spin_lock(&sfb->slock);
1021
1022         irq_sts_reg = readl(regs + VIDINTCON1);
1023
1024         if (irq_sts_reg & VIDINTCON1_INT_FRAME) {
1025
1026                 /* VSYNC interrupt, accept it */
1027                 writel(VIDINTCON1_INT_FRAME, regs + VIDINTCON1);
1028
1029                 sfb->vsync_info.count++;
1030                 wake_up_interruptible(&sfb->vsync_info.wait);
1031         }
1032
1033         /* We only support waiting for VSYNC for now, so it's safe
1034          * to always disable irqs here.
1035          */
1036         s3c_fb_disable_irq(sfb);
1037
1038         spin_unlock(&sfb->slock);
1039         return IRQ_HANDLED;
1040 }
1041
1042 /**
1043  * s3c_fb_wait_for_vsync() - sleep until next VSYNC interrupt or timeout
1044  * @sfb: main hardware state
1045  * @crtc: head index.
1046  */
1047 static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc)
1048 {
1049         unsigned long count;
1050         int ret;
1051
1052         if (crtc != 0)
1053                 return -ENODEV;
1054
1055         pm_runtime_get_sync(sfb->dev);
1056
1057         count = sfb->vsync_info.count;
1058         s3c_fb_enable_irq(sfb);
1059         ret = wait_event_interruptible_timeout(sfb->vsync_info.wait,
1060                                        count != sfb->vsync_info.count,
1061                                        msecs_to_jiffies(VSYNC_TIMEOUT_MSEC));
1062
1063         pm_runtime_put_sync(sfb->dev);
1064
1065         if (ret == 0)
1066                 return -ETIMEDOUT;
1067
1068         return 0;
1069 }
1070
1071 static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd,
1072                         unsigned long arg)
1073 {
1074         struct s3c_fb_win *win = info->par;
1075         struct s3c_fb *sfb = win->parent;
1076         int ret;
1077         u32 crtc;
1078
1079         switch (cmd) {
1080         case FBIO_WAITFORVSYNC:
1081                 if (get_user(crtc, (u32 __user *)arg)) {
1082                         ret = -EFAULT;
1083                         break;
1084                 }
1085
1086                 ret = s3c_fb_wait_for_vsync(sfb, crtc);
1087                 break;
1088         default:
1089                 ret = -ENOTTY;
1090         }
1091
1092         return ret;
1093 }
1094
1095 static struct fb_ops s3c_fb_ops = {
1096         .owner          = THIS_MODULE,
1097         .fb_check_var   = s3c_fb_check_var,
1098         .fb_set_par     = s3c_fb_set_par,
1099         .fb_blank       = s3c_fb_blank,
1100         .fb_setcolreg   = s3c_fb_setcolreg,
1101         .fb_fillrect    = cfb_fillrect,
1102         .fb_copyarea    = cfb_copyarea,
1103         .fb_imageblit   = cfb_imageblit,
1104         .fb_pan_display = s3c_fb_pan_display,
1105         .fb_ioctl       = s3c_fb_ioctl,
1106 };
1107
1108 /**
1109  * s3c_fb_missing_pixclock() - calculates pixel clock
1110  * @mode: The video mode to change.
1111  *
1112  * Calculate the pixel clock when none has been given through platform data.
1113  */
1114 static void __devinit s3c_fb_missing_pixclock(struct fb_videomode *mode)
1115 {
1116         u64 pixclk = 1000000000000ULL;
1117         u32 div;
1118
1119         div  = mode->left_margin + mode->hsync_len + mode->right_margin +
1120                mode->xres;
1121         div *= mode->upper_margin + mode->vsync_len + mode->lower_margin +
1122                mode->yres;
1123         div *= mode->refresh ? : 60;
1124
1125         do_div(pixclk, div);
1126
1127         mode->pixclock = pixclk;
1128 }
1129
1130 /**
1131  * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
1132  * @sfb: The base resources for the hardware.
1133  * @win: The window to initialise memory for.
1134  *
1135  * Allocate memory for the given framebuffer.
1136  */
1137 static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
1138                                          struct s3c_fb_win *win)
1139 {
1140         struct s3c_fb_pd_win *windata = win->windata;
1141         unsigned int real_size, virt_size, size;
1142         struct fb_info *fbi = win->fbinfo;
1143         dma_addr_t map_dma;
1144
1145         dev_dbg(sfb->dev, "allocating memory for display\n");
1146
1147         real_size = windata->win_mode.xres * windata->win_mode.yres;
1148         virt_size = windata->virtual_x * windata->virtual_y;
1149
1150         dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
1151                 real_size, windata->win_mode.xres, windata->win_mode.yres,
1152                 virt_size, windata->virtual_x, windata->virtual_y);
1153
1154         size = (real_size > virt_size) ? real_size : virt_size;
1155         size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
1156         size /= 8;
1157
1158         fbi->fix.smem_len = size;
1159         size = PAGE_ALIGN(size);
1160
1161         dev_dbg(sfb->dev, "want %u bytes for window\n", size);
1162
1163         fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
1164                                                   &map_dma, GFP_KERNEL);
1165         if (!fbi->screen_base)
1166                 return -ENOMEM;
1167
1168         dev_dbg(sfb->dev, "mapped %x to %p\n",
1169                 (unsigned int)map_dma, fbi->screen_base);
1170
1171         memset(fbi->screen_base, 0x0, size);
1172         fbi->fix.smem_start = map_dma;
1173
1174         return 0;
1175 }
1176
1177 /**
1178  * s3c_fb_free_memory() - free the display memory for the given window
1179  * @sfb: The base resources for the hardware.
1180  * @win: The window to free the display memory for.
1181  *
1182  * Free the display memory allocated by s3c_fb_alloc_memory().
1183  */
1184 static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
1185 {
1186         struct fb_info *fbi = win->fbinfo;
1187
1188         if (fbi->screen_base)
1189                 dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
1190                               fbi->screen_base, fbi->fix.smem_start);
1191 }
1192
1193 /**
1194  * s3c_fb_release_win() - release resources for a framebuffer window.
1195  * @win: The window to cleanup the resources for.
1196  *
1197  * Release the resources that where claimed for the hardware window,
1198  * such as the framebuffer instance and any memory claimed for it.
1199  */
1200 static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
1201 {
1202         u32 data;
1203
1204         if (win->fbinfo) {
1205                 if (sfb->variant.has_shadowcon) {
1206                         data = readl(sfb->regs + SHADOWCON);
1207                         data &= ~SHADOWCON_CHx_ENABLE(win->index);
1208                         data &= ~SHADOWCON_CHx_LOCAL_ENABLE(win->index);
1209                         writel(data, sfb->regs + SHADOWCON);
1210                 }
1211                 unregister_framebuffer(win->fbinfo);
1212                 if (win->fbinfo->cmap.len)
1213                         fb_dealloc_cmap(&win->fbinfo->cmap);
1214                 s3c_fb_free_memory(sfb, win);
1215                 framebuffer_release(win->fbinfo);
1216         }
1217 }
1218
1219 /**
1220  * s3c_fb_probe_win() - register an hardware window
1221  * @sfb: The base resources for the hardware
1222  * @variant: The variant information for this window.
1223  * @res: Pointer to where to place the resultant window.
1224  *
1225  * Allocate and do the basic initialisation for one of the hardware's graphics
1226  * windows.
1227  */
1228 static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
1229                                       struct s3c_fb_win_variant *variant,
1230                                       struct s3c_fb_win **res)
1231 {
1232         struct fb_var_screeninfo *var;
1233         struct fb_videomode *initmode;
1234         struct s3c_fb_pd_win *windata;
1235         struct s3c_fb_win *win;
1236         struct fb_info *fbinfo;
1237         int palette_size;
1238         int ret;
1239
1240         dev_dbg(sfb->dev, "probing window %d, variant %p\n", win_no, variant);
1241
1242         init_waitqueue_head(&sfb->vsync_info.wait);
1243
1244         palette_size = variant->palette_sz * 4;
1245
1246         fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
1247                                    palette_size * sizeof(u32), sfb->dev);
1248         if (!fbinfo) {
1249                 dev_err(sfb->dev, "failed to allocate framebuffer\n");
1250                 return -ENOENT;
1251         }
1252
1253         windata = sfb->pdata->win[win_no];
1254         initmode = &windata->win_mode;
1255
1256         WARN_ON(windata->max_bpp == 0);
1257         WARN_ON(windata->win_mode.xres == 0);
1258         WARN_ON(windata->win_mode.yres == 0);
1259
1260         win = fbinfo->par;
1261         *res = win;
1262         var = &fbinfo->var;
1263         win->variant = *variant;
1264         win->fbinfo = fbinfo;
1265         win->parent = sfb;
1266         win->windata = windata;
1267         win->index = win_no;
1268         win->palette_buffer = (u32 *)(win + 1);
1269
1270         ret = s3c_fb_alloc_memory(sfb, win);
1271         if (ret) {
1272                 dev_err(sfb->dev, "failed to allocate display memory\n");
1273                 return ret;
1274         }
1275
1276         /* setup the r/b/g positions for the window's palette */
1277         if (win->variant.palette_16bpp) {
1278                 /* Set RGB 5:6:5 as default */
1279                 win->palette.r.offset = 11;
1280                 win->palette.r.length = 5;
1281                 win->palette.g.offset = 5;
1282                 win->palette.g.length = 6;
1283                 win->palette.b.offset = 0;
1284                 win->palette.b.length = 5;
1285
1286         } else {
1287                 /* Set 8bpp or 8bpp and 1bit alpha */
1288                 win->palette.r.offset = 16;
1289                 win->palette.r.length = 8;
1290                 win->palette.g.offset = 8;
1291                 win->palette.g.length = 8;
1292                 win->palette.b.offset = 0;
1293                 win->palette.b.length = 8;
1294         }
1295
1296         /* setup the initial video mode from the window */
1297         fb_videomode_to_var(&fbinfo->var, initmode);
1298
1299         fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
1300         fbinfo->fix.accel       = FB_ACCEL_NONE;
1301         fbinfo->var.activate    = FB_ACTIVATE_NOW;
1302         fbinfo->var.vmode       = FB_VMODE_NONINTERLACED;
1303         fbinfo->var.bits_per_pixel = windata->default_bpp;
1304         fbinfo->fbops           = &s3c_fb_ops;
1305         fbinfo->flags           = FBINFO_FLAG_DEFAULT;
1306         fbinfo->pseudo_palette  = &win->pseudo_palette;
1307
1308         /* prepare to actually start the framebuffer */
1309
1310         ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
1311         if (ret < 0) {
1312                 dev_err(sfb->dev, "check_var failed on initial video params\n");
1313                 return ret;
1314         }
1315
1316         /* create initial colour map */
1317
1318         ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
1319         if (ret == 0)
1320                 fb_set_cmap(&fbinfo->cmap, fbinfo);
1321         else
1322                 dev_err(sfb->dev, "failed to allocate fb cmap\n");
1323
1324         s3c_fb_set_par(fbinfo);
1325
1326         dev_dbg(sfb->dev, "about to register framebuffer\n");
1327
1328         /* run the check_var and set_par on our configuration. */
1329
1330         ret = register_framebuffer(fbinfo);
1331         if (ret < 0) {
1332                 dev_err(sfb->dev, "failed to register framebuffer\n");
1333                 return ret;
1334         }
1335
1336         dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
1337
1338         return 0;
1339 }
1340
1341 /**
1342  * s3c_fb_clear_win() - clear hardware window registers.
1343  * @sfb: The base resources for the hardware.
1344  * @win: The window to process.
1345  *
1346  * Reset the specific window registers to a known state.
1347  */
1348 static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
1349 {
1350         void __iomem *regs = sfb->regs;
1351         u32 reg;
1352
1353         writel(0, regs + sfb->variant.wincon + (win * 4));
1354         writel(0, regs + VIDOSD_A(win, sfb->variant));
1355         writel(0, regs + VIDOSD_B(win, sfb->variant));
1356         writel(0, regs + VIDOSD_C(win, sfb->variant));
1357         reg = readl(regs + SHADOWCON);
1358         writel(reg & ~SHADOWCON_WINx_PROTECT(win), regs + SHADOWCON);
1359 }
1360
1361 static int __devinit s3c_fb_probe(struct platform_device *pdev)
1362 {
1363         const struct platform_device_id *platid;
1364         struct s3c_fb_driverdata *fbdrv;
1365         struct device *dev = &pdev->dev;
1366         struct s3c_fb_platdata *pd;
1367         struct s3c_fb *sfb;
1368         struct resource *res;
1369         int win;
1370         int ret = 0;
1371         u32 reg;
1372
1373         platid = platform_get_device_id(pdev);
1374         fbdrv = (struct s3c_fb_driverdata *)platid->driver_data;
1375
1376         if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
1377                 dev_err(dev, "too many windows, cannot attach\n");
1378                 return -EINVAL;
1379         }
1380
1381         pd = pdev->dev.platform_data;
1382         if (!pd) {
1383                 dev_err(dev, "no platform data specified\n");
1384                 return -EINVAL;
1385         }
1386
1387         sfb = devm_kzalloc(dev, sizeof(struct s3c_fb), GFP_KERNEL);
1388         if (!sfb) {
1389                 dev_err(dev, "no memory for framebuffers\n");
1390                 return -ENOMEM;
1391         }
1392
1393         dev_dbg(dev, "allocate new framebuffer %p\n", sfb);
1394
1395         sfb->dev = dev;
1396         sfb->pdata = pd;
1397         sfb->variant = fbdrv->variant;
1398
1399         spin_lock_init(&sfb->slock);
1400
1401         sfb->bus_clk = clk_get(dev, "lcd");
1402         if (IS_ERR(sfb->bus_clk)) {
1403                 dev_err(dev, "failed to get bus clock\n");
1404                 ret = PTR_ERR(sfb->bus_clk);
1405                 goto err_sfb;
1406         }
1407
1408         clk_enable(sfb->bus_clk);
1409
1410         if (!sfb->variant.has_clksel) {
1411                 sfb->lcd_clk = clk_get(dev, "sclk_fimd");
1412                 if (IS_ERR(sfb->lcd_clk)) {
1413                         dev_err(dev, "failed to get lcd clock\n");
1414                         ret = PTR_ERR(sfb->lcd_clk);
1415                         goto err_bus_clk;
1416                 }
1417
1418                 clk_enable(sfb->lcd_clk);
1419         }
1420
1421         pm_runtime_enable(sfb->dev);
1422
1423         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1424         if (!res) {
1425                 dev_err(dev, "failed to find registers\n");
1426                 ret = -ENOENT;
1427                 goto err_lcd_clk;
1428         }
1429
1430         sfb->regs = devm_request_and_ioremap(dev, res);
1431         if (!sfb->regs) {
1432                 dev_err(dev, "failed to map registers\n");
1433                 ret = -ENXIO;
1434                 goto err_lcd_clk;
1435         }
1436
1437         res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
1438         if (!res) {
1439                 dev_err(dev, "failed to acquire irq resource\n");
1440                 ret = -ENOENT;
1441                 goto err_lcd_clk;
1442         }
1443         sfb->irq_no = res->start;
1444         ret = devm_request_irq(dev, sfb->irq_no, s3c_fb_irq,
1445                           0, "s3c_fb", sfb);
1446         if (ret) {
1447                 dev_err(dev, "irq request failed\n");
1448                 goto err_lcd_clk;
1449         }
1450
1451         dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
1452
1453         platform_set_drvdata(pdev, sfb);
1454         pm_runtime_get_sync(sfb->dev);
1455
1456         /* setup gpio and output polarity controls */
1457
1458         pd->setup_gpio();
1459
1460         writel(pd->vidcon1, sfb->regs + VIDCON1);
1461
1462         /* set video clock running at under-run */
1463         if (sfb->variant.has_fixvclk) {
1464                 reg = readl(sfb->regs + VIDCON1);
1465                 reg &= ~VIDCON1_VCLK_MASK;
1466                 reg |= VIDCON1_VCLK_RUN;
1467                 writel(reg, sfb->regs + VIDCON1);
1468         }
1469
1470         /* zero all windows before we do anything */
1471
1472         for (win = 0; win < fbdrv->variant.nr_windows; win++)
1473                 s3c_fb_clear_win(sfb, win);
1474
1475         /* initialise colour key controls */
1476         for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
1477                 void __iomem *regs = sfb->regs + sfb->variant.keycon;
1478
1479                 regs += (win * 8);
1480                 writel(0xffffff, regs + WKEYCON0);
1481                 writel(0xffffff, regs + WKEYCON1);
1482         }
1483
1484         /* we have the register setup, start allocating framebuffers */
1485
1486         for (win = 0; win < fbdrv->variant.nr_windows; win++) {
1487                 if (!pd->win[win])
1488                         continue;
1489
1490                 if (!pd->win[win]->win_mode.pixclock)
1491                         s3c_fb_missing_pixclock(&pd->win[win]->win_mode);
1492
1493                 ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
1494                                        &sfb->windows[win]);
1495                 if (ret < 0) {
1496                         dev_err(dev, "failed to create window %d\n", win);
1497                         for (; win >= 0; win--)
1498                                 s3c_fb_release_win(sfb, sfb->windows[win]);
1499                         goto err_pm_runtime;
1500                 }
1501         }
1502
1503         platform_set_drvdata(pdev, sfb);
1504         pm_runtime_put_sync(sfb->dev);
1505
1506         return 0;
1507
1508 err_pm_runtime:
1509         pm_runtime_put_sync(sfb->dev);
1510
1511 err_lcd_clk:
1512         pm_runtime_disable(sfb->dev);
1513
1514         if (!sfb->variant.has_clksel) {
1515                 clk_disable(sfb->lcd_clk);
1516                 clk_put(sfb->lcd_clk);
1517         }
1518
1519 err_bus_clk:
1520         clk_disable(sfb->bus_clk);
1521         clk_put(sfb->bus_clk);
1522
1523 err_sfb:
1524         return ret;
1525 }
1526
1527 /**
1528  * s3c_fb_remove() - Cleanup on module finalisation
1529  * @pdev: The platform device we are bound to.
1530  *
1531  * Shutdown and then release all the resources that the driver allocated
1532  * on initialisation.
1533  */
1534 static int __devexit s3c_fb_remove(struct platform_device *pdev)
1535 {
1536         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1537         int win;
1538
1539         pm_runtime_get_sync(sfb->dev);
1540
1541         for (win = 0; win < S3C_FB_MAX_WIN; win++)
1542                 if (sfb->windows[win])
1543                         s3c_fb_release_win(sfb, sfb->windows[win]);
1544
1545         if (!sfb->variant.has_clksel) {
1546                 clk_disable(sfb->lcd_clk);
1547                 clk_put(sfb->lcd_clk);
1548         }
1549
1550         clk_disable(sfb->bus_clk);
1551         clk_put(sfb->bus_clk);
1552
1553         pm_runtime_put_sync(sfb->dev);
1554         pm_runtime_disable(sfb->dev);
1555
1556         return 0;
1557 }
1558
1559 #ifdef CONFIG_PM_SLEEP
1560 static int s3c_fb_suspend(struct device *dev)
1561 {
1562         struct platform_device *pdev = to_platform_device(dev);
1563         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1564         struct s3c_fb_win *win;
1565         int win_no;
1566
1567         for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
1568                 win = sfb->windows[win_no];
1569                 if (!win)
1570                         continue;
1571
1572                 /* use the blank function to push into power-down */
1573                 s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
1574         }
1575
1576         if (!sfb->variant.has_clksel)
1577                 clk_disable(sfb->lcd_clk);
1578
1579         clk_disable(sfb->bus_clk);
1580         return 0;
1581 }
1582
1583 static int s3c_fb_resume(struct device *dev)
1584 {
1585         struct platform_device *pdev = to_platform_device(dev);
1586         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1587         struct s3c_fb_platdata *pd = sfb->pdata;
1588         struct s3c_fb_win *win;
1589         int win_no;
1590         u32 reg;
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         /* restore framebuffers */
1627         for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
1628                 win = sfb->windows[win_no];
1629                 if (!win)
1630                         continue;
1631
1632                 dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
1633                 s3c_fb_set_par(win->fbinfo);
1634         }
1635
1636         return 0;
1637 }
1638 #endif
1639
1640 #ifdef CONFIG_PM_RUNTIME
1641 static int s3c_fb_runtime_suspend(struct device *dev)
1642 {
1643         struct platform_device *pdev = to_platform_device(dev);
1644         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1645
1646         if (!sfb->variant.has_clksel)
1647                 clk_disable(sfb->lcd_clk);
1648
1649         clk_disable(sfb->bus_clk);
1650
1651         return 0;
1652 }
1653
1654 static int s3c_fb_runtime_resume(struct device *dev)
1655 {
1656         struct platform_device *pdev = to_platform_device(dev);
1657         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1658         struct s3c_fb_platdata *pd = sfb->pdata;
1659
1660         clk_enable(sfb->bus_clk);
1661
1662         if (!sfb->variant.has_clksel)
1663                 clk_enable(sfb->lcd_clk);
1664
1665         /* setup gpio and output polarity controls */
1666         pd->setup_gpio();
1667         writel(pd->vidcon1, sfb->regs + VIDCON1);
1668
1669         return 0;
1670 }
1671 #endif
1672
1673 #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
1674 #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
1675
1676 static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] = {
1677         [0] = {
1678                 .has_osd_c      = 1,
1679                 .osd_size_off   = 0x8,
1680                 .palette_sz     = 256,
1681                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
1682                                    VALID_BPP(18) | VALID_BPP(24)),
1683         },
1684         [1] = {
1685                 .has_osd_c      = 1,
1686                 .has_osd_d      = 1,
1687                 .osd_size_off   = 0xc,
1688                 .has_osd_alpha  = 1,
1689                 .palette_sz     = 256,
1690                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
1691                                    VALID_BPP(18) | VALID_BPP(19) |
1692                                    VALID_BPP(24) | VALID_BPP(25) |
1693                                    VALID_BPP(28)),
1694         },
1695         [2] = {
1696                 .has_osd_c      = 1,
1697                 .has_osd_d      = 1,
1698                 .osd_size_off   = 0xc,
1699                 .has_osd_alpha  = 1,
1700                 .palette_sz     = 16,
1701                 .palette_16bpp  = 1,
1702                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
1703                                    VALID_BPP(18) | VALID_BPP(19) |
1704                                    VALID_BPP(24) | VALID_BPP(25) |
1705                                    VALID_BPP(28)),
1706         },
1707         [3] = {
1708                 .has_osd_c      = 1,
1709                 .has_osd_alpha  = 1,
1710                 .palette_sz     = 16,
1711                 .palette_16bpp  = 1,
1712                 .valid_bpp      = (VALID_BPP124  | VALID_BPP(16) |
1713                                    VALID_BPP(18) | VALID_BPP(19) |
1714                                    VALID_BPP(24) | VALID_BPP(25) |
1715                                    VALID_BPP(28)),
1716         },
1717         [4] = {
1718                 .has_osd_c      = 1,
1719                 .has_osd_alpha  = 1,
1720                 .palette_sz     = 4,
1721                 .palette_16bpp  = 1,
1722                 .valid_bpp      = (VALID_BPP(1) | VALID_BPP(2) |
1723                                    VALID_BPP(16) | VALID_BPP(18) |
1724                                    VALID_BPP(19) | VALID_BPP(24) |
1725                                    VALID_BPP(25) | VALID_BPP(28)),
1726         },
1727 };
1728
1729 static struct s3c_fb_win_variant s3c_fb_data_s5p_wins[] = {
1730         [0] = {
1731                 .has_osd_c      = 1,
1732                 .osd_size_off   = 0x8,
1733                 .palette_sz     = 256,
1734                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
1735                                    VALID_BPP(15) | VALID_BPP(16) |
1736                                    VALID_BPP(18) | VALID_BPP(19) |
1737                                    VALID_BPP(24) | VALID_BPP(25) |
1738                                    VALID_BPP(32)),
1739         },
1740         [1] = {
1741                 .has_osd_c      = 1,
1742                 .has_osd_d      = 1,
1743                 .osd_size_off   = 0xc,
1744                 .has_osd_alpha  = 1,
1745                 .palette_sz     = 256,
1746                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
1747                                    VALID_BPP(15) | VALID_BPP(16) |
1748                                    VALID_BPP(18) | VALID_BPP(19) |
1749                                    VALID_BPP(24) | VALID_BPP(25) |
1750                                    VALID_BPP(32)),
1751         },
1752         [2] = {
1753                 .has_osd_c      = 1,
1754                 .has_osd_d      = 1,
1755                 .osd_size_off   = 0xc,
1756                 .has_osd_alpha  = 1,
1757                 .palette_sz     = 256,
1758                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
1759                                    VALID_BPP(15) | VALID_BPP(16) |
1760                                    VALID_BPP(18) | VALID_BPP(19) |
1761                                    VALID_BPP(24) | VALID_BPP(25) |
1762                                    VALID_BPP(32)),
1763         },
1764         [3] = {
1765                 .has_osd_c      = 1,
1766                 .has_osd_alpha  = 1,
1767                 .palette_sz     = 256,
1768                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
1769                                    VALID_BPP(15) | VALID_BPP(16) |
1770                                    VALID_BPP(18) | VALID_BPP(19) |
1771                                    VALID_BPP(24) | VALID_BPP(25) |
1772                                    VALID_BPP(32)),
1773         },
1774         [4] = {
1775                 .has_osd_c      = 1,
1776                 .has_osd_alpha  = 1,
1777                 .palette_sz     = 256,
1778                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(13) |
1779                                    VALID_BPP(15) | VALID_BPP(16) |
1780                                    VALID_BPP(18) | VALID_BPP(19) |
1781                                    VALID_BPP(24) | VALID_BPP(25) |
1782                                    VALID_BPP(32)),
1783         },
1784 };
1785
1786 static struct s3c_fb_driverdata s3c_fb_data_64xx = {
1787         .variant = {
1788                 .nr_windows     = 5,
1789                 .vidtcon        = VIDTCON0,
1790                 .wincon         = WINCON(0),
1791                 .winmap         = WINxMAP(0),
1792                 .keycon         = WKEYCON,
1793                 .osd            = VIDOSD_BASE,
1794                 .osd_stride     = 16,
1795                 .buf_start      = VIDW_BUF_START(0),
1796                 .buf_size       = VIDW_BUF_SIZE(0),
1797                 .buf_end        = VIDW_BUF_END(0),
1798
1799                 .palette = {
1800                         [0] = 0x400,
1801                         [1] = 0x800,
1802                         [2] = 0x300,
1803                         [3] = 0x320,
1804                         [4] = 0x340,
1805                 },
1806
1807                 .has_prtcon     = 1,
1808                 .has_clksel     = 1,
1809         },
1810         .win[0] = &s3c_fb_data_64xx_wins[0],
1811         .win[1] = &s3c_fb_data_64xx_wins[1],
1812         .win[2] = &s3c_fb_data_64xx_wins[2],
1813         .win[3] = &s3c_fb_data_64xx_wins[3],
1814         .win[4] = &s3c_fb_data_64xx_wins[4],
1815 };
1816
1817 static struct s3c_fb_driverdata s3c_fb_data_s5pc100 = {
1818         .variant = {
1819                 .nr_windows     = 5,
1820                 .vidtcon        = VIDTCON0,
1821                 .wincon         = WINCON(0),
1822                 .winmap         = WINxMAP(0),
1823                 .keycon         = WKEYCON,
1824                 .osd            = VIDOSD_BASE,
1825                 .osd_stride     = 16,
1826                 .buf_start      = VIDW_BUF_START(0),
1827                 .buf_size       = VIDW_BUF_SIZE(0),
1828                 .buf_end        = VIDW_BUF_END(0),
1829
1830                 .palette = {
1831                         [0] = 0x2400,
1832                         [1] = 0x2800,
1833                         [2] = 0x2c00,
1834                         [3] = 0x3000,
1835                         [4] = 0x3400,
1836                 },
1837
1838                 .has_prtcon     = 1,
1839                 .has_blendcon   = 1,
1840                 .has_clksel     = 1,
1841         },
1842         .win[0] = &s3c_fb_data_s5p_wins[0],
1843         .win[1] = &s3c_fb_data_s5p_wins[1],
1844         .win[2] = &s3c_fb_data_s5p_wins[2],
1845         .win[3] = &s3c_fb_data_s5p_wins[3],
1846         .win[4] = &s3c_fb_data_s5p_wins[4],
1847 };
1848
1849 static struct s3c_fb_driverdata s3c_fb_data_s5pv210 = {
1850         .variant = {
1851                 .nr_windows     = 5,
1852                 .vidtcon        = VIDTCON0,
1853                 .wincon         = WINCON(0),
1854                 .winmap         = WINxMAP(0),
1855                 .keycon         = WKEYCON,
1856                 .osd            = VIDOSD_BASE,
1857                 .osd_stride     = 16,
1858                 .buf_start      = VIDW_BUF_START(0),
1859                 .buf_size       = VIDW_BUF_SIZE(0),
1860                 .buf_end        = VIDW_BUF_END(0),
1861
1862                 .palette = {
1863                         [0] = 0x2400,
1864                         [1] = 0x2800,
1865                         [2] = 0x2c00,
1866                         [3] = 0x3000,
1867                         [4] = 0x3400,
1868                 },
1869
1870                 .has_shadowcon  = 1,
1871                 .has_blendcon   = 1,
1872                 .has_clksel     = 1,
1873                 .has_fixvclk    = 1,
1874         },
1875         .win[0] = &s3c_fb_data_s5p_wins[0],
1876         .win[1] = &s3c_fb_data_s5p_wins[1],
1877         .win[2] = &s3c_fb_data_s5p_wins[2],
1878         .win[3] = &s3c_fb_data_s5p_wins[3],
1879         .win[4] = &s3c_fb_data_s5p_wins[4],
1880 };
1881
1882 static struct s3c_fb_driverdata s3c_fb_data_exynos4 = {
1883         .variant = {
1884                 .nr_windows     = 5,
1885                 .vidtcon        = VIDTCON0,
1886                 .wincon         = WINCON(0),
1887                 .winmap         = WINxMAP(0),
1888                 .keycon         = WKEYCON,
1889                 .osd            = VIDOSD_BASE,
1890                 .osd_stride     = 16,
1891                 .buf_start      = VIDW_BUF_START(0),
1892                 .buf_size       = VIDW_BUF_SIZE(0),
1893                 .buf_end        = VIDW_BUF_END(0),
1894
1895                 .palette = {
1896                         [0] = 0x2400,
1897                         [1] = 0x2800,
1898                         [2] = 0x2c00,
1899                         [3] = 0x3000,
1900                         [4] = 0x3400,
1901                 },
1902
1903                 .has_shadowcon  = 1,
1904                 .has_blendcon   = 1,
1905                 .has_fixvclk    = 1,
1906         },
1907         .win[0] = &s3c_fb_data_s5p_wins[0],
1908         .win[1] = &s3c_fb_data_s5p_wins[1],
1909         .win[2] = &s3c_fb_data_s5p_wins[2],
1910         .win[3] = &s3c_fb_data_s5p_wins[3],
1911         .win[4] = &s3c_fb_data_s5p_wins[4],
1912 };
1913
1914 static struct s3c_fb_driverdata s3c_fb_data_exynos5 = {
1915         .variant = {
1916                 .nr_windows     = 5,
1917                 .vidtcon        = VIDTCON0,
1918                 .wincon         = WINCON(0),
1919                 .winmap         = WINxMAP(0),
1920                 .keycon         = WKEYCON,
1921                 .osd            = VIDOSD_BASE,
1922                 .osd_stride     = 16,
1923                 .buf_start      = VIDW_BUF_START(0),
1924                 .buf_size       = VIDW_BUF_SIZE(0),
1925                 .buf_end        = VIDW_BUF_END(0),
1926
1927                 .palette = {
1928                         [0] = 0x2400,
1929                         [1] = 0x2800,
1930                         [2] = 0x2c00,
1931                         [3] = 0x3000,
1932                         [4] = 0x3400,
1933                 },
1934                 .has_shadowcon  = 1,
1935                 .has_blendcon   = 1,
1936                 .has_fixvclk    = 1,
1937         },
1938         .win[0] = &s3c_fb_data_s5p_wins[0],
1939         .win[1] = &s3c_fb_data_s5p_wins[1],
1940         .win[2] = &s3c_fb_data_s5p_wins[2],
1941         .win[3] = &s3c_fb_data_s5p_wins[3],
1942         .win[4] = &s3c_fb_data_s5p_wins[4],
1943 };
1944
1945 /* S3C2443/S3C2416 style hardware */
1946 static struct s3c_fb_driverdata s3c_fb_data_s3c2443 = {
1947         .variant = {
1948                 .nr_windows     = 2,
1949                 .is_2443        = 1,
1950
1951                 .vidtcon        = 0x08,
1952                 .wincon         = 0x14,
1953                 .winmap         = 0xd0,
1954                 .keycon         = 0xb0,
1955                 .osd            = 0x28,
1956                 .osd_stride     = 12,
1957                 .buf_start      = 0x64,
1958                 .buf_size       = 0x94,
1959                 .buf_end        = 0x7c,
1960
1961                 .palette = {
1962                         [0] = 0x400,
1963                         [1] = 0x800,
1964                 },
1965                 .has_clksel     = 1,
1966         },
1967         .win[0] = &(struct s3c_fb_win_variant) {
1968                 .palette_sz     = 256,
1969                 .valid_bpp      = VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
1970         },
1971         .win[1] = &(struct s3c_fb_win_variant) {
1972                 .has_osd_c      = 1,
1973                 .has_osd_alpha  = 1,
1974                 .palette_sz     = 256,
1975                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
1976                                    VALID_BPP(18) | VALID_BPP(19) |
1977                                    VALID_BPP(24) | VALID_BPP(25) |
1978                                    VALID_BPP(28)),
1979         },
1980 };
1981
1982 static struct s3c_fb_driverdata s3c_fb_data_s5p64x0 = {
1983         .variant = {
1984                 .nr_windows     = 3,
1985                 .vidtcon        = VIDTCON0,
1986                 .wincon         = WINCON(0),
1987                 .winmap         = WINxMAP(0),
1988                 .keycon         = WKEYCON,
1989                 .osd            = VIDOSD_BASE,
1990                 .osd_stride     = 16,
1991                 .buf_start      = VIDW_BUF_START(0),
1992                 .buf_size       = VIDW_BUF_SIZE(0),
1993                 .buf_end        = VIDW_BUF_END(0),
1994
1995                 .palette = {
1996                         [0] = 0x2400,
1997                         [1] = 0x2800,
1998                         [2] = 0x2c00,
1999                 },
2000
2001                 .has_blendcon   = 1,
2002                 .has_fixvclk    = 1,
2003         },
2004         .win[0] = &s3c_fb_data_s5p_wins[0],
2005         .win[1] = &s3c_fb_data_s5p_wins[1],
2006         .win[2] = &s3c_fb_data_s5p_wins[2],
2007 };
2008
2009 static struct platform_device_id s3c_fb_driver_ids[] = {
2010         {
2011                 .name           = "s3c-fb",
2012                 .driver_data    = (unsigned long)&s3c_fb_data_64xx,
2013         }, {
2014                 .name           = "s5pc100-fb",
2015                 .driver_data    = (unsigned long)&s3c_fb_data_s5pc100,
2016         }, {
2017                 .name           = "s5pv210-fb",
2018                 .driver_data    = (unsigned long)&s3c_fb_data_s5pv210,
2019         }, {
2020                 .name           = "exynos4-fb",
2021                 .driver_data    = (unsigned long)&s3c_fb_data_exynos4,
2022         }, {
2023                 .name           = "exynos5-fb",
2024                 .driver_data    = (unsigned long)&s3c_fb_data_exynos5,
2025         }, {
2026                 .name           = "s3c2443-fb",
2027                 .driver_data    = (unsigned long)&s3c_fb_data_s3c2443,
2028         }, {
2029                 .name           = "s5p64x0-fb",
2030                 .driver_data    = (unsigned long)&s3c_fb_data_s5p64x0,
2031         },
2032         {},
2033 };
2034 MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
2035
2036 static const struct dev_pm_ops s3cfb_pm_ops = {
2037         SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume)
2038         SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume,
2039                            NULL)
2040 };
2041
2042 static struct platform_driver s3c_fb_driver = {
2043         .probe          = s3c_fb_probe,
2044         .remove         = __devexit_p(s3c_fb_remove),
2045         .id_table       = s3c_fb_driver_ids,
2046         .driver         = {
2047                 .name   = "s3c-fb",
2048                 .owner  = THIS_MODULE,
2049                 .pm     = &s3cfb_pm_ops,
2050         },
2051 };
2052
2053 module_platform_driver(s3c_fb_driver);
2054
2055 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
2056 MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
2057 MODULE_LICENSE("GPL");
2058 MODULE_ALIAS("platform:s3c-fb");