Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[linux-2.6] / drivers / video / mbx / mbxfb.c
1 /*
2  *  linux/drivers/video/mbx/mbxfb.c
3  *
4  *  Copyright (C) 2006-2007 8D Technologies inc
5  *  Raphael Assenat <raph@8d.com>
6  *      - Added video overlay support
7  *      - Various improvements
8  *
9  *  Copyright (C) 2006 Compulab, Ltd.
10  *  Mike Rapoport <mike@compulab.co.il>
11  *      - Creation of driver
12  *
13  *   Based on pxafb.c
14  *
15  * This file is subject to the terms and conditions of the GNU General Public
16  * License.  See the file COPYING in the main directory of this archive for
17  * more details.
18  *
19  *   Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver
20  *
21  */
22
23 #include <linux/delay.h>
24 #include <linux/fb.h>
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/platform_device.h>
28 #include <linux/uaccess.h>
29
30 #include <asm/io.h>
31
32 #include <video/mbxfb.h>
33
34 #include "regs.h"
35 #include "reg_bits.h"
36
37 static unsigned long virt_base_2700;
38
39 #define write_reg(val, reg) do { writel((val), (reg)); } while(0)
40
41 /* Without this delay, the graphics appears somehow scaled and
42  * there is a lot of jitter in scanlines. This delay is probably
43  * needed only after setting some specific register(s) somewhere,
44  * not all over the place... */
45 #define write_reg_dly(val, reg) do { writel((val), reg); udelay(1000); } while(0)
46
47 #define MIN_XRES        16
48 #define MIN_YRES        16
49 #define MAX_XRES        2048
50 #define MAX_YRES        2048
51
52 #define MAX_PALETTES    16
53
54 /* FIXME: take care of different chip revisions with different sizes
55    of ODFB */
56 #define MEMORY_OFFSET   0x60000
57
58 struct mbxfb_info {
59         struct device *dev;
60
61         struct resource *fb_res;
62         struct resource *fb_req;
63
64         struct resource *reg_res;
65         struct resource *reg_req;
66
67         void __iomem *fb_virt_addr;
68         unsigned long fb_phys_addr;
69
70         void __iomem *reg_virt_addr;
71         unsigned long reg_phys_addr;
72
73         int (*platform_probe) (struct fb_info * fb);
74         int (*platform_remove) (struct fb_info * fb);
75
76         u32 pseudo_palette[MAX_PALETTES];
77 #ifdef CONFIG_FB_MBX_DEBUG
78         void *debugfs_data;
79 #endif
80
81 };
82
83 static struct fb_var_screeninfo mbxfb_default __devinitdata = {
84         .xres = 640,
85         .yres = 480,
86         .xres_virtual = 640,
87         .yres_virtual = 480,
88         .bits_per_pixel = 16,
89         .red = {11, 5, 0},
90         .green = {5, 6, 0},
91         .blue = {0, 5, 0},
92         .activate = FB_ACTIVATE_TEST,
93         .height = -1,
94         .width = -1,
95         .pixclock = 40000,
96         .left_margin = 48,
97         .right_margin = 16,
98         .upper_margin = 33,
99         .lower_margin = 10,
100         .hsync_len = 96,
101         .vsync_len = 2,
102         .vmode = FB_VMODE_NONINTERLACED,
103         .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
104 };
105
106 static struct fb_fix_screeninfo mbxfb_fix  __devinitdata = {
107         .id = "MBX",
108         .type = FB_TYPE_PACKED_PIXELS,
109         .visual = FB_VISUAL_TRUECOLOR,
110         .xpanstep = 0,
111         .ypanstep = 0,
112         .ywrapstep = 0,
113         .accel = FB_ACCEL_NONE,
114 };
115
116 struct pixclock_div {
117         u8 m;
118         u8 n;
119         u8 p;
120 };
121
122 static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps,
123                                        struct pixclock_div *div)
124 {
125         u8 m, n, p;
126         unsigned int err = 0;
127         unsigned int min_err = ~0x0;
128         unsigned int clk;
129         unsigned int best_clk = 0;
130         unsigned int ref_clk = 13000;   /* FIXME: take from platform data */
131         unsigned int pixclock;
132
133         /* convert pixclock to KHz */
134         pixclock = PICOS2KHZ(pixclock_ps);
135
136         /* PLL output freq = (ref_clk * M) / (N * 2^P)
137          *
138          * M: 1 to 63
139          * N: 1 to 7
140          * P: 0 to 7
141          */
142
143         /* RAPH: When N==1, the resulting pixel clock appears to
144          * get divided by 2. Preventing N=1 by starting the following
145          * loop at 2 prevents this. Is this a bug with my chip
146          * revision or something I dont understand? */
147         for (m = 1; m < 64; m++) {
148                 for (n = 2; n < 8; n++) {
149                         for (p = 0; p < 8; p++) {
150                                 clk = (ref_clk * m) / (n * (1 << p));
151                                 err = (clk > pixclock) ? (clk - pixclock) :
152                                         (pixclock - clk);
153                                 if (err < min_err) {
154                                         min_err = err;
155                                         best_clk = clk;
156                                         div->m = m;
157                                         div->n = n;
158                                         div->p = p;
159                                 }
160                         }
161                 }
162         }
163         return KHZ2PICOS(best_clk);
164 }
165
166 static int mbxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
167                            u_int trans, struct fb_info *info)
168 {
169         u32 val, ret = 1;
170
171         if (regno < MAX_PALETTES) {
172                 u32 *pal = info->pseudo_palette;
173
174                 val = (red & 0xf800) | ((green & 0xfc00) >> 5) |
175                         ((blue & 0xf800) >> 11);
176                 pal[regno] = val;
177                 ret = 0;
178         }
179
180         return ret;
181 }
182
183 static int mbxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
184 {
185         struct pixclock_div div;
186
187         var->pixclock = mbxfb_get_pixclock(var->pixclock, &div);
188
189         if (var->xres < MIN_XRES)
190                 var->xres = MIN_XRES;
191         if (var->yres < MIN_YRES)
192                 var->yres = MIN_YRES;
193         if (var->xres > MAX_XRES)
194                 return -EINVAL;
195         if (var->yres > MAX_YRES)
196                 return -EINVAL;
197         var->xres_virtual = max(var->xres_virtual, var->xres);
198         var->yres_virtual = max(var->yres_virtual, var->yres);
199
200         switch (var->bits_per_pixel) {
201                 /* 8 bits-per-pixel is not supported yet */
202         case 8:
203                 return -EINVAL;
204         case 16:
205                 var->green.length = (var->green.length == 5) ? 5 : 6;
206                 var->red.length = 5;
207                 var->blue.length = 5;
208                 var->transp.length = 6 - var->green.length;
209                 var->blue.offset = 0;
210                 var->green.offset = 5;
211                 var->red.offset = 5 + var->green.length;
212                 var->transp.offset = (5 + var->red.offset) & 15;
213                 break;
214         case 24:                /* RGB 888   */
215         case 32:                /* RGBA 8888 */
216                 var->red.offset = 16;
217                 var->red.length = 8;
218                 var->green.offset = 8;
219                 var->green.length = 8;
220                 var->blue.offset = 0;
221                 var->blue.length = 8;
222                 var->transp.length = var->bits_per_pixel - 24;
223                 var->transp.offset = (var->transp.length) ? 24 : 0;
224                 break;
225         }
226         var->red.msb_right = 0;
227         var->green.msb_right = 0;
228         var->blue.msb_right = 0;
229         var->transp.msb_right = 0;
230
231         return 0;
232 }
233
234 static int mbxfb_set_par(struct fb_info *info)
235 {
236         struct fb_var_screeninfo *var = &info->var;
237         struct pixclock_div div;
238         ushort hbps, ht, hfps, has;
239         ushort vbps, vt, vfps, vas;
240         u32 gsctrl = readl(GSCTRL);
241         u32 gsadr = readl(GSADR);
242
243         info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
244
245         /* setup color mode */
246         gsctrl &= ~(FMsk(GSCTRL_GPIXFMT));
247         /* FIXME: add *WORKING* support for 8-bits per color */
248         if (info->var.bits_per_pixel == 8) {
249                 return -EINVAL;
250         } else {
251                 fb_dealloc_cmap(&info->cmap);
252                 gsctrl &= ~GSCTRL_LUT_EN;
253
254                 info->fix.visual = FB_VISUAL_TRUECOLOR;
255                 switch (info->var.bits_per_pixel) {
256                 case 16:
257                         if (info->var.green.length == 5)
258                                 gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
259                         else
260                                 gsctrl |= GSCTRL_GPIXFMT_RGB565;
261                         break;
262                 case 24:
263                         gsctrl |= GSCTRL_GPIXFMT_RGB888;
264                         break;
265                 case 32:
266                         gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
267                         break;
268                 }
269         }
270
271         /* setup resolution */
272         gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
273         gsctrl |= Gsctrl_Width(info->var.xres) |
274                 Gsctrl_Height(info->var.yres);
275         write_reg_dly(gsctrl, GSCTRL);
276
277         gsadr &= ~(FMsk(GSADR_SRCSTRIDE));
278         gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel /
279                                  (8 * 16) - 1);
280         write_reg_dly(gsadr, GSADR);
281
282         /* setup timings */
283         var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div);
284
285         write_reg_dly((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
286                 Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL);
287
288         hbps = var->hsync_len;
289         has = hbps + var->left_margin;
290         hfps = has + var->xres;
291         ht = hfps + var->right_margin;
292
293         vbps = var->vsync_len;
294         vas = vbps + var->upper_margin;
295         vfps = vas + var->yres;
296         vt = vfps + var->lower_margin;
297
298         write_reg_dly((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
299         write_reg_dly((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
300         write_reg_dly((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
301         write_reg_dly((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
302
303         write_reg_dly((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
304         write_reg_dly((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
305         write_reg_dly((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
306         write_reg_dly((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
307         write_reg_dly((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
308
309         write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
310
311         write_reg_dly(DINTRE_VEVENT0_EN, DINTRE);
312
313         return 0;
314 }
315
316 static int mbxfb_blank(int blank, struct fb_info *info)
317 {
318         switch (blank) {
319         case FB_BLANK_POWERDOWN:
320         case FB_BLANK_VSYNC_SUSPEND:
321         case FB_BLANK_HSYNC_SUSPEND:
322         case FB_BLANK_NORMAL:
323                 write_reg_dly((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
324                 write_reg_dly((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
325                 write_reg_dly((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
326                 break;
327         case FB_BLANK_UNBLANK:
328                 write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
329                 write_reg_dly((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
330                 break;
331         }
332         return 0;
333 }
334
335 static int mbxfb_setupOverlay(struct mbxfb_overlaySetup *set)
336 {
337         u32 vsctrl, vscadr, vsadr;
338         u32 sssize, spoctrl, shctrl;
339         u32 vubase, vvbase;
340         u32 vovrclk;
341
342         if (set->scaled_width==0 || set->scaled_height==0)
343                 return -EINVAL;
344
345         /* read registers which have reserved bits
346          * so we can write them back as-is. */
347         vovrclk = readl(VOVRCLK);
348         vsctrl = readl(VSCTRL);
349         vscadr = readl(VSCADR);
350         vubase = readl(VUBASE);
351         vvbase = readl(VVBASE);
352         shctrl = readl(SHCTRL);
353
354         spoctrl = readl(SPOCTRL);
355         sssize = readl(SSSIZE);
356
357         vsctrl &= ~(    FMsk(VSCTRL_VSWIDTH) |
358                                         FMsk(VSCTRL_VSHEIGHT) |
359                                         FMsk(VSCTRL_VPIXFMT) |
360                                         VSCTRL_GAMMA_EN | VSCTRL_CSC_EN |
361                                         VSCTRL_COSITED );
362         vsctrl |= Vsctrl_Width(set->width) | Vsctrl_Height(set->height) |
363                                 VSCTRL_CSC_EN;
364
365         vscadr &= ~(VSCADR_STR_EN | FMsk(VSCADR_VBASE_ADR) );
366         vubase &= ~(VUBASE_UVHALFSTR | FMsk(VUBASE_UBASE_ADR));
367         vvbase &= ~(FMsk(VVBASE_VBASE_ADR));
368
369         switch (set->fmt) {
370         case MBXFB_FMT_YUV16:
371                 vsctrl |= VSCTRL_VPIXFMT_YUV12;
372
373                 set->Y_stride = ((set->width) + 0xf ) & ~0xf;
374                 break;
375         case MBXFB_FMT_YUV12:
376                 vsctrl |= VSCTRL_VPIXFMT_YUV12;
377
378                 set->Y_stride = ((set->width) + 0xf ) & ~0xf;
379                 vubase |= VUBASE_UVHALFSTR;
380
381                 break;
382         case MBXFB_FMT_UY0VY1:
383                 vsctrl |= VSCTRL_VPIXFMT_UY0VY1;
384                 set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
385                 break;
386         case MBXFB_FMT_VY0UY1:
387                 vsctrl |= VSCTRL_VPIXFMT_VY0UY1;
388                 set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
389                 break;
390         case MBXFB_FMT_Y0UY1V:
391                 vsctrl |= VSCTRL_VPIXFMT_Y0UY1V;
392                 set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
393                 break;
394         case MBXFB_FMT_Y0VY1U:
395                 vsctrl |= VSCTRL_VPIXFMT_Y0VY1U;
396                 set->Y_stride = (set->width*2 + 0xf ) & ~0xf;
397                         break;
398         default:
399                 return -EINVAL;
400         }
401
402         /* VSCTRL has the bits which sets the Video Pixel Format.
403          * When passing from a packed to planar format,
404          * if we write VSCTRL first, VVBASE and VUBASE would
405          * be zero if we would not set them here. (And then,
406          * the chips hangs and only a reset seems to fix it).
407          *
408          * If course, the values calculated here have no meaning
409          * for packed formats.
410          */
411         set->UV_stride = ((set->width/2) + 0x7 ) & ~0x7;
412                 set->U_offset = set->height * set->Y_stride;
413                 set->V_offset = set->U_offset +
414                                                 set->height * set->UV_stride;
415         vubase |= Vubase_Ubase_Adr(
416                         (0x60000 + set->mem_offset + set->U_offset)>>3);
417         vvbase |= Vvbase_Vbase_Adr(
418                         (0x60000 + set->mem_offset + set->V_offset)>>3);
419
420
421         vscadr |= Vscadr_Vbase_Adr((0x60000 + set->mem_offset)>>4);
422
423         if (set->enable)
424                 vscadr |= VSCADR_STR_EN;
425
426
427         vsadr = Vsadr_Srcstride((set->Y_stride)/16-1) |
428                 Vsadr_Xstart(set->x) | Vsadr_Ystart(set->y);
429
430         sssize &= ~(FMsk(SSSIZE_SC_WIDTH) | FMsk(SSSIZE_SC_HEIGHT));
431         sssize = Sssize_Sc_Width(set->scaled_width-1) |
432                         Sssize_Sc_Height(set->scaled_height-1);
433
434         spoctrl &= ~(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP |
435                         SPOCTRL_HV_SC_OR | SPOCTRL_VS_UR_C |
436                         FMsk(SPOCTRL_VPITCH));
437         spoctrl |= Spoctrl_Vpitch((set->height<<11)/set->scaled_height);
438
439         /* Bypass horiz/vert scaler when same size */
440         if (set->scaled_width == set->width)
441                 spoctrl |= SPOCTRL_H_SC_BP;
442         if (set->scaled_height == set->height)
443                 spoctrl |= SPOCTRL_V_SC_BP;
444
445         shctrl &= ~(FMsk(SHCTRL_HPITCH) | SHCTRL_HDECIM);
446         shctrl |= Shctrl_Hpitch((set->width<<11)/set->scaled_width);
447
448         /* Video plane registers */
449         write_reg(vsctrl, VSCTRL);
450         write_reg(vscadr, VSCADR);
451         write_reg(vubase, VUBASE);
452         write_reg(vvbase, VVBASE);
453         write_reg(vsadr, VSADR);
454
455         /* Video scaler registers */
456         write_reg(sssize, SSSIZE);
457         write_reg(spoctrl, SPOCTRL);
458         write_reg(shctrl, SHCTRL);
459
460         /* Clock */
461         if (set->enable)
462                 vovrclk |= 1;
463         else
464                 vovrclk &= ~1;
465
466         write_reg(vovrclk, VOVRCLK);
467
468         return 0;
469 }
470
471 static int mbxfb_ioctl_planeorder(struct mbxfb_planeorder *porder)
472 {
473         unsigned long gscadr, vscadr;
474
475         if (porder->bottom == porder->top)
476                 return -EINVAL;
477
478         gscadr = readl(GSCADR);
479         vscadr = readl(VSCADR);
480
481         gscadr &= ~(FMsk(GSCADR_BLEND_POS));
482         vscadr &= ~(FMsk(VSCADR_BLEND_POS));
483
484         switch (porder->bottom) {
485         case MBXFB_PLANE_GRAPHICS:
486                 gscadr |= GSCADR_BLEND_GFX;
487                 break;
488         case MBXFB_PLANE_VIDEO:
489                 vscadr |= VSCADR_BLEND_GFX;
490                 break;
491         default:
492                 return -EINVAL;
493         }
494
495         switch (porder->top) {
496         case MBXFB_PLANE_GRAPHICS:
497                 gscadr |= GSCADR_BLEND_VID;
498                 break;
499         case MBXFB_PLANE_VIDEO:
500                 vscadr |= GSCADR_BLEND_VID;
501                 break;
502         default:
503                 return -EINVAL;
504         }
505
506         write_reg_dly(vscadr, VSCADR);
507         write_reg_dly(gscadr, GSCADR);
508
509         return 0;
510
511 }
512
513 static int mbxfb_ioctl_alphactl(struct mbxfb_alphaCtl *alpha)
514 {
515         unsigned long vscadr, vbbase, vcmsk;
516         unsigned long gscadr, gbbase, gdrctrl;
517
518         vbbase = Vbbase_Glalpha(alpha->overlay_global_alpha) |
519                                 Vbbase_Colkey(alpha->overlay_colorkey);
520
521         gbbase = Gbbase_Glalpha(alpha->graphics_global_alpha) |
522                                 Gbbase_Colkey(alpha->graphics_colorkey);
523
524         vcmsk = readl(VCMSK);
525         vcmsk &= ~(FMsk(VCMSK_COLKEY_M));
526         vcmsk |= Vcmsk_colkey_m(alpha->overlay_colorkey_mask);
527
528         gdrctrl = readl(GDRCTRL);
529         gdrctrl &= ~(FMsk(GDRCTRL_COLKEYM));
530         gdrctrl |= Gdrctrl_Colkeym(alpha->graphics_colorkey_mask);
531
532         vscadr = readl(VSCADR);
533         vscadr &= ~(FMsk(VSCADR_BLEND_M) | VSCADR_COLKEYSRC | VSCADR_COLKEY_EN);
534
535         gscadr = readl(GSCADR);
536         gscadr &= ~(FMsk(GSCADR_BLEND_M) | GSCADR_COLKEY_EN | GSCADR_COLKEYSRC);
537
538         switch (alpha->overlay_colorkey_mode) {
539         case MBXFB_COLORKEY_DISABLED:
540                 break;
541         case MBXFB_COLORKEY_PREVIOUS:
542                 vscadr |= VSCADR_COLKEY_EN;
543                 break;
544         case MBXFB_COLORKEY_CURRENT:
545                 vscadr |= VSCADR_COLKEY_EN | VSCADR_COLKEYSRC;
546                 break;
547         default:
548                 return -EINVAL;
549         }
550
551         switch (alpha->overlay_blend_mode) {
552         case MBXFB_ALPHABLEND_NONE:
553                 vscadr |= VSCADR_BLEND_NONE;
554                 break;
555         case MBXFB_ALPHABLEND_GLOBAL:
556                 vscadr |= VSCADR_BLEND_GLOB;
557                 break;
558         case MBXFB_ALPHABLEND_PIXEL:
559                 vscadr |= VSCADR_BLEND_PIX;
560                 break;
561         default:
562                 return -EINVAL;
563         }
564
565         switch (alpha->graphics_colorkey_mode) {
566         case MBXFB_COLORKEY_DISABLED:
567                 break;
568         case MBXFB_COLORKEY_PREVIOUS:
569                 gscadr |= GSCADR_COLKEY_EN;
570                 break;
571         case MBXFB_COLORKEY_CURRENT:
572                 gscadr |= GSCADR_COLKEY_EN | GSCADR_COLKEYSRC;
573                 break;
574         default:
575                 return -EINVAL;
576         }
577
578         switch (alpha->graphics_blend_mode) {
579         case MBXFB_ALPHABLEND_NONE:
580                 gscadr |= GSCADR_BLEND_NONE;
581                 break;
582         case MBXFB_ALPHABLEND_GLOBAL:
583                 gscadr |= GSCADR_BLEND_GLOB;
584                 break;
585         case MBXFB_ALPHABLEND_PIXEL:
586                 gscadr |= GSCADR_BLEND_PIX;
587                 break;
588         default:
589                 return -EINVAL;
590         }
591
592         write_reg_dly(vbbase, VBBASE);
593         write_reg_dly(gbbase, GBBASE);
594         write_reg_dly(vcmsk, VCMSK);
595         write_reg_dly(gdrctrl, GDRCTRL);
596         write_reg_dly(gscadr, GSCADR);
597         write_reg_dly(vscadr, VSCADR);
598
599         return 0;
600 }
601
602 static int mbxfb_ioctl(struct fb_info *info, unsigned int cmd,
603                                 unsigned long arg)
604 {
605         struct mbxfb_overlaySetup       setup;
606         struct mbxfb_planeorder         porder;
607         struct mbxfb_alphaCtl           alpha;
608         struct mbxfb_reg                        reg;
609         int res;
610         __u32 tmp;
611
612         switch (cmd)
613         {
614                 case MBXFB_IOCX_OVERLAY:
615                         if (copy_from_user(&setup, (void __user*)arg,
616                                                 sizeof(struct mbxfb_overlaySetup)))
617                                 return -EFAULT;
618
619                         res = mbxfb_setupOverlay(&setup);
620                         if (res)
621                                 return res;
622
623                         if (copy_to_user((void __user*)arg, &setup,
624                                                 sizeof(struct mbxfb_overlaySetup)))
625                                 return -EFAULT;
626
627                         return 0;
628
629                 case MBXFB_IOCS_PLANEORDER:
630                         if (copy_from_user(&porder, (void __user*)arg,
631                                         sizeof(struct mbxfb_planeorder)))
632                         return -EFAULT;
633
634                         return mbxfb_ioctl_planeorder(&porder);
635
636                 case MBXFB_IOCS_ALPHA:
637                         if (copy_from_user(&alpha, (void __user*)arg,
638                                         sizeof(struct mbxfb_alphaCtl)))
639                         return -EFAULT;
640
641                         return mbxfb_ioctl_alphactl(&alpha);
642
643                 case MBXFB_IOCS_REG:
644                         if (copy_from_user(&reg, (void __user*)arg,
645                                                 sizeof(struct mbxfb_reg)))
646                                 return -EFAULT;
647
648                         if (reg.addr >= 0x10000) /* regs are from 0x3fe0000 to 0x3feffff */
649                                 return -EINVAL;
650
651                         tmp = readl(virt_base_2700 + reg.addr);
652                         tmp &= ~reg.mask;
653                         tmp |= reg.val & reg.mask;
654                         writel(tmp, virt_base_2700 + reg.addr);
655
656                         return 0;
657                 case MBXFB_IOCX_REG:
658                         if (copy_from_user(&reg, (void __user*)arg,
659                                                 sizeof(struct mbxfb_reg)))
660                                 return -EFAULT;
661
662                         if (reg.addr >= 0x10000)        /* regs are from 0x3fe0000 to 0x3feffff */
663                                 return -EINVAL;
664                         reg.val = readl(virt_base_2700 + reg.addr);
665
666                         if (copy_to_user((void __user*)arg, &reg,
667                                                 sizeof(struct mbxfb_reg)))
668                                 return -EFAULT;
669
670                         return 0;
671         }
672         return -EINVAL;
673 }
674
675 static struct fb_ops mbxfb_ops = {
676         .owner = THIS_MODULE,
677         .fb_check_var = mbxfb_check_var,
678         .fb_set_par = mbxfb_set_par,
679         .fb_setcolreg = mbxfb_setcolreg,
680         .fb_fillrect = cfb_fillrect,
681         .fb_copyarea = cfb_copyarea,
682         .fb_imageblit = cfb_imageblit,
683         .fb_blank = mbxfb_blank,
684         .fb_ioctl = mbxfb_ioctl,
685 };
686
687 /*
688   Enable external SDRAM controller. Assume that all clocks are active
689   by now.
690 */
691 static void __devinit setup_memc(struct fb_info *fbi)
692 {
693         unsigned long tmp;
694         int i;
695
696         /* FIXME: use platfrom specific parameters */
697         /* setup SDRAM controller */
698         write_reg_dly((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
699                 LMCFG_LMA_TS),
700                LMCFG);
701
702         write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
703
704         /* setup SDRAM timings */
705         write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
706                 Lmtim_Trc(9) | Lmtim_Tdpl(2)),
707                LMTIM);
708         /* setup SDRAM refresh rate */
709         write_reg_dly(0xc2b, LMREFRESH);
710         /* setup SDRAM type parameters */
711         write_reg_dly((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
712                 LMTYPE_COLSZ_8),
713                LMTYPE);
714         /* enable memory controller */
715         write_reg_dly(LMPWR_MC_PWR_ACT, LMPWR);
716         /* perform dummy reads */
717         for ( i = 0; i < 16; i++ ) {
718                 tmp = readl(fbi->screen_base);
719         }
720 }
721
722 static void enable_clocks(struct fb_info *fbi)
723 {
724         /* enable clocks */
725         write_reg_dly(SYSCLKSRC_PLL_2, SYSCLKSRC);
726         write_reg_dly(PIXCLKSRC_PLL_1, PIXCLKSRC);
727         write_reg_dly(0x00000000, CLKSLEEP);
728
729         /* PLL output = (Frefclk * M) / (N * 2^P )
730          *
731          * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz!
732          * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz
733          * */
734         write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) |
735                 CORE_PLL_EN),
736                COREPLL);
737
738         write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
739                 DISP_PLL_EN),
740                DISPPLL);
741
742         write_reg_dly(0x00000000, VOVRCLK);
743         write_reg_dly(PIXCLK_EN, PIXCLK);
744         write_reg_dly(MEMCLK_EN, MEMCLK);
745         write_reg_dly(0x00000001, M24CLK);
746         write_reg_dly(0x00000001, MBXCLK);
747         write_reg_dly(SDCLK_EN, SDCLK);
748         write_reg_dly(0x00000001, PIXCLKDIV);
749 }
750
751 static void __devinit setup_graphics(struct fb_info *fbi)
752 {
753         unsigned long gsctrl;
754         unsigned long vscadr;
755
756         gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) |
757                 Gsctrl_Height(fbi->var.yres);
758         switch (fbi->var.bits_per_pixel) {
759         case 16:
760                 if (fbi->var.green.length == 5)
761                         gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
762                 else
763                         gsctrl |= GSCTRL_GPIXFMT_RGB565;
764                 break;
765         case 24:
766                 gsctrl |= GSCTRL_GPIXFMT_RGB888;
767                 break;
768         case 32:
769                 gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
770                 break;
771         }
772
773         write_reg_dly(gsctrl, GSCTRL);
774         write_reg_dly(0x00000000, GBBASE);
775         write_reg_dly(0x00ffffff, GDRCTRL);
776         write_reg_dly((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
777         write_reg_dly(0x00000000, GPLUT);
778
779         vscadr = readl(VSCADR);
780         vscadr &= ~(FMsk(VSCADR_BLEND_POS) | FMsk(VSCADR_BLEND_M));
781         vscadr |= VSCADR_BLEND_VID | VSCADR_BLEND_NONE;
782         write_reg_dly(vscadr, VSCADR);
783 }
784
785 static void __devinit setup_display(struct fb_info *fbi)
786 {
787         unsigned long dsctrl = 0;
788
789         dsctrl = DSCTRL_BLNK_POL;
790         if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
791                 dsctrl |= DSCTRL_HS_POL;
792         if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
793                 dsctrl |= DSCTRL_VS_POL;
794         write_reg_dly(dsctrl, DSCTRL);
795         write_reg_dly(0xd0303010, DMCTRL);
796         write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
797 }
798
799 static void __devinit enable_controller(struct fb_info *fbi)
800 {
801         u32 svctrl, shctrl;
802
803         write_reg_dly(SYSRST_RST, SYSRST);
804
805         /* setup a timeout, raise drive strength */
806         write_reg_dly(0xffffff0c, SYSCFG);
807
808         enable_clocks(fbi);
809         setup_memc(fbi);
810         setup_graphics(fbi);
811         setup_display(fbi);
812
813         shctrl = readl(SHCTRL);
814         shctrl &= ~(FMsk(SHCTRL_HINITIAL));
815         shctrl |= Shctrl_Hinitial(4<<11);
816         writel(shctrl, SHCTRL);
817
818         svctrl = Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10);
819         writel(svctrl, SVCTRL);
820
821         writel(SPOCTRL_H_SC_BP | SPOCTRL_V_SC_BP | SPOCTRL_VORDER_4TAP
822                         , SPOCTRL);
823
824         /* Those coefficients are good for scaling up. For scaling
825          * down, the application has to calculate them. */
826         write_reg(0xff000100, VSCOEFF0);
827         write_reg(0xfdfcfdfe, VSCOEFF1);
828         write_reg(0x170d0500, VSCOEFF2);
829         write_reg(0x3d372d22, VSCOEFF3);
830         write_reg(0x00000040, VSCOEFF4);
831
832         write_reg(0xff010100, HSCOEFF0);
833         write_reg(0x00000000, HSCOEFF1);
834         write_reg(0x02010000, HSCOEFF2);
835         write_reg(0x01020302, HSCOEFF3);
836         write_reg(0xf9fbfe00, HSCOEFF4);
837         write_reg(0xfbf7f6f7, HSCOEFF5);
838         write_reg(0x1c110700, HSCOEFF6);
839         write_reg(0x3e393127, HSCOEFF7);
840         write_reg(0x00000040, HSCOEFF8);
841
842 }
843
844 #ifdef CONFIG_PM
845 /*
846  * Power management hooks.  Note that we won't be called from IRQ context,
847  * unlike the blank functions above, so we may sleep.
848  */
849 static int mbxfb_suspend(struct platform_device *dev, pm_message_t state)
850 {
851         /* make frame buffer memory enter self-refresh mode */
852         write_reg_dly(LMPWR_MC_PWR_SRM, LMPWR);
853         while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM)
854                 ; /* empty statement */
855
856         /* reset the device, since it's initial state is 'mostly sleeping' */
857         write_reg_dly(SYSRST_RST, SYSRST);
858         return 0;
859 }
860
861 static int mbxfb_resume(struct platform_device *dev)
862 {
863         struct fb_info *fbi = platform_get_drvdata(dev);
864
865         enable_clocks(fbi);
866 /*      setup_graphics(fbi); */
867 /*      setup_display(fbi); */
868
869         write_reg_dly((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
870         return 0;
871 }
872 #else
873 #define mbxfb_suspend   NULL
874 #define mbxfb_resume    NULL
875 #endif
876
877 /* debugfs entries */
878 #ifndef CONFIG_FB_MBX_DEBUG
879 #define mbxfb_debugfs_init(x)   do {} while(0)
880 #define mbxfb_debugfs_remove(x) do {} while(0)
881 #endif
882
883 #define res_size(_r) (((_r)->end - (_r)->start) + 1)
884
885 static int __devinit mbxfb_probe(struct platform_device *dev)
886 {
887         int ret;
888         struct fb_info *fbi;
889         struct mbxfb_info *mfbi;
890         struct mbxfb_platform_data *pdata;
891
892         dev_dbg(&dev->dev, "mbxfb_probe\n");
893
894         pdata = dev->dev.platform_data;
895         if (!pdata) {
896                 dev_err(&dev->dev, "platform data is required\n");
897                 return -EINVAL;
898         }
899
900         fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
901         if (fbi == NULL) {
902                 dev_err(&dev->dev, "framebuffer_alloc failed\n");
903                 return -ENOMEM;
904         }
905
906         mfbi = fbi->par;
907         fbi->pseudo_palette = mfbi->pseudo_palette;
908
909
910         if (pdata->probe)
911                 mfbi->platform_probe = pdata->probe;
912         if (pdata->remove)
913                 mfbi->platform_remove = pdata->remove;
914
915         mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
916         mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
917
918         if (!mfbi->fb_res || !mfbi->reg_res) {
919                 dev_err(&dev->dev, "no resources found\n");
920                 ret = -ENODEV;
921                 goto err1;
922         }
923
924         mfbi->fb_req = request_mem_region(mfbi->fb_res->start,
925                                           res_size(mfbi->fb_res), dev->name);
926         if (mfbi->fb_req == NULL) {
927                 dev_err(&dev->dev, "failed to claim framebuffer memory\n");
928                 ret = -EINVAL;
929                 goto err1;
930         }
931         mfbi->fb_phys_addr = mfbi->fb_res->start;
932
933         mfbi->reg_req = request_mem_region(mfbi->reg_res->start,
934                                            res_size(mfbi->reg_res), dev->name);
935         if (mfbi->reg_req == NULL) {
936                 dev_err(&dev->dev, "failed to claim Marathon registers\n");
937                 ret = -EINVAL;
938                 goto err2;
939         }
940         mfbi->reg_phys_addr = mfbi->reg_res->start;
941
942         mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr,
943                                               res_size(mfbi->reg_req));
944         if (!mfbi->reg_virt_addr) {
945                 dev_err(&dev->dev, "failed to ioremap Marathon registers\n");
946                 ret = -EINVAL;
947                 goto err3;
948         }
949         virt_base_2700 = (unsigned long)mfbi->reg_virt_addr;
950
951         mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr,
952                                              res_size(mfbi->fb_req));
953         if (!mfbi->reg_virt_addr) {
954                 dev_err(&dev->dev, "failed to ioremap frame buffer\n");
955                 ret = -EINVAL;
956                 goto err4;
957         }
958
959         fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
960         fbi->screen_size = pdata->memsize;
961         fbi->fbops = &mbxfb_ops;
962
963         fbi->var = mbxfb_default;
964         fbi->fix = mbxfb_fix;
965         fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000;
966         fbi->fix.smem_len = pdata->memsize;
967         fbi->fix.line_length = mbxfb_default.xres_virtual *
968                                         mbxfb_default.bits_per_pixel / 8;
969
970         ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
971         if (ret < 0) {
972                 dev_err(&dev->dev, "fb_alloc_cmap failed\n");
973                 ret = -EINVAL;
974                 goto err5;
975         }
976
977         platform_set_drvdata(dev, fbi);
978
979         printk(KERN_INFO "fb%d: mbx frame buffer device\n", fbi->node);
980
981         if (mfbi->platform_probe)
982                 mfbi->platform_probe(fbi);
983
984         enable_controller(fbi);
985
986         mbxfb_debugfs_init(fbi);
987
988         ret = register_framebuffer(fbi);
989         if (ret < 0) {
990                 dev_err(&dev->dev, "register_framebuffer failed\n");
991                 ret = -EINVAL;
992                 goto err6;
993         }
994
995         return 0;
996
997 err6:
998         fb_dealloc_cmap(&fbi->cmap);
999 err5:
1000         iounmap(mfbi->fb_virt_addr);
1001 err4:
1002         iounmap(mfbi->reg_virt_addr);
1003 err3:
1004         release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));
1005 err2:
1006         release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res));
1007 err1:
1008         framebuffer_release(fbi);
1009
1010         return ret;
1011 }
1012
1013 static int __devexit mbxfb_remove(struct platform_device *dev)
1014 {
1015         struct fb_info *fbi = platform_get_drvdata(dev);
1016
1017         write_reg_dly(SYSRST_RST, SYSRST);
1018
1019         mbxfb_debugfs_remove(fbi);
1020
1021         if (fbi) {
1022                 struct mbxfb_info *mfbi = fbi->par;
1023
1024                 unregister_framebuffer(fbi);
1025                 if (mfbi) {
1026                         if (mfbi->platform_remove)
1027                                 mfbi->platform_remove(fbi);
1028
1029                         if (mfbi->fb_virt_addr)
1030                                 iounmap(mfbi->fb_virt_addr);
1031                         if (mfbi->reg_virt_addr)
1032                                 iounmap(mfbi->reg_virt_addr);
1033                         if (mfbi->reg_req)
1034                                 release_mem_region(mfbi->reg_req->start,
1035                                                    res_size(mfbi->reg_req));
1036                         if (mfbi->fb_req)
1037                                 release_mem_region(mfbi->fb_req->start,
1038                                                    res_size(mfbi->fb_req));
1039                 }
1040                 framebuffer_release(fbi);
1041         }
1042
1043         return 0;
1044 }
1045
1046 static struct platform_driver mbxfb_driver = {
1047         .probe = mbxfb_probe,
1048         .remove = mbxfb_remove,
1049         .suspend = mbxfb_suspend,
1050         .resume = mbxfb_resume,
1051         .driver = {
1052                 .name = "mbx-fb",
1053         },
1054 };
1055
1056 int __devinit mbxfb_init(void)
1057 {
1058         return platform_driver_register(&mbxfb_driver);
1059 }
1060
1061 static void __devexit mbxfb_exit(void)
1062 {
1063         platform_driver_unregister(&mbxfb_driver);
1064 }
1065
1066 module_init(mbxfb_init);
1067 module_exit(mbxfb_exit);
1068
1069 MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
1070 MODULE_AUTHOR("Mike Rapoport, Compulab");
1071 MODULE_LICENSE("GPL");