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