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