2 * linux/drivers/video/mbx/mbxfb.c
4 * Copyright (C) 2006 8D Technologies inc
5 * Raphael Assenat <raph@8d.com>
6 * - Added video overlay support
7 * - Various improvements
9 * Copyright (C) 2006 Compulab, Ltd.
10 * Mike Rapoport <mike@compulab.co.il>
11 * - Creation of driver
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
19 * Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver
23 #include <linux/delay.h>
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/platform_device.h>
28 #include <linux/uaccess.h>
32 #include <video/mbxfb.h>
37 static unsigned long virt_base_2700
;
39 #define write_reg(val, reg) do { writel((val), (reg)); } while(0)
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)
52 #define MAX_PALETTES 16
54 /* FIXME: take care of different chip revisions with different sizes
56 #define MEMORY_OFFSET 0x60000
61 struct resource
*fb_res
;
62 struct resource
*fb_req
;
64 struct resource
*reg_res
;
65 struct resource
*reg_req
;
67 void __iomem
*fb_virt_addr
;
68 unsigned long fb_phys_addr
;
70 void __iomem
*reg_virt_addr
;
71 unsigned long reg_phys_addr
;
73 int (*platform_probe
) (struct fb_info
* fb
);
74 int (*platform_remove
) (struct fb_info
* fb
);
76 u32 pseudo_palette
[MAX_PALETTES
];
77 #ifdef CONFIG_FB_MBX_DEBUG
83 static struct fb_var_screeninfo mbxfb_default __devinitdata
= {
92 .activate
= FB_ACTIVATE_TEST
,
102 .vmode
= FB_VMODE_NONINTERLACED
,
103 .sync
= FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
106 static struct fb_fix_screeninfo mbxfb_fix __devinitdata
= {
108 .type
= FB_TYPE_PACKED_PIXELS
,
109 .visual
= FB_VISUAL_TRUECOLOR
,
113 .accel
= FB_ACCEL_NONE
,
116 struct pixclock_div
{
122 static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps
,
123 struct pixclock_div
*div
)
126 unsigned int err
= 0;
127 unsigned int min_err
= ~0x0;
129 unsigned int best_clk
= 0;
130 unsigned int ref_clk
= 13000; /* FIXME: take from platform data */
131 unsigned int pixclock
;
133 /* convert pixclock to KHz */
134 pixclock
= PICOS2KHZ(pixclock_ps
);
136 /* PLL output freq = (ref_clk * M) / (N * 2^P)
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
) :
163 return KHZ2PICOS(best_clk
);
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
)
171 if (regno
< MAX_PALETTES
) {
172 u32
*pal
= info
->pseudo_palette
;
174 val
= (red
& 0xf800) | ((green
& 0xfc00) >> 5) |
175 ((blue
& 0xf800) >> 11);
183 static int mbxfb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
185 struct pixclock_div div
;
187 var
->pixclock
= mbxfb_get_pixclock(var
->pixclock
, &div
);
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
)
195 if (var
->yres
> MAX_YRES
)
197 var
->xres_virtual
= max(var
->xres_virtual
, var
->xres
);
198 var
->yres_virtual
= max(var
->yres_virtual
, var
->yres
);
200 switch (var
->bits_per_pixel
) {
201 /* 8 bits-per-pixel is not supported yet */
205 var
->green
.length
= (var
->green
.length
== 5) ? 5 : 6;
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;
214 case 24: /* RGB 888 */
215 case 32: /* RGBA 8888 */
216 var
->red
.offset
= 16;
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;
226 var
->red
.msb_right
= 0;
227 var
->green
.msb_right
= 0;
228 var
->blue
.msb_right
= 0;
229 var
->transp
.msb_right
= 0;
234 static int mbxfb_set_par(struct fb_info
*info
)
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
);
243 info
->fix
.line_length
= var
->xres_virtual
* var
->bits_per_pixel
/ 8;
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) {
251 fb_dealloc_cmap(&info
->cmap
);
252 gsctrl
&= ~GSCTRL_LUT_EN
;
254 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
255 switch (info
->var
.bits_per_pixel
) {
257 if (info
->var
.green
.length
== 5)
258 gsctrl
|= GSCTRL_GPIXFMT_ARGB1555
;
260 gsctrl
|= GSCTRL_GPIXFMT_RGB565
;
263 gsctrl
|= GSCTRL_GPIXFMT_RGB888
;
266 gsctrl
|= GSCTRL_GPIXFMT_ARGB8888
;
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
);
277 gsadr
&= ~(FMsk(GSADR_SRCSTRIDE
));
278 gsadr
|= Gsadr_Srcstride(info
->var
.xres
* info
->var
.bits_per_pixel
/
280 write_reg_dly(gsadr
, GSADR
);
283 var
->pixclock
= mbxfb_get_pixclock(info
->var
.pixclock
, &div
);
285 write_reg_dly((Disp_Pll_M(div
.m
) | Disp_Pll_N(div
.n
) |
286 Disp_Pll_P(div
.p
) | DISP_PLL_EN
), DISPPLL
);
288 hbps
= var
->hsync_len
;
289 has
= hbps
+ var
->left_margin
;
290 hfps
= has
+ var
->xres
;
291 ht
= hfps
+ var
->right_margin
;
293 vbps
= var
->vsync_len
;
294 vas
= vbps
+ var
->upper_margin
;
295 vfps
= vas
+ var
->yres
;
296 vt
= vfps
+ var
->lower_margin
;
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
);
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
);
309 write_reg_dly((readl(DSCTRL
) | DSCTRL_SYNCGEN_EN
), DSCTRL
);
311 write_reg_dly(DINTRE_VEVENT0_EN
, DINTRE
);
316 static int mbxfb_blank(int blank
, struct fb_info
*info
)
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
);
327 case FB_BLANK_UNBLANK
:
328 write_reg_dly((readl(DSCTRL
) | DSCTRL_SYNCGEN_EN
), DSCTRL
);
329 write_reg_dly((readl(PIXCLK
) | PIXCLK_EN
), PIXCLK
);
335 static int mbxfb_setupOverlay(struct mbxfb_overlaySetup
*set
)
337 u32 vsctrl
, vbbase
, vscadr
, vsadr
;
338 u32 sssize
, spoctrl
, svctrl
, shctrl
;
342 if (set
->scaled_width
==0 || set
->scaled_height
==0)
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
);
353 spoctrl
= readl(SPOCTRL
);
354 sssize
= readl(SSSIZE
);
357 vbbase
= Vbbase_Glalpha(set
->alpha
);
359 vsctrl
&= ~( FMsk(VSCTRL_VSWIDTH
) |
360 FMsk(VSCTRL_VSHEIGHT
) |
361 FMsk(VSCTRL_VPIXFMT
) |
362 VSCTRL_GAMMA_EN
| VSCTRL_CSC_EN
|
364 vsctrl
|= Vsctrl_Width(set
->width
) | Vsctrl_Height(set
->height
) |
367 vscadr
&= ~(VSCADR_STR_EN
| VSCADR_COLKEY_EN
| VSCADR_COLKEYSRC
|
368 FMsk(VSCADR_BLEND_M
) | FMsk(VSCADR_BLEND_POS
) |
369 FMsk(VSCADR_VBASE_ADR
) );
370 vubase
&= ~(VUBASE_UVHALFSTR
| FMsk(VUBASE_UBASE_ADR
));
371 vvbase
&= ~(FMsk(VVBASE_VBASE_ADR
));
375 case MBXFB_FMT_YUV12
:
376 vsctrl
|= VSCTRL_VPIXFMT_YUV12
;
378 set
->Y_stride
= ((set
->width
) + 0xf ) & ~0xf;
381 case MBXFB_FMT_UY0VY1
:
382 vsctrl
|= VSCTRL_VPIXFMT_UY0VY1
;
383 set
->Y_stride
= (set
->width
*2 + 0xf ) & ~0xf;
385 case MBXFB_FMT_VY0UY1
:
386 vsctrl
|= VSCTRL_VPIXFMT_VY0UY1
;
387 set
->Y_stride
= (set
->width
*2 + 0xf ) & ~0xf;
389 case MBXFB_FMT_Y0UY1V
:
390 vsctrl
|= VSCTRL_VPIXFMT_Y0UY1V
;
391 set
->Y_stride
= (set
->width
*2 + 0xf ) & ~0xf;
393 case MBXFB_FMT_Y0VY1U
:
394 vsctrl
|= VSCTRL_VPIXFMT_Y0VY1U
;
395 set
->Y_stride
= (set
->width
*2 + 0xf ) & ~0xf;
401 /* VSCTRL has the bits which sets the Video Pixel Format.
402 * When passing from a packed to planar format,
403 * if we write VSCTRL first, VVBASE and VUBASE would
404 * be zero if we would not set them here. (And then,
405 * the chips hangs and only a reset seems to fix it).
407 * If course, the values calculated here have no meaning
408 * for packed formats.
410 set
->UV_stride
= ((set
->width
/2) + 0x7 ) & ~0x7;
411 set
->U_offset
= set
->height
* set
->Y_stride
;
412 set
->V_offset
= set
->U_offset
+
413 set
->height
* set
->UV_stride
;
414 vubase
|= Vubase_Ubase_Adr(
415 (0x60000 + set
->mem_offset
+ set
->U_offset
)>>3);
416 vvbase
|= Vvbase_Vbase_Adr(
417 (0x60000 + set
->mem_offset
+ set
->V_offset
)>>3);
420 vscadr
|= VSCADR_BLEND_VID
| VSCADR_BLEND_GLOB
|
421 Vscadr_Vbase_Adr((0x60000 + set
->mem_offset
)>>4);
424 vscadr
|= VSCADR_STR_EN
;
427 vsadr
= Vsadr_Srcstride((set
->Y_stride
)/16-1) |
428 Vsadr_Xstart(set
->x
) | Vsadr_Ystart(set
->y
);
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);
434 spoctrl
&= ~(SPOCTRL_H_SC_BP
| SPOCTRL_V_SC_BP
|
435 SPOCTRL_HV_SC_OR
| SPOCTRL_VS_UR_C
|
436 FMsk(SPOCTRL_VORDER
) | FMsk(SPOCTRL_VPITCH
));
437 spoctrl
= Spoctrl_Vpitch((set
->height
<<11)/set
->scaled_height
)
438 | SPOCTRL_VORDER_2TAP
;
440 /* Bypass horiz/vert scaler when same size */
441 if (set
->scaled_width
== set
->width
)
442 spoctrl
|= SPOCTRL_H_SC_BP
;
443 if (set
->scaled_height
== set
->height
)
444 spoctrl
|= SPOCTRL_V_SC_BP
;
446 svctrl
= Svctrl_Initial1(1<<10) | Svctrl_Initial2(1<<10);
448 shctrl
= Shctrl_Hinitial(4<<11)
449 | Shctrl_Hpitch((set
->width
<<11)/set
->scaled_width
);
451 /* Video plane registers */
452 write_reg(vsctrl
, VSCTRL
);
453 write_reg(vbbase
, VBBASE
);
454 write_reg(vscadr
, VSCADR
);
455 write_reg(vubase
, VUBASE
);
456 write_reg(vvbase
, VVBASE
);
457 write_reg(vsadr
, VSADR
);
459 /* Video scaler registers */
460 write_reg(sssize
, SSSIZE
);
461 write_reg(spoctrl
, SPOCTRL
);
462 write_reg(svctrl
, SVCTRL
);
463 write_reg(shctrl
, SHCTRL
);
465 /* RAPH: Using those coefficients, the scaled
466 * image is quite blurry. I dont know how
467 * to improve them ; The chip documentation
468 * was not helpful.. */
469 write_reg(0x21212121, VSCOEFF0
);
470 write_reg(0x21212121, VSCOEFF1
);
471 write_reg(0x21212121, VSCOEFF2
);
472 write_reg(0x21212121, VSCOEFF3
);
473 write_reg(0x21212121, VSCOEFF4
);
474 write_reg(0x00000000, HSCOEFF0
);
475 write_reg(0x00000000, HSCOEFF1
);
476 write_reg(0x00000000, HSCOEFF2
);
477 write_reg(0x03020201, HSCOEFF3
);
478 write_reg(0x09070604, HSCOEFF4
);
479 write_reg(0x0f0e0c0a, HSCOEFF5
);
480 write_reg(0x15141211, HSCOEFF6
);
481 write_reg(0x19181716, HSCOEFF7
);
482 write_reg(0x00000019, HSCOEFF8
);
490 write_reg(vovrclk
, VOVRCLK
);
495 static int mbxfb_ioctl(struct fb_info
*info
, unsigned int cmd
,
498 struct mbxfb_overlaySetup setup
;
501 if (cmd
== MBXFB_IOCX_OVERLAY
)
503 if (copy_from_user(&setup
, (void __user
*)arg
,
504 sizeof(struct mbxfb_overlaySetup
)))
507 res
= mbxfb_setupOverlay(&setup
);
511 if (copy_to_user((void __user
*)arg
, &setup
,
512 sizeof(struct mbxfb_overlaySetup
)))
520 static struct fb_ops mbxfb_ops
= {
521 .owner
= THIS_MODULE
,
522 .fb_check_var
= mbxfb_check_var
,
523 .fb_set_par
= mbxfb_set_par
,
524 .fb_setcolreg
= mbxfb_setcolreg
,
525 .fb_fillrect
= cfb_fillrect
,
526 .fb_copyarea
= cfb_copyarea
,
527 .fb_imageblit
= cfb_imageblit
,
528 .fb_blank
= mbxfb_blank
,
529 .fb_ioctl
= mbxfb_ioctl
,
533 Enable external SDRAM controller. Assume that all clocks are active
536 static void __devinit
setup_memc(struct fb_info
*fbi
)
541 /* FIXME: use platfrom specific parameters */
542 /* setup SDRAM controller */
543 write_reg_dly((LMCFG_LMC_DS
| LMCFG_LMC_TS
| LMCFG_LMD_TS
|
547 write_reg_dly(LMPWR_MC_PWR_ACT
, LMPWR
);
549 /* setup SDRAM timings */
550 write_reg_dly((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
551 Lmtim_Trc(9) | Lmtim_Tdpl(2)),
553 /* setup SDRAM refresh rate */
554 write_reg_dly(0xc2b, LMREFRESH
);
555 /* setup SDRAM type parameters */
556 write_reg_dly((LMTYPE_CASLAT_3
| LMTYPE_BKSZ_2
| LMTYPE_ROWSZ_11
|
559 /* enable memory controller */
560 write_reg_dly(LMPWR_MC_PWR_ACT
, LMPWR
);
562 /* perform dummy reads */
563 for ( i
= 0; i
< 16; i
++ ) {
564 tmp
= readl(fbi
->screen_base
);
568 static void enable_clocks(struct fb_info
*fbi
)
571 write_reg_dly(SYSCLKSRC_PLL_2
, SYSCLKSRC
);
572 write_reg_dly(PIXCLKSRC_PLL_1
, PIXCLKSRC
);
573 write_reg_dly(0x00000000, CLKSLEEP
);
575 /* PLL output = (Frefclk * M) / (N * 2^P )
577 * M: 0x17, N: 0x3, P: 0x0 == 100 Mhz!
578 * M: 0xb, N: 0x1, P: 0x1 == 71 Mhz
580 write_reg_dly((Core_Pll_M(0xb) | Core_Pll_N(0x1) | Core_Pll_P(0x1) |
584 write_reg_dly((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
588 write_reg_dly(0x00000000, VOVRCLK
);
589 write_reg_dly(PIXCLK_EN
, PIXCLK
);
590 write_reg_dly(MEMCLK_EN
, MEMCLK
);
591 write_reg_dly(0x00000006, M24CLK
);
592 write_reg_dly(0x00000006, MBXCLK
);
593 write_reg_dly(SDCLK_EN
, SDCLK
);
594 write_reg_dly(0x00000001, PIXCLKDIV
);
597 static void __devinit
setup_graphics(struct fb_info
*fbi
)
599 unsigned long gsctrl
;
601 gsctrl
= GSCTRL_GAMMA_EN
| Gsctrl_Width(fbi
->var
.xres
) |
602 Gsctrl_Height(fbi
->var
.yres
);
603 switch (fbi
->var
.bits_per_pixel
) {
605 if (fbi
->var
.green
.length
== 5)
606 gsctrl
|= GSCTRL_GPIXFMT_ARGB1555
;
608 gsctrl
|= GSCTRL_GPIXFMT_RGB565
;
611 gsctrl
|= GSCTRL_GPIXFMT_RGB888
;
614 gsctrl
|= GSCTRL_GPIXFMT_ARGB8888
;
618 write_reg_dly(gsctrl
, GSCTRL
);
619 write_reg_dly(0x00000000, GBBASE
);
620 write_reg_dly(0x00ffffff, GDRCTRL
);
621 write_reg_dly((GSCADR_STR_EN
| Gscadr_Gbase_Adr(0x6000)), GSCADR
);
622 write_reg_dly(0x00000000, GPLUT
);
625 static void __devinit
setup_display(struct fb_info
*fbi
)
627 unsigned long dsctrl
= 0;
629 dsctrl
= DSCTRL_BLNK_POL
;
630 if (fbi
->var
.sync
& FB_SYNC_HOR_HIGH_ACT
)
631 dsctrl
|= DSCTRL_HS_POL
;
632 if (fbi
->var
.sync
& FB_SYNC_VERT_HIGH_ACT
)
633 dsctrl
|= DSCTRL_VS_POL
;
634 write_reg_dly(dsctrl
, DSCTRL
);
635 write_reg_dly(0xd0303010, DMCTRL
);
636 write_reg_dly((readl(DSCTRL
) | DSCTRL_SYNCGEN_EN
), DSCTRL
);
639 static void __devinit
enable_controller(struct fb_info
*fbi
)
641 write_reg_dly(SYSRST_RST
, SYSRST
);
652 * Power management hooks. Note that we won't be called from IRQ context,
653 * unlike the blank functions above, so we may sleep.
655 static int mbxfb_suspend(struct platform_device
*dev
, pm_message_t state
)
657 /* make frame buffer memory enter self-refresh mode */
658 write_reg_dly(LMPWR_MC_PWR_SRM
, LMPWR
);
659 while (LMPWRSTAT
!= LMPWRSTAT_MC_PWR_SRM
)
660 ; /* empty statement */
662 /* reset the device, since it's initial state is 'mostly sleeping' */
663 write_reg_dly(SYSRST_RST
, SYSRST
);
667 static int mbxfb_resume(struct platform_device
*dev
)
669 struct fb_info
*fbi
= platform_get_drvdata(dev
);
672 /* setup_graphics(fbi); */
673 /* setup_display(fbi); */
675 write_reg_dly((readl(DSCTRL
) | DSCTRL_SYNCGEN_EN
), DSCTRL
);
679 #define mbxfb_suspend NULL
680 #define mbxfb_resume NULL
683 /* debugfs entries */
684 #ifndef CONFIG_FB_MBX_DEBUG
685 #define mbxfb_debugfs_init(x) do {} while(0)
686 #define mbxfb_debugfs_remove(x) do {} while(0)
689 #define res_size(_r) (((_r)->end - (_r)->start) + 1)
691 static int __devinit
mbxfb_probe(struct platform_device
*dev
)
695 struct mbxfb_info
*mfbi
;
696 struct mbxfb_platform_data
*pdata
;
698 dev_dbg(dev
, "mbxfb_probe\n");
700 pdata
= dev
->dev
.platform_data
;
702 dev_err(&dev
->dev
, "platform data is required\n");
706 fbi
= framebuffer_alloc(sizeof(struct mbxfb_info
), &dev
->dev
);
708 dev_err(&dev
->dev
, "framebuffer_alloc failed\n");
713 fbi
->pseudo_palette
= mfbi
->pseudo_palette
;
717 mfbi
->platform_probe
= pdata
->probe
;
719 mfbi
->platform_remove
= pdata
->remove
;
721 mfbi
->fb_res
= platform_get_resource(dev
, IORESOURCE_MEM
, 0);
722 mfbi
->reg_res
= platform_get_resource(dev
, IORESOURCE_MEM
, 1);
724 if (!mfbi
->fb_res
|| !mfbi
->reg_res
) {
725 dev_err(&dev
->dev
, "no resources found\n");
730 mfbi
->fb_req
= request_mem_region(mfbi
->fb_res
->start
,
731 res_size(mfbi
->fb_res
), dev
->name
);
732 if (mfbi
->fb_req
== NULL
) {
733 dev_err(&dev
->dev
, "failed to claim framebuffer memory\n");
737 mfbi
->fb_phys_addr
= mfbi
->fb_res
->start
;
739 mfbi
->reg_req
= request_mem_region(mfbi
->reg_res
->start
,
740 res_size(mfbi
->reg_res
), dev
->name
);
741 if (mfbi
->reg_req
== NULL
) {
742 dev_err(&dev
->dev
, "failed to claim Marathon registers\n");
746 mfbi
->reg_phys_addr
= mfbi
->reg_res
->start
;
748 mfbi
->reg_virt_addr
= ioremap_nocache(mfbi
->reg_phys_addr
,
749 res_size(mfbi
->reg_req
));
750 if (!mfbi
->reg_virt_addr
) {
751 dev_err(&dev
->dev
, "failed to ioremap Marathon registers\n");
755 virt_base_2700
= (unsigned long)mfbi
->reg_virt_addr
;
757 mfbi
->fb_virt_addr
= ioremap_nocache(mfbi
->fb_phys_addr
,
758 res_size(mfbi
->fb_req
));
759 if (!mfbi
->reg_virt_addr
) {
760 dev_err(&dev
->dev
, "failed to ioremap frame buffer\n");
765 fbi
->screen_base
= (char __iomem
*)(mfbi
->fb_virt_addr
+ 0x60000);
766 fbi
->screen_size
= pdata
->memsize
;
767 fbi
->fbops
= &mbxfb_ops
;
769 fbi
->var
= mbxfb_default
;
770 fbi
->fix
= mbxfb_fix
;
771 fbi
->fix
.smem_start
= mfbi
->fb_phys_addr
+ 0x60000;
772 fbi
->fix
.smem_len
= pdata
->memsize
;
773 fbi
->fix
.line_length
= mbxfb_default
.xres_virtual
*
774 mbxfb_default
.bits_per_pixel
/ 8;
776 ret
= fb_alloc_cmap(&fbi
->cmap
, 256, 0);
778 dev_err(&dev
->dev
, "fb_alloc_cmap failed\n");
783 platform_set_drvdata(dev
, fbi
);
785 printk(KERN_INFO
"fb%d: mbx frame buffer device\n", fbi
->node
);
787 if (mfbi
->platform_probe
)
788 mfbi
->platform_probe(fbi
);
790 enable_controller(fbi
);
792 mbxfb_debugfs_init(fbi
);
794 ret
= register_framebuffer(fbi
);
796 dev_err(&dev
->dev
, "register_framebuffer failed\n");
804 fb_dealloc_cmap(&fbi
->cmap
);
806 iounmap(mfbi
->fb_virt_addr
);
808 iounmap(mfbi
->reg_virt_addr
);
810 release_mem_region(mfbi
->reg_res
->start
, res_size(mfbi
->reg_res
));
812 release_mem_region(mfbi
->fb_res
->start
, res_size(mfbi
->fb_res
));
814 framebuffer_release(fbi
);
819 static int __devexit
mbxfb_remove(struct platform_device
*dev
)
821 struct fb_info
*fbi
= platform_get_drvdata(dev
);
823 write_reg_dly(SYSRST_RST
, SYSRST
);
825 mbxfb_debugfs_remove(fbi
);
828 struct mbxfb_info
*mfbi
= fbi
->par
;
830 unregister_framebuffer(fbi
);
832 if (mfbi
->platform_remove
)
833 mfbi
->platform_remove(fbi
);
835 if (mfbi
->fb_virt_addr
)
836 iounmap(mfbi
->fb_virt_addr
);
837 if (mfbi
->reg_virt_addr
)
838 iounmap(mfbi
->reg_virt_addr
);
840 release_mem_region(mfbi
->reg_req
->start
,
841 res_size(mfbi
->reg_req
));
843 release_mem_region(mfbi
->fb_req
->start
,
844 res_size(mfbi
->fb_req
));
846 framebuffer_release(fbi
);
852 static struct platform_driver mbxfb_driver
= {
853 .probe
= mbxfb_probe
,
854 .remove
= mbxfb_remove
,
855 .suspend
= mbxfb_suspend
,
856 .resume
= mbxfb_resume
,
862 int __devinit
mbxfb_init(void)
864 return platform_driver_register(&mbxfb_driver
);
867 static void __devexit
mbxfb_exit(void)
869 platform_driver_unregister(&mbxfb_driver
);
872 module_init(mbxfb_init
);
873 module_exit(mbxfb_exit
);
875 MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
876 MODULE_AUTHOR("Mike Rapoport, Compulab");
877 MODULE_LICENSE("GPL");