Version:  2.6.34 2.6.35 2.6.36 2.6.37 2.6.38 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us