]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/video/s3c-fb.c
e700cfd50023cc15bb0b2af9bf95c3c8dd3a3018
[net-next-2.6.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
25 #include <mach/map.h>
26 #include <mach/regs-fb.h>
27 #include <plat/fb.h>
28
29 /* This driver will export a number of framebuffer interfaces depending
30  * on the configuration passed in via the platform data. Each fb instance
31  * maps to a hardware window. Currently there is no support for runtime
32  * setting of the alpha-blending functions that each window has, so only
33  * window 0 is actually useful.
34  *
35  * Window 0 is treated specially, it is used for the basis of the LCD
36  * output timings and as the control for the output power-down state.
37 */
38
39 /* note, the previous use of <mach/regs-fb.h> to get platform specific data
40  * has been replaced by using the platform device name to pick the correct
41  * configuration data for the system.
42 */
43
44 #ifdef CONFIG_FB_S3C_DEBUG_REGWRITE
45 #undef writel
46 #define writel(v, r) do { \
47         printk(KERN_DEBUG "%s: %08x => %p\n", __func__, (unsigned int)v, r); \
48         __raw_writel(v, r); } while(0)
49 #endif /* FB_S3C_DEBUG_REGWRITE */
50
51 struct s3c_fb;
52
53 #define VALID_BPP(x) (1 << ((x) - 1))
54
55 /**
56  * struct s3c_fb_variant - fb variant information
57  * @nr_windows: The number of windows.
58  * @palette: Address of palette memory, or 0 if none.
59  */
60 struct s3c_fb_variant {
61         unsigned short  nr_windows;
62         unsigned short  palette[S3C_FB_MAX_WIN];
63 };
64
65 /**
66  * struct s3c_fb_win_variant
67  * @has_osd_c: Set if has OSD C register.
68  * @has_osd_d: Set if has OSD D register.
69  * @palette_sz: Size of palette in entries.
70  * @palette_16bpp: Set if palette is 16bits wide.
71  * @valid_bpp: 1 bit per BPP setting to show valid bits-per-pixel.
72  *
73  * valid_bpp bit x is set if (x+1)BPP is supported.
74  */
75 struct s3c_fb_win_variant {
76         unsigned int    has_osd_c:1;
77         unsigned int    has_osd_d:1;
78         unsigned int    palette_16bpp:1;
79         unsigned short  palette_sz;
80         u32             valid_bpp;
81 };
82
83 /**
84  * struct s3c_fb_driverdata - per-device type driver data for init time.
85  * @variant: The variant information for this driver.
86  * @win: The window information for each window.
87  */
88 struct s3c_fb_driverdata {
89         struct s3c_fb_variant   variant;
90         struct s3c_fb_win_variant *win[S3C_FB_MAX_WIN];
91 };
92
93 /**
94  * struct s3c_fb_win - per window private data for each framebuffer.
95  * @windata: The platform data supplied for the window configuration.
96  * @parent: The hardware that this window is part of.
97  * @fbinfo: Pointer pack to the framebuffer info for this window.
98  * @varint: The variant information for this window.
99  * @palette_buffer: Buffer/cache to hold palette entries.
100  * @pseudo_palette: For use in TRUECOLOUR modes for entries 0..15/
101  * @index: The window number of this window.
102  * @palette: The bitfields for changing r/g/b into a hardware palette entry.
103  */
104 struct s3c_fb_win {
105         struct s3c_fb_pd_win    *windata;
106         struct s3c_fb           *parent;
107         struct fb_info          *fbinfo;
108         struct s3c_fb_palette    palette;
109         struct s3c_fb_win_variant variant;
110
111         u32                     *palette_buffer;
112         u32                      pseudo_palette[16];
113         unsigned int             index;
114 };
115
116 /**
117  * struct s3c_fb - overall hardware state of the hardware
118  * @dev: The device that we bound to, for printing, etc.
119  * @regs_res: The resource we claimed for the IO registers.
120  * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk.
121  * @regs: The mapped hardware registers.
122  * @variant: Variant information for this hardware.
123  * @enabled: A bitmask of enabled hardware windows.
124  * @pdata: The platform configuration data passed with the device.
125  * @windows: The hardware windows that have been claimed.
126  */
127 struct s3c_fb {
128         struct device           *dev;
129         struct resource         *regs_res;
130         struct clk              *bus_clk;
131         void __iomem            *regs;
132         struct s3c_fb_variant    variant;
133
134         unsigned char            enabled;
135
136         struct s3c_fb_platdata  *pdata;
137         struct s3c_fb_win       *windows[S3C_FB_MAX_WIN];
138 };
139
140 /**
141  * s3c_fb_validate_win_bpp - validate the bits-per-pixel for this mode.
142  * @win: The device window.
143  * @bpp: The bit depth.
144  */
145 static bool s3c_fb_validate_win_bpp(struct s3c_fb_win *win, unsigned int bpp)
146 {
147         return win->variant.valid_bpp & VALID_BPP(bpp);
148 }
149
150 /**
151  * s3c_fb_check_var() - framebuffer layer request to verify a given mode.
152  * @var: The screen information to verify.
153  * @info: The framebuffer device.
154  *
155  * Framebuffer layer call to verify the given information and allow us to
156  * update various information depending on the hardware capabilities.
157  */
158 static int s3c_fb_check_var(struct fb_var_screeninfo *var,
159                             struct fb_info *info)
160 {
161         struct s3c_fb_win *win = info->par;
162         struct s3c_fb_pd_win *windata = win->windata;
163         struct s3c_fb *sfb = win->parent;
164
165         dev_dbg(sfb->dev, "checking parameters\n");
166
167         var->xres_virtual = max((unsigned int)windata->virtual_x, var->xres);
168         var->yres_virtual = max((unsigned int)windata->virtual_y, var->yres);
169
170         if (!s3c_fb_validate_win_bpp(win, var->bits_per_pixel)) {
171                 dev_dbg(sfb->dev, "win %d: unsupported bpp %d\n",
172                         win->index, var->bits_per_pixel);
173                 return -EINVAL;
174         }
175
176         /* always ensure these are zero, for drop through cases below */
177         var->transp.offset = 0;
178         var->transp.length = 0;
179
180         switch (var->bits_per_pixel) {
181         case 1:
182         case 2:
183         case 4:
184         case 8:
185                 if (sfb->variant.palette[win->index] != 0) {
186                         /* non palletised, A:1,R:2,G:3,B:2 mode */
187                         var->red.offset         = 4;
188                         var->green.offset       = 2;
189                         var->blue.offset        = 0;
190                         var->red.length         = 5;
191                         var->green.length       = 3;
192                         var->blue.length        = 2;
193                         var->transp.offset      = 7;
194                         var->transp.length      = 1;
195                 } else {
196                         var->red.offset = 0;
197                         var->red.length = var->bits_per_pixel;
198                         var->green      = var->red;
199                         var->blue       = var->red;
200                 }
201                 break;
202
203         case 19:
204                 /* 666 with one bit alpha/transparency */
205                 var->transp.offset      = 18;
206                 var->transp.length      = 1;
207         case 18:
208                 var->bits_per_pixel     = 32;
209
210                 /* 666 format */
211                 var->red.offset         = 12;
212                 var->green.offset       = 6;
213                 var->blue.offset        = 0;
214                 var->red.length         = 6;
215                 var->green.length       = 6;
216                 var->blue.length        = 6;
217                 break;
218
219         case 16:
220                 /* 16 bpp, 565 format */
221                 var->red.offset         = 11;
222                 var->green.offset       = 5;
223                 var->blue.offset        = 0;
224                 var->red.length         = 5;
225                 var->green.length       = 6;
226                 var->blue.length        = 5;
227                 break;
228
229         case 28:
230         case 25:
231                 var->transp.length      = var->bits_per_pixel - 24;
232                 var->transp.offset      = 24;
233                 /* drop through */
234         case 24:
235                 /* our 24bpp is unpacked, so 32bpp */
236                 var->bits_per_pixel     = 32;
237         case 32:
238                 var->red.offset         = 16;
239                 var->red.length         = 8;
240                 var->green.offset       = 8;
241                 var->green.length       = 8;
242                 var->blue.offset        = 0;
243                 var->blue.length        = 8;
244                 break;
245
246         default:
247                 dev_err(sfb->dev, "invalid bpp\n");
248         }
249
250         dev_dbg(sfb->dev, "%s: verified parameters\n", __func__);
251         return 0;
252 }
253
254 /**
255  * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
256  * @sfb: The hardware state.
257  * @pixclock: The pixel clock wanted, in picoseconds.
258  *
259  * Given the specified pixel clock, work out the necessary divider to get
260  * close to the output frequency.
261  */
262 static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
263 {
264         unsigned long clk = clk_get_rate(sfb->bus_clk);
265         unsigned long long tmp;
266         unsigned int result;
267
268         tmp = (unsigned long long)clk;
269         tmp *= pixclk;
270
271         do_div(tmp, 1000000000UL);
272         result = (unsigned int)tmp / 1000;
273
274         dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
275                 pixclk, clk, result, clk / result);
276
277         return result;
278 }
279
280 /**
281  * s3c_fb_align_word() - align pixel count to word boundary
282  * @bpp: The number of bits per pixel
283  * @pix: The value to be aligned.
284  *
285  * Align the given pixel count so that it will start on an 32bit word
286  * boundary.
287  */
288 static int s3c_fb_align_word(unsigned int bpp, unsigned int pix)
289 {
290         int pix_per_word;
291
292         if (bpp > 16)
293                 return pix;
294
295         pix_per_word = (8 * 32) / bpp;
296         return ALIGN(pix, pix_per_word);
297 }
298
299 /**
300  * s3c_fb_set_par() - framebuffer request to set new framebuffer state.
301  * @info: The framebuffer to change.
302  *
303  * Framebuffer layer request to set a new mode for the specified framebuffer
304  */
305 static int s3c_fb_set_par(struct fb_info *info)
306 {
307         struct fb_var_screeninfo *var = &info->var;
308         struct s3c_fb_win *win = info->par;
309         struct s3c_fb *sfb = win->parent;
310         void __iomem *regs = sfb->regs;
311         int win_no = win->index;
312         u32 osdc_data = 0;
313         u32 data;
314         u32 pagewidth;
315         int clkdiv;
316
317         dev_dbg(sfb->dev, "setting framebuffer parameters\n");
318
319         switch (var->bits_per_pixel) {
320         case 32:
321         case 24:
322         case 16:
323         case 12:
324                 info->fix.visual = FB_VISUAL_TRUECOLOR;
325                 break;
326         case 8:
327                 if (win->variant.palette_sz >= 256)
328                         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
329                 else
330                         info->fix.visual = FB_VISUAL_TRUECOLOR;
331                 break;
332         case 1:
333                 info->fix.visual = FB_VISUAL_MONO01;
334                 break;
335         default:
336                 info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
337                 break;
338         }
339
340         info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;
341
342         /* disable the window whilst we update it */
343         writel(0, regs + WINCON(win_no));
344
345         /* use platform specified window as the basis for the lcd timings */
346
347         if (win_no == sfb->pdata->default_win) {
348                 clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
349
350                 data = sfb->pdata->vidcon0;
351                 data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
352
353                 if (clkdiv > 1)
354                         data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR;
355                 else
356                         data &= ~VIDCON0_CLKDIR;        /* 1:1 clock */
357
358                 /* write the timing data to the panel */
359
360                 data |= VIDCON0_ENVID | VIDCON0_ENVID_F;
361                 writel(data, regs + VIDCON0);
362
363                 data = VIDTCON0_VBPD(var->upper_margin - 1) |
364                        VIDTCON0_VFPD(var->lower_margin - 1) |
365                        VIDTCON0_VSPW(var->vsync_len - 1);
366
367                 writel(data, regs + VIDTCON0);
368
369                 data = VIDTCON1_HBPD(var->left_margin - 1) |
370                        VIDTCON1_HFPD(var->right_margin - 1) |
371                        VIDTCON1_HSPW(var->hsync_len - 1);
372
373                 writel(data, regs + VIDTCON1);
374
375                 data = VIDTCON2_LINEVAL(var->yres - 1) |
376                        VIDTCON2_HOZVAL(var->xres - 1);
377                 writel(data, regs + VIDTCON2);
378         }
379
380         /* write the buffer address */
381
382         writel(info->fix.smem_start, regs + VIDW_BUF_START(win_no));
383
384         data = info->fix.smem_start + info->fix.line_length * var->yres;
385         writel(data, regs + VIDW_BUF_END(win_no));
386
387         pagewidth = (var->xres * var->bits_per_pixel) >> 3;
388         data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) |
389                VIDW_BUF_SIZE_PAGEWIDTH(pagewidth);
390         writel(data, regs + VIDW_BUF_SIZE(win_no));
391
392         /* write 'OSD' registers to control position of framebuffer */
393
394         data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0);
395         writel(data, regs + VIDOSD_A(win_no));
396
397         data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel,
398                                                      var->xres - 1)) |
399                VIDOSDxB_BOTRIGHT_Y(var->yres - 1);
400
401         writel(data, regs + VIDOSD_B(win_no));
402
403         data = var->xres * var->yres;
404
405         osdc_data = VIDISD14C_ALPHA1_R(0xf) |
406                 VIDISD14C_ALPHA1_G(0xf) |
407                 VIDISD14C_ALPHA1_B(0xf);
408
409         if (win->variant.has_osd_d) {
410                 writel(data, regs + VIDOSD_D(win_no));
411                 writel(osdc_data, regs + VIDOSD_C(win_no));
412         } else
413                 writel(data, regs + VIDOSD_C(win_no));
414
415         data = WINCONx_ENWIN;
416
417         /* note, since we have to round up the bits-per-pixel, we end up
418          * relying on the bitfield information for r/g/b/a to work out
419          * exactly which mode of operation is intended. */
420
421         switch (var->bits_per_pixel) {
422         case 1:
423                 data |= WINCON0_BPPMODE_1BPP;
424                 data |= WINCONx_BITSWP;
425                 data |= WINCONx_BURSTLEN_4WORD;
426                 break;
427         case 2:
428                 data |= WINCON0_BPPMODE_2BPP;
429                 data |= WINCONx_BITSWP;
430                 data |= WINCONx_BURSTLEN_8WORD;
431                 break;
432         case 4:
433                 data |= WINCON0_BPPMODE_4BPP;
434                 data |= WINCONx_BITSWP;
435                 data |= WINCONx_BURSTLEN_8WORD;
436                 break;
437         case 8:
438                 if (var->transp.length != 0)
439                         data |= WINCON1_BPPMODE_8BPP_1232;
440                 else
441                         data |= WINCON0_BPPMODE_8BPP_PALETTE;
442                 data |= WINCONx_BURSTLEN_8WORD;
443                 data |= WINCONx_BYTSWP;
444                 break;
445         case 16:
446                 if (var->transp.length != 0)
447                         data |= WINCON1_BPPMODE_16BPP_A1555;
448                 else
449                         data |= WINCON0_BPPMODE_16BPP_565;
450                 data |= WINCONx_HAWSWP;
451                 data |= WINCONx_BURSTLEN_16WORD;
452                 break;
453         case 24:
454         case 32:
455                 if (var->red.length == 6) {
456                         if (var->transp.length != 0)
457                                 data |= WINCON1_BPPMODE_19BPP_A1666;
458                         else
459                                 data |= WINCON1_BPPMODE_18BPP_666;
460                 } else if (var->transp.length == 1)
461                         data |= WINCON1_BPPMODE_25BPP_A1888
462                                 | WINCON1_BLD_PIX;
463                 else if (var->transp.length == 4)
464                         data |= WINCON1_BPPMODE_28BPP_A4888
465                                 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
466                 else
467                         data |= WINCON0_BPPMODE_24BPP_888;
468
469                 data |= WINCONx_WSWP;
470                 data |= WINCONx_BURSTLEN_16WORD;
471                 break;
472         }
473
474         /* It has no color key control register for window0 */
475         if (win_no > 0) {
476                 u32 keycon0_data = 0, keycon1_data = 0;
477
478                 keycon0_data = ~(WxKEYCON0_KEYBL_EN |
479                                 WxKEYCON0_KEYEN_F |
480                                 WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
481
482                 keycon1_data = WxKEYCON1_COLVAL(0xffffff);
483
484                 writel(keycon0_data, regs + WxKEYCONy(win_no-1, 0));
485                 writel(keycon1_data, regs + WxKEYCONy(win_no-1, 1));
486         }
487
488         writel(data, regs + WINCON(win_no));
489         writel(0x0, regs + WINxMAP(win_no));
490
491         return 0;
492 }
493
494 /**
495  * s3c_fb_update_palette() - set or schedule a palette update.
496  * @sfb: The hardware information.
497  * @win: The window being updated.
498  * @reg: The palette index being changed.
499  * @value: The computed palette value.
500  *
501  * Change the value of a palette register, either by directly writing to
502  * the palette (this requires the palette RAM to be disconnected from the
503  * hardware whilst this is in progress) or schedule the update for later.
504  *
505  * At the moment, since we have no VSYNC interrupt support, we simply set
506  * the palette entry directly.
507  */
508 static void s3c_fb_update_palette(struct s3c_fb *sfb,
509                                   struct s3c_fb_win *win,
510                                   unsigned int reg,
511                                   u32 value)
512 {
513         void __iomem *palreg;
514         u32 palcon;
515
516         palreg = sfb->regs + sfb->variant.palette[win->index];
517
518         dev_dbg(sfb->dev, "%s: win %d, reg %d (%p): %08x\n",
519                 __func__, win->index, reg, palreg, value);
520
521         win->palette_buffer[reg] = value;
522
523         palcon = readl(sfb->regs + WPALCON);
524         writel(palcon | WPALCON_PAL_UPDATE, sfb->regs + WPALCON);
525
526         if (win->variant.palette_16bpp)
527                 writew(value, palreg + (reg * 2));
528         else
529                 writel(value, palreg + (reg * 4));
530
531         writel(palcon, sfb->regs + WPALCON);
532 }
533
534 static inline unsigned int chan_to_field(unsigned int chan,
535                                          struct fb_bitfield *bf)
536 {
537         chan &= 0xffff;
538         chan >>= 16 - bf->length;
539         return chan << bf->offset;
540 }
541
542 /**
543  * s3c_fb_setcolreg() - framebuffer layer request to change palette.
544  * @regno: The palette index to change.
545  * @red: The red field for the palette data.
546  * @green: The green field for the palette data.
547  * @blue: The blue field for the palette data.
548  * @trans: The transparency (alpha) field for the palette data.
549  * @info: The framebuffer being changed.
550  */
551 static int s3c_fb_setcolreg(unsigned regno,
552                             unsigned red, unsigned green, unsigned blue,
553                             unsigned transp, struct fb_info *info)
554 {
555         struct s3c_fb_win *win = info->par;
556         struct s3c_fb *sfb = win->parent;
557         unsigned int val;
558
559         dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n",
560                 __func__, win->index, regno, red, green, blue);
561
562         switch (info->fix.visual) {
563         case FB_VISUAL_TRUECOLOR:
564                 /* true-colour, use pseudo-palette */
565
566                 if (regno < 16) {
567                         u32 *pal = info->pseudo_palette;
568
569                         val  = chan_to_field(red,   &info->var.red);
570                         val |= chan_to_field(green, &info->var.green);
571                         val |= chan_to_field(blue,  &info->var.blue);
572
573                         pal[regno] = val;
574                 }
575                 break;
576
577         case FB_VISUAL_PSEUDOCOLOR:
578                 if (regno < win->variant.palette_sz) {
579                         val  = chan_to_field(red, &win->palette.r);
580                         val |= chan_to_field(green, &win->palette.g);
581                         val |= chan_to_field(blue, &win->palette.b);
582
583                         s3c_fb_update_palette(sfb, win, regno, val);
584                 }
585
586                 break;
587
588         default:
589                 return 1;       /* unknown type */
590         }
591
592         return 0;
593 }
594
595 /**
596  * s3c_fb_enable() - Set the state of the main LCD output
597  * @sfb: The main framebuffer state.
598  * @enable: The state to set.
599  */
600 static void s3c_fb_enable(struct s3c_fb *sfb, int enable)
601 {
602         u32 vidcon0 = readl(sfb->regs + VIDCON0);
603
604         if (enable)
605                 vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F;
606         else {
607                 /* see the note in the framebuffer datasheet about
608                  * why you cannot take both of these bits down at the
609                  * same time. */
610
611                 if (!(vidcon0 & VIDCON0_ENVID))
612                         return;
613
614                 vidcon0 |= VIDCON0_ENVID;
615                 vidcon0 &= ~VIDCON0_ENVID_F;
616         }
617
618         writel(vidcon0, sfb->regs + VIDCON0);
619 }
620
621 /**
622  * s3c_fb_blank() - blank or unblank the given window
623  * @blank_mode: The blank state from FB_BLANK_*
624  * @info: The framebuffer to blank.
625  *
626  * Framebuffer layer request to change the power state.
627  */
628 static int s3c_fb_blank(int blank_mode, struct fb_info *info)
629 {
630         struct s3c_fb_win *win = info->par;
631         struct s3c_fb *sfb = win->parent;
632         unsigned int index = win->index;
633         u32 wincon;
634
635         dev_dbg(sfb->dev, "blank mode %d\n", blank_mode);
636
637         wincon = readl(sfb->regs + WINCON(index));
638
639         switch (blank_mode) {
640         case FB_BLANK_POWERDOWN:
641                 wincon &= ~WINCONx_ENWIN;
642                 sfb->enabled &= ~(1 << index);
643                 /* fall through to FB_BLANK_NORMAL */
644
645         case FB_BLANK_NORMAL:
646                 /* disable the DMA and display 0x0 (black) */
647                 writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0),
648                        sfb->regs + WINxMAP(index));
649                 break;
650
651         case FB_BLANK_UNBLANK:
652                 writel(0x0, sfb->regs + WINxMAP(index));
653                 wincon |= WINCONx_ENWIN;
654                 sfb->enabled |= (1 << index);
655                 break;
656
657         case FB_BLANK_VSYNC_SUSPEND:
658         case FB_BLANK_HSYNC_SUSPEND:
659         default:
660                 return 1;
661         }
662
663         writel(wincon, sfb->regs + WINCON(index));
664
665         /* Check the enabled state to see if we need to be running the
666          * main LCD interface, as if there are no active windows then
667          * it is highly likely that we also do not need to output
668          * anything.
669          */
670
671         /* We could do something like the following code, but the current
672          * system of using framebuffer events means that we cannot make
673          * the distinction between just window 0 being inactive and all
674          * the windows being down.
675          *
676          * s3c_fb_enable(sfb, sfb->enabled ? 1 : 0);
677         */
678
679         /* we're stuck with this until we can do something about overriding
680          * the power control using the blanking event for a single fb.
681          */
682         if (index == sfb->pdata->default_win)
683                 s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0);
684
685         return 0;
686 }
687
688 static struct fb_ops s3c_fb_ops = {
689         .owner          = THIS_MODULE,
690         .fb_check_var   = s3c_fb_check_var,
691         .fb_set_par     = s3c_fb_set_par,
692         .fb_blank       = s3c_fb_blank,
693         .fb_setcolreg   = s3c_fb_setcolreg,
694         .fb_fillrect    = cfb_fillrect,
695         .fb_copyarea    = cfb_copyarea,
696         .fb_imageblit   = cfb_imageblit,
697 };
698
699 /**
700  * s3c_fb_alloc_memory() - allocate display memory for framebuffer window
701  * @sfb: The base resources for the hardware.
702  * @win: The window to initialise memory for.
703  *
704  * Allocate memory for the given framebuffer.
705  */
706 static int __devinit s3c_fb_alloc_memory(struct s3c_fb *sfb,
707                                          struct s3c_fb_win *win)
708 {
709         struct s3c_fb_pd_win *windata = win->windata;
710         unsigned int real_size, virt_size, size;
711         struct fb_info *fbi = win->fbinfo;
712         dma_addr_t map_dma;
713
714         dev_dbg(sfb->dev, "allocating memory for display\n");
715
716         real_size = windata->win_mode.xres * windata->win_mode.yres;
717         virt_size = windata->virtual_x * windata->virtual_y;
718
719         dev_dbg(sfb->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
720                 real_size, windata->win_mode.xres, windata->win_mode.yres,
721                 virt_size, windata->virtual_x, windata->virtual_y);
722
723         size = (real_size > virt_size) ? real_size : virt_size;
724         size *= (windata->max_bpp > 16) ? 32 : windata->max_bpp;
725         size /= 8;
726
727         fbi->fix.smem_len = size;
728         size = PAGE_ALIGN(size);
729
730         dev_dbg(sfb->dev, "want %u bytes for window\n", size);
731
732         fbi->screen_base = dma_alloc_writecombine(sfb->dev, size,
733                                                   &map_dma, GFP_KERNEL);
734         if (!fbi->screen_base)
735                 return -ENOMEM;
736
737         dev_dbg(sfb->dev, "mapped %x to %p\n",
738                 (unsigned int)map_dma, fbi->screen_base);
739
740         memset(fbi->screen_base, 0x0, size);
741         fbi->fix.smem_start = map_dma;
742
743         return 0;
744 }
745
746 /**
747  * s3c_fb_free_memory() - free the display memory for the given window
748  * @sfb: The base resources for the hardware.
749  * @win: The window to free the display memory for.
750  *
751  * Free the display memory allocated by s3c_fb_alloc_memory().
752  */
753 static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
754 {
755         struct fb_info *fbi = win->fbinfo;
756
757         dma_free_writecombine(sfb->dev, PAGE_ALIGN(fbi->fix.smem_len),
758                               fbi->screen_base, fbi->fix.smem_start);
759 }
760
761 /**
762  * s3c_fb_release_win() - release resources for a framebuffer window.
763  * @win: The window to cleanup the resources for.
764  *
765  * Release the resources that where claimed for the hardware window,
766  * such as the framebuffer instance and any memory claimed for it.
767  */
768 static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
769 {
770         if (win->fbinfo) {
771                 unregister_framebuffer(win->fbinfo);
772                 fb_dealloc_cmap(&win->fbinfo->cmap);
773                 s3c_fb_free_memory(sfb, win);
774                 framebuffer_release(win->fbinfo);
775         }
776 }
777
778 /**
779  * s3c_fb_probe_win() - register an hardware window
780  * @sfb: The base resources for the hardware
781  * @variant: The variant information for this window.
782  * @res: Pointer to where to place the resultant window.
783  *
784  * Allocate and do the basic initialisation for one of the hardware's graphics
785  * windows.
786  */
787 static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
788                                       struct s3c_fb_win_variant *variant,
789                                       struct s3c_fb_win **res)
790 {
791         struct fb_var_screeninfo *var;
792         struct fb_videomode *initmode;
793         struct s3c_fb_pd_win *windata;
794         struct s3c_fb_win *win;
795         struct fb_info *fbinfo;
796         int palette_size;
797         int ret;
798
799         dev_dbg(sfb->dev, "probing window %d\n", win_no);
800
801         palette_size = variant->palette_sz * 4;
802
803         fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
804                                    palette_size * sizeof(u32), sfb->dev);
805         if (!fbinfo) {
806                 dev_err(sfb->dev, "failed to allocate framebuffer\n");
807                 return -ENOENT;
808         }
809
810         windata = sfb->pdata->win[win_no];
811         initmode = &windata->win_mode;
812
813         WARN_ON(windata->max_bpp == 0);
814         WARN_ON(windata->win_mode.xres == 0);
815         WARN_ON(windata->win_mode.yres == 0);
816
817         win = fbinfo->par;
818         var = &fbinfo->var;
819         win->variant = *variant;
820         win->fbinfo = fbinfo;
821         win->parent = sfb;
822         win->windata = windata;
823         win->index = win_no;
824         win->palette_buffer = (u32 *)(win + 1);
825
826         ret = s3c_fb_alloc_memory(sfb, win);
827         if (ret) {
828                 dev_err(sfb->dev, "failed to allocate display memory\n");
829                 return ret;
830         }
831
832         /* setup the r/b/g positions for the window's palette */
833         s3c_fb_init_palette(win_no, &win->palette);
834
835         /* setup the initial video mode from the window */
836         fb_videomode_to_var(&fbinfo->var, initmode);
837
838         fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
839         fbinfo->fix.accel       = FB_ACCEL_NONE;
840         fbinfo->var.activate    = FB_ACTIVATE_NOW;
841         fbinfo->var.vmode       = FB_VMODE_NONINTERLACED;
842         fbinfo->var.bits_per_pixel = windata->default_bpp;
843         fbinfo->fbops           = &s3c_fb_ops;
844         fbinfo->flags           = FBINFO_FLAG_DEFAULT;
845         fbinfo->pseudo_palette  = &win->pseudo_palette;
846
847         /* prepare to actually start the framebuffer */
848
849         ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
850         if (ret < 0) {
851                 dev_err(sfb->dev, "check_var failed on initial video params\n");
852                 return ret;
853         }
854
855         /* create initial colour map */
856
857         ret = fb_alloc_cmap(&fbinfo->cmap, win->variant.palette_sz, 1);
858         if (ret == 0)
859                 fb_set_cmap(&fbinfo->cmap, fbinfo);
860         else
861                 dev_err(sfb->dev, "failed to allocate fb cmap\n");
862
863         s3c_fb_set_par(fbinfo);
864
865         dev_dbg(sfb->dev, "about to register framebuffer\n");
866
867         /* run the check_var and set_par on our configuration. */
868
869         ret = register_framebuffer(fbinfo);
870         if (ret < 0) {
871                 dev_err(sfb->dev, "failed to register framebuffer\n");
872                 return ret;
873         }
874
875         *res = win;
876         dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
877
878         return 0;
879 }
880
881 /**
882  * s3c_fb_clear_win() - clear hardware window registers.
883  * @sfb: The base resources for the hardware.
884  * @win: The window to process.
885  *
886  * Reset the specific window registers to a known state.
887  */
888 static void s3c_fb_clear_win(struct s3c_fb *sfb, int win)
889 {
890         void __iomem *regs = sfb->regs;
891
892         writel(0, regs + WINCON(win));
893         writel(0, regs + VIDOSD_A(win));
894         writel(0, regs + VIDOSD_B(win));
895         writel(0, regs + VIDOSD_C(win));
896 }
897
898 static int __devinit s3c_fb_probe(struct platform_device *pdev)
899 {
900         struct s3c_fb_driverdata *fbdrv;
901         struct device *dev = &pdev->dev;
902         struct s3c_fb_platdata *pd;
903         struct s3c_fb *sfb;
904         struct resource *res;
905         int win;
906         int ret = 0;
907
908         fbdrv = (struct s3c_fb_driverdata *)platform_get_device_id(pdev)->driver_data;
909
910         if (fbdrv->variant.nr_windows > S3C_FB_MAX_WIN) {
911                 dev_err(dev, "too many windows, cannot attach\n");
912                 return -EINVAL;
913         }
914
915         pd = pdev->dev.platform_data;
916         if (!pd) {
917                 dev_err(dev, "no platform data specified\n");
918                 return -EINVAL;
919         }
920
921         sfb = kzalloc(sizeof(struct s3c_fb), GFP_KERNEL);
922         if (!sfb) {
923                 dev_err(dev, "no memory for framebuffers\n");
924                 return -ENOMEM;
925         }
926
927         sfb->dev = dev;
928         sfb->pdata = pd;
929         sfb->variant = fbdrv->variant;
930
931         sfb->bus_clk = clk_get(dev, "lcd");
932         if (IS_ERR(sfb->bus_clk)) {
933                 dev_err(dev, "failed to get bus clock\n");
934                 goto err_sfb;
935         }
936
937         clk_enable(sfb->bus_clk);
938
939         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
940         if (!res) {
941                 dev_err(dev, "failed to find registers\n");
942                 ret = -ENOENT;
943                 goto err_clk;
944         }
945
946         sfb->regs_res = request_mem_region(res->start, resource_size(res),
947                                            dev_name(dev));
948         if (!sfb->regs_res) {
949                 dev_err(dev, "failed to claim register region\n");
950                 ret = -ENOENT;
951                 goto err_clk;
952         }
953
954         sfb->regs = ioremap(res->start, resource_size(res));
955         if (!sfb->regs) {
956                 dev_err(dev, "failed to map registers\n");
957                 ret = -ENXIO;
958                 goto err_req_region;
959         }
960
961         dev_dbg(dev, "got resources (regs %p), probing windows\n", sfb->regs);
962
963         /* setup gpio and output polarity controls */
964
965         pd->setup_gpio();
966
967         writel(pd->vidcon1, sfb->regs + VIDCON1);
968
969         /* zero all windows before we do anything */
970
971         for (win = 0; win < fbdrv->variant.nr_windows; win++)
972                 s3c_fb_clear_win(sfb, win);
973
974         /* initialise colour key controls */
975         for (win = 0; win < (fbdrv->variant.nr_windows - 1); win++) {
976                 writel(0xffffff, sfb->regs + WxKEYCONy(win, 0));
977                 writel(0xffffff, sfb->regs + WxKEYCONy(win, 1));
978         }
979
980         /* we have the register setup, start allocating framebuffers */
981
982         for (win = 0; win < fbdrv->variant.nr_windows; win++) {
983                 if (!pd->win[win])
984                         continue;
985
986                 ret = s3c_fb_probe_win(sfb, win, fbdrv->win[win],
987                                        &sfb->windows[win]);
988                 if (ret < 0) {
989                         dev_err(dev, "failed to create window %d\n", win);
990                         for (; win >= 0; win--)
991                                 s3c_fb_release_win(sfb, sfb->windows[win]);
992                         goto err_ioremap;
993                 }
994         }
995
996         platform_set_drvdata(pdev, sfb);
997
998         return 0;
999
1000 err_ioremap:
1001         iounmap(sfb->regs);
1002
1003 err_req_region:
1004         release_resource(sfb->regs_res);
1005         kfree(sfb->regs_res);
1006
1007 err_clk:
1008         clk_disable(sfb->bus_clk);
1009         clk_put(sfb->bus_clk);
1010
1011 err_sfb:
1012         kfree(sfb);
1013         return ret;
1014 }
1015
1016 /**
1017  * s3c_fb_remove() - Cleanup on module finalisation
1018  * @pdev: The platform device we are bound to.
1019  *
1020  * Shutdown and then release all the resources that the driver allocated
1021  * on initialisation.
1022  */
1023 static int __devexit s3c_fb_remove(struct platform_device *pdev)
1024 {
1025         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1026         int win;
1027
1028         for (win = 0; win < S3C_FB_MAX_WIN; win++)
1029                 if (sfb->windows[win])
1030                         s3c_fb_release_win(sfb, sfb->windows[win]);
1031
1032         iounmap(sfb->regs);
1033
1034         clk_disable(sfb->bus_clk);
1035         clk_put(sfb->bus_clk);
1036
1037         release_resource(sfb->regs_res);
1038         kfree(sfb->regs_res);
1039
1040         kfree(sfb);
1041
1042         return 0;
1043 }
1044
1045 #ifdef CONFIG_PM
1046 static int s3c_fb_suspend(struct platform_device *pdev, pm_message_t state)
1047 {
1048         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1049         struct s3c_fb_win *win;
1050         int win_no;
1051
1052         for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) {
1053                 win = sfb->windows[win_no];
1054                 if (!win)
1055                         continue;
1056
1057                 /* use the blank function to push into power-down */
1058                 s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo);
1059         }
1060
1061         clk_disable(sfb->bus_clk);
1062         return 0;
1063 }
1064
1065 static int s3c_fb_resume(struct platform_device *pdev)
1066 {
1067         struct s3c_fb *sfb = platform_get_drvdata(pdev);
1068         struct s3c_fb_platdata *pd = sfb->pdata;
1069         struct s3c_fb_win *win;
1070         int win_no;
1071
1072         clk_enable(sfb->bus_clk);
1073
1074         /* setup registers */
1075         writel(pd->vidcon1, sfb->regs + VIDCON1);
1076
1077         /* zero all windows before we do anything */
1078         for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++)
1079                 s3c_fb_clear_win(sfb, win_no);
1080
1081         for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) {
1082                 writel(0xffffff, sfb->regs + WxKEYCONy(win_no, 1));
1083                 writel(0xffffff, sfb->regs + WxKEYCONy(win_no, 1));
1084         }
1085
1086         /* restore framebuffers */
1087         for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) {
1088                 win = sfb->windows[win_no];
1089                 if (!win)
1090                         continue;
1091
1092                 dev_dbg(&pdev->dev, "resuming window %d\n", win_no);
1093                 s3c_fb_set_par(win->fbinfo);
1094         }
1095
1096         return 0;
1097 }
1098 #else
1099 #define s3c_fb_suspend NULL
1100 #define s3c_fb_resume  NULL
1101 #endif
1102
1103
1104 #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4))
1105 #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8))
1106
1107 static struct s3c_fb_win_variant s3c_fb_data_64xx_wins[] __devinitdata = {
1108         [0] = {
1109                 .has_osd_c      = 1,
1110                 .palette_sz     = 256,
1111                 .valid_bpp      = VALID_BPP1248 | VALID_BPP(16) | VALID_BPP(24),
1112         },
1113         [1] = {
1114                 .has_osd_c      = 1,
1115                 .has_osd_d      = 1,
1116                 .palette_sz     = 256,
1117                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
1118                                    VALID_BPP(18) | VALID_BPP(19) |
1119                                    VALID_BPP(24) | VALID_BPP(25)),
1120         },
1121         [2] = {
1122                 .has_osd_c      = 1,
1123                 .has_osd_d      = 1,
1124                 .palette_sz     = 16,
1125                 .palette_16bpp  = 1,
1126                 .valid_bpp      = (VALID_BPP1248 | VALID_BPP(16) |
1127                                    VALID_BPP(18) | VALID_BPP(19) |
1128                                    VALID_BPP(24) | VALID_BPP(25)),
1129         },
1130         [3] = {
1131                 .has_osd_c      = 1,
1132                 .has_osd_d      = 1,
1133                 .palette_sz     = 16,
1134                 .palette_16bpp  = 1,
1135                 .valid_bpp      = (VALID_BPP124  | VALID_BPP(16) |
1136                                    VALID_BPP(18) | VALID_BPP(19) |
1137                                    VALID_BPP(24) | VALID_BPP(25)),
1138         },
1139         [4] = {
1140                 .has_osd_c      = 1,
1141                 .palette_sz     = 4,
1142                 .palette_16bpp  = 1,
1143                 .valid_bpp      = (VALID_BPP(1) | VALID_BPP(2) |
1144                                    VALID_BPP(16) | VALID_BPP(18) |
1145                                    VALID_BPP(24) | VALID_BPP(25)),
1146         },
1147 };
1148
1149 static struct s3c_fb_driverdata s3c_fb_data_64xx __devinitdata = {
1150         .variant = {
1151                 .nr_windows     = 5,
1152
1153                 .palette = {
1154                         [0] = 0x400,
1155                         [1] = 0x800,
1156                         [2] = 0x300,
1157                         [3] = 0x320,
1158                         [4] = 0x340,
1159                 },
1160         },
1161         .win[0] = &s3c_fb_data_64xx_wins[0],
1162         .win[1] = &s3c_fb_data_64xx_wins[1],
1163         .win[2] = &s3c_fb_data_64xx_wins[2],
1164         .win[3] = &s3c_fb_data_64xx_wins[3],
1165         .win[4] = &s3c_fb_data_64xx_wins[4],
1166 };
1167
1168 static struct s3c_fb_driverdata s3c_fb_data_s5p __devinitdata = {
1169         .variant = {
1170                 .nr_windows     = 5,
1171
1172                 .palette = {
1173                         [0] = 0x2400,
1174                         [1] = 0x2800,
1175                         [2] = 0x2c00,
1176                         [3] = 0x3000,
1177                         [4] = 0x3400,
1178                 },
1179         },
1180         .win[0] = &s3c_fb_data_64xx_wins[0],
1181         .win[1] = &s3c_fb_data_64xx_wins[1],
1182         .win[2] = &s3c_fb_data_64xx_wins[2],
1183         .win[3] = &s3c_fb_data_64xx_wins[3],
1184         .win[4] = &s3c_fb_data_64xx_wins[4],
1185 };
1186
1187 static struct platform_device_id s3c_fb_driver_ids[] = {
1188         {
1189                 .name           = "s3c-fb",
1190                 .driver_data    = (unsigned long)&s3c_fb_data_64xx,
1191         }, {
1192                 .name           = "s5p-fb",
1193                 .driver_data    = (unsigned long)&s3c_fb_data_s5p,
1194         },
1195         {},
1196 };
1197 MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids);
1198
1199 static struct platform_driver s3c_fb_driver = {
1200         .probe          = s3c_fb_probe,
1201         .remove         = __devexit_p(s3c_fb_remove),
1202         .suspend        = s3c_fb_suspend,
1203         .resume         = s3c_fb_resume,
1204         .id_table       = s3c_fb_driver_ids,
1205         .driver         = {
1206                 .name   = "s3c-fb",
1207                 .owner  = THIS_MODULE,
1208         },
1209 };
1210
1211 static int __init s3c_fb_init(void)
1212 {
1213         return platform_driver_register(&s3c_fb_driver);
1214 }
1215
1216 static void __exit s3c_fb_cleanup(void)
1217 {
1218         platform_driver_unregister(&s3c_fb_driver);
1219 }
1220
1221 module_init(s3c_fb_init);
1222 module_exit(s3c_fb_cleanup);
1223
1224 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
1225 MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver");
1226 MODULE_LICENSE("GPL");
1227 MODULE_ALIAS("platform:s3c-fb");