2 * linux/drivers/video/mbx/mbxfb.c
4 * Copyright (C) 2006 Compulab, Ltd.
5 * Mike Rapoport <mike@compulab.co.il>
9 * This file is subject to the terms and conditions of the GNU General Public
10 * License. See the file COPYING in the main directory of this archive for
13 * Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver
17 #include <linux/delay.h>
19 #include <linux/init.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
25 #include <video/mbxfb.h>
30 static unsigned long virt_base_2700
;
37 #define MAX_PALETTES 16
39 /* FIXME: take care of different chip revisions with different sizes
41 #define MEMORY_OFFSET 0x60000
46 struct resource
*fb_res
;
47 struct resource
*fb_req
;
49 struct resource
*reg_res
;
50 struct resource
*reg_req
;
52 void __iomem
*fb_virt_addr
;
53 unsigned long fb_phys_addr
;
55 void __iomem
*reg_virt_addr
;
56 unsigned long reg_phys_addr
;
58 int (*platform_probe
) (struct fb_info
* fb
);
59 int (*platform_remove
) (struct fb_info
* fb
);
61 u32 pseudo_palette
[MAX_PALETTES
];
62 #ifdef CONFIG_FB_MBX_DEBUG
68 static struct fb_var_screeninfo mbxfb_default __devinitdata
= {
77 .activate
= FB_ACTIVATE_TEST
,
87 .vmode
= FB_VMODE_NONINTERLACED
,
88 .sync
= FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
,
91 static struct fb_fix_screeninfo mbxfb_fix __devinitdata
= {
93 .type
= FB_TYPE_PACKED_PIXELS
,
94 .visual
= FB_VISUAL_TRUECOLOR
,
98 .accel
= FB_ACCEL_NONE
,
101 struct pixclock_div
{
107 static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps
,
108 struct pixclock_div
*div
)
111 unsigned int err
= 0;
112 unsigned int min_err
= ~0x0;
114 unsigned int best_clk
= 0;
115 unsigned int ref_clk
= 13000; /* FIXME: take from platform data */
116 unsigned int pixclock
;
118 /* convert pixclock to KHz */
119 pixclock
= PICOS2KHZ(pixclock_ps
);
121 /* PLL output freq = (ref_clk * M) / (N * 2^P)
128 /* RAPH: When N==1, the resulting pixel clock appears to
129 * get divided by 2. Preventing N=1 by starting the following
130 * loop at 2 prevents this. Is this a bug with my chip
131 * revision or something I dont understand? */
132 for (m
= 1; m
< 64; m
++) {
133 for (n
= 2; n
< 8; n
++) {
134 for (p
= 0; p
< 8; p
++) {
135 clk
= (ref_clk
* m
) / (n
* (1 << p
));
136 err
= (clk
> pixclock
) ? (clk
- pixclock
) :
148 return KHZ2PICOS(best_clk
);
151 static int mbxfb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
152 u_int trans
, struct fb_info
*info
)
156 if (regno
< MAX_PALETTES
) {
157 u32
*pal
= info
->pseudo_palette
;
159 val
= (red
& 0xf800) | ((green
& 0xfc00) >> 5) |
160 ((blue
& 0xf800) >> 11);
168 static int mbxfb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
170 struct pixclock_div div
;
172 var
->pixclock
= mbxfb_get_pixclock(var
->pixclock
, &div
);
174 if (var
->xres
< MIN_XRES
)
175 var
->xres
= MIN_XRES
;
176 if (var
->yres
< MIN_YRES
)
177 var
->yres
= MIN_YRES
;
178 if (var
->xres
> MAX_XRES
)
180 if (var
->yres
> MAX_YRES
)
182 var
->xres_virtual
= max(var
->xres_virtual
, var
->xres
);
183 var
->yres_virtual
= max(var
->yres_virtual
, var
->yres
);
185 switch (var
->bits_per_pixel
) {
186 /* 8 bits-per-pixel is not supported yet */
190 var
->green
.length
= (var
->green
.length
== 5) ? 5 : 6;
192 var
->blue
.length
= 5;
193 var
->transp
.length
= 6 - var
->green
.length
;
194 var
->blue
.offset
= 0;
195 var
->green
.offset
= 5;
196 var
->red
.offset
= 5 + var
->green
.length
;
197 var
->transp
.offset
= (5 + var
->red
.offset
) & 15;
199 case 24: /* RGB 888 */
200 case 32: /* RGBA 8888 */
201 var
->red
.offset
= 16;
203 var
->green
.offset
= 8;
204 var
->green
.length
= 8;
205 var
->blue
.offset
= 0;
206 var
->blue
.length
= 8;
207 var
->transp
.length
= var
->bits_per_pixel
- 24;
208 var
->transp
.offset
= (var
->transp
.length
) ? 24 : 0;
211 var
->red
.msb_right
= 0;
212 var
->green
.msb_right
= 0;
213 var
->blue
.msb_right
= 0;
214 var
->transp
.msb_right
= 0;
219 static int mbxfb_set_par(struct fb_info
*info
)
221 struct fb_var_screeninfo
*var
= &info
->var
;
222 struct pixclock_div div
;
223 ushort hbps
, ht
, hfps
, has
;
224 ushort vbps
, vt
, vfps
, vas
;
225 u32 gsctrl
= readl(GSCTRL
);
226 u32 gsadr
= readl(GSADR
);
228 info
->fix
.line_length
= var
->xres_virtual
* var
->bits_per_pixel
/ 8;
230 /* setup color mode */
231 gsctrl
&= ~(FMsk(GSCTRL_GPIXFMT
));
232 /* FIXME: add *WORKING* support for 8-bits per color */
233 if (info
->var
.bits_per_pixel
== 8) {
236 fb_dealloc_cmap(&info
->cmap
);
237 gsctrl
&= ~GSCTRL_LUT_EN
;
239 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
240 switch (info
->var
.bits_per_pixel
) {
242 if (info
->var
.green
.length
== 5)
243 gsctrl
|= GSCTRL_GPIXFMT_ARGB1555
;
245 gsctrl
|= GSCTRL_GPIXFMT_RGB565
;
248 gsctrl
|= GSCTRL_GPIXFMT_RGB888
;
251 gsctrl
|= GSCTRL_GPIXFMT_ARGB8888
;
256 /* setup resolution */
257 gsctrl
&= ~(FMsk(GSCTRL_GSWIDTH
) | FMsk(GSCTRL_GSHEIGHT
));
258 gsctrl
|= Gsctrl_Width(info
->var
.xres
) |
259 Gsctrl_Height(info
->var
.yres
);
260 writel(gsctrl
, GSCTRL
);
263 gsadr
&= ~(FMsk(GSADR_SRCSTRIDE
));
264 gsadr
|= Gsadr_Srcstride(info
->var
.xres
* info
->var
.bits_per_pixel
/
266 writel(gsadr
, GSADR
);
270 var
->pixclock
= mbxfb_get_pixclock(info
->var
.pixclock
, &div
);
272 writel((Disp_Pll_M(div
.m
) | Disp_Pll_N(div
.n
) |
273 Disp_Pll_P(div
.p
) | DISP_PLL_EN
), DISPPLL
);
275 hbps
= var
->hsync_len
;
276 has
= hbps
+ var
->left_margin
;
277 hfps
= has
+ var
->xres
;
278 ht
= hfps
+ var
->right_margin
;
280 vbps
= var
->vsync_len
;
281 vas
= vbps
+ var
->upper_margin
;
282 vfps
= vas
+ var
->yres
;
283 vt
= vfps
+ var
->lower_margin
;
285 writel((Dht01_Hbps(hbps
) | Dht01_Ht(ht
)), DHT01
);
286 writel((Dht02_Hlbs(has
) | Dht02_Has(has
)), DHT02
);
287 writel((Dht03_Hfps(hfps
) | Dht03_Hrbs(hfps
)), DHT03
);
288 writel((Dhdet_Hdes(has
) | Dhdet_Hdef(hfps
)), DHDET
);
290 writel((Dvt01_Vbps(vbps
) | Dvt01_Vt(vt
)), DVT01
);
291 writel((Dvt02_Vtbs(vas
) | Dvt02_Vas(vas
)), DVT02
);
292 writel((Dvt03_Vfps(vfps
) | Dvt03_Vbbs(vfps
)), DVT03
);
293 writel((Dvdet_Vdes(vas
) | Dvdet_Vdef(vfps
)), DVDET
);
294 writel((Dvectrl_Vevent(vfps
) | Dvectrl_Vfetch(vbps
)), DVECTRL
);
296 writel((readl(DSCTRL
) | DSCTRL_SYNCGEN_EN
), DSCTRL
);
301 static int mbxfb_blank(int blank
, struct fb_info
*info
)
304 case FB_BLANK_POWERDOWN
:
305 case FB_BLANK_VSYNC_SUSPEND
:
306 case FB_BLANK_HSYNC_SUSPEND
:
307 case FB_BLANK_NORMAL
:
308 writel((readl(DSCTRL
) & ~DSCTRL_SYNCGEN_EN
), DSCTRL
);
310 writel((readl(PIXCLK
) & ~PIXCLK_EN
), PIXCLK
);
312 writel((readl(VOVRCLK
) & ~VOVRCLK_EN
), VOVRCLK
);
315 case FB_BLANK_UNBLANK
:
316 writel((readl(DSCTRL
) | DSCTRL_SYNCGEN_EN
), DSCTRL
);
318 writel((readl(PIXCLK
) | PIXCLK_EN
), PIXCLK
);
325 static struct fb_ops mbxfb_ops
= {
326 .owner
= THIS_MODULE
,
327 .fb_check_var
= mbxfb_check_var
,
328 .fb_set_par
= mbxfb_set_par
,
329 .fb_setcolreg
= mbxfb_setcolreg
,
330 .fb_fillrect
= cfb_fillrect
,
331 .fb_copyarea
= cfb_copyarea
,
332 .fb_imageblit
= cfb_imageblit
,
333 .fb_blank
= mbxfb_blank
,
337 Enable external SDRAM controller. Assume that all clocks are active
340 static void __devinit
setup_memc(struct fb_info
*fbi
)
342 struct mbxfb_info
*mfbi
= fbi
->par
;
346 /* FIXME: use platfrom specific parameters */
347 /* setup SDRAM controller */
348 writel((LMCFG_LMC_DS
| LMCFG_LMC_TS
| LMCFG_LMD_TS
|
353 writel(LMPWR_MC_PWR_ACT
, LMPWR
);
356 /* setup SDRAM timings */
357 writel((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
358 Lmtim_Trc(9) | Lmtim_Tdpl(2)),
361 /* setup SDRAM refresh rate */
362 writel(0xc2b, LMREFRESH
);
364 /* setup SDRAM type parameters */
365 writel((LMTYPE_CASLAT_3
| LMTYPE_BKSZ_2
| LMTYPE_ROWSZ_11
|
369 /* enable memory controller */
370 writel(LMPWR_MC_PWR_ACT
, LMPWR
);
373 /* perform dummy reads */
374 for ( i
= 0; i
< 16; i
++ ) {
375 tmp
= readl(fbi
->screen_base
);
379 static void enable_clocks(struct fb_info
*fbi
)
382 writel(SYSCLKSRC_PLL_2
, SYSCLKSRC
);
384 writel(PIXCLKSRC_PLL_1
, PIXCLKSRC
);
386 writel(0x00000000, CLKSLEEP
);
388 writel((Core_Pll_M(0x17) | Core_Pll_N(0x3) | Core_Pll_P(0x0) |
392 writel((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
396 writel(0x00000000, VOVRCLK
);
398 writel(PIXCLK_EN
, PIXCLK
);
400 writel(MEMCLK_EN
, MEMCLK
);
402 writel(0x00000006, M24CLK
);
404 writel(0x00000006, MBXCLK
);
406 writel(SDCLK_EN
, SDCLK
);
408 writel(0x00000001, PIXCLKDIV
);
412 static void __devinit
setup_graphics(struct fb_info
*fbi
)
414 unsigned long gsctrl
;
416 gsctrl
= GSCTRL_GAMMA_EN
| Gsctrl_Width(fbi
->var
.xres
) |
417 Gsctrl_Height(fbi
->var
.yres
);
418 switch (fbi
->var
.bits_per_pixel
) {
420 if (fbi
->var
.green
.length
== 5)
421 gsctrl
|= GSCTRL_GPIXFMT_ARGB1555
;
423 gsctrl
|= GSCTRL_GPIXFMT_RGB565
;
426 gsctrl
|= GSCTRL_GPIXFMT_RGB888
;
429 gsctrl
|= GSCTRL_GPIXFMT_ARGB8888
;
433 writel(gsctrl
, GSCTRL
);
435 writel(0x00000000, GBBASE
);
437 writel(0x00ffffff, GDRCTRL
);
439 writel((GSCADR_STR_EN
| Gscadr_Gbase_Adr(0x6000)), GSCADR
);
441 writel(0x00000000, GPLUT
);
445 static void __devinit
setup_display(struct fb_info
*fbi
)
447 unsigned long dsctrl
= 0;
449 dsctrl
= DSCTRL_BLNK_POL
;
450 if (fbi
->var
.sync
& FB_SYNC_HOR_HIGH_ACT
)
451 dsctrl
|= DSCTRL_HS_POL
;
452 if (fbi
->var
.sync
& FB_SYNC_VERT_HIGH_ACT
)
453 dsctrl
|= DSCTRL_VS_POL
;
454 writel(dsctrl
, DSCTRL
);
456 writel(0xd0303010, DMCTRL
);
458 writel((readl(DSCTRL
) | DSCTRL_SYNCGEN_EN
), DSCTRL
);
461 static void __devinit
enable_controller(struct fb_info
*fbi
)
463 writel(SYSRST_RST
, SYSRST
);
475 * Power management hooks. Note that we won't be called from IRQ context,
476 * unlike the blank functions above, so we may sleep.
478 static int mbxfb_suspend(struct platform_device
*dev
, pm_message_t state
)
480 /* make frame buffer memory enter self-refresh mode */
481 writel(LMPWR_MC_PWR_SRM
, LMPWR
);
482 while (LMPWRSTAT
!= LMPWRSTAT_MC_PWR_SRM
)
483 ; /* empty statement */
485 /* reset the device, since it's initial state is 'mostly sleeping' */
486 writel(SYSRST_RST
, SYSRST
);
490 static int mbxfb_resume(struct platform_device
*dev
)
492 struct fb_info
*fbi
= platform_get_drvdata(dev
);
495 /* setup_graphics(fbi); */
496 /* setup_display(fbi); */
498 writel((readl(DSCTRL
) | DSCTRL_SYNCGEN_EN
), DSCTRL
);
502 #define mbxfb_suspend NULL
503 #define mbxfb_resume NULL
506 /* debugfs entries */
507 #ifndef CONFIG_FB_MBX_DEBUG
508 #define mbxfb_debugfs_init(x) do {} while(0)
509 #define mbxfb_debugfs_remove(x) do {} while(0)
512 #define res_size(_r) (((_r)->end - (_r)->start) + 1)
514 static int __devinit
mbxfb_probe(struct platform_device
*dev
)
518 struct mbxfb_info
*mfbi
;
519 struct mbxfb_platform_data
*pdata
;
521 dev_dbg(dev
, "mbxfb_probe\n");
523 fbi
= framebuffer_alloc(sizeof(struct mbxfb_info
), &dev
->dev
);
525 dev_err(&dev
->dev
, "framebuffer_alloc failed\n");
530 fbi
->pseudo_palette
= mfbi
->pseudo_palette
;
531 pdata
= dev
->dev
.platform_data
;
533 mfbi
->platform_probe
= pdata
->probe
;
535 mfbi
->platform_remove
= pdata
->remove
;
537 mfbi
->fb_res
= platform_get_resource(dev
, IORESOURCE_MEM
, 0);
538 mfbi
->reg_res
= platform_get_resource(dev
, IORESOURCE_MEM
, 1);
540 if (!mfbi
->fb_res
|| !mfbi
->reg_res
) {
541 dev_err(&dev
->dev
, "no resources found\n");
546 mfbi
->fb_req
= request_mem_region(mfbi
->fb_res
->start
,
547 res_size(mfbi
->fb_res
), dev
->name
);
548 if (mfbi
->fb_req
== NULL
) {
549 dev_err(&dev
->dev
, "failed to claim framebuffer memory\n");
553 mfbi
->fb_phys_addr
= mfbi
->fb_res
->start
;
555 mfbi
->reg_req
= request_mem_region(mfbi
->reg_res
->start
,
556 res_size(mfbi
->reg_res
), dev
->name
);
557 if (mfbi
->reg_req
== NULL
) {
558 dev_err(&dev
->dev
, "failed to claim Marathon registers\n");
562 mfbi
->reg_phys_addr
= mfbi
->reg_res
->start
;
564 mfbi
->reg_virt_addr
= ioremap_nocache(mfbi
->reg_phys_addr
,
565 res_size(mfbi
->reg_req
));
566 if (!mfbi
->reg_virt_addr
) {
567 dev_err(&dev
->dev
, "failed to ioremap Marathon registers\n");
571 virt_base_2700
= (unsigned long)mfbi
->reg_virt_addr
;
573 mfbi
->fb_virt_addr
= ioremap_nocache(mfbi
->fb_phys_addr
,
574 res_size(mfbi
->fb_req
));
575 if (!mfbi
->reg_virt_addr
) {
576 dev_err(&dev
->dev
, "failed to ioremap frame buffer\n");
581 /* FIXME: get from platform */
582 fbi
->screen_base
= (char __iomem
*)(mfbi
->fb_virt_addr
+ 0x60000);
583 fbi
->screen_size
= 8 * 1024 * 1024; /* 8 Megs */
584 fbi
->fbops
= &mbxfb_ops
;
586 fbi
->var
= mbxfb_default
;
587 fbi
->fix
= mbxfb_fix
;
588 fbi
->fix
.smem_start
= mfbi
->fb_phys_addr
+ 0x60000;
589 fbi
->fix
.smem_len
= 8 * 1024 * 1024;
590 fbi
->fix
.line_length
= 640 * 2;
592 ret
= fb_alloc_cmap(&fbi
->cmap
, 256, 0);
594 dev_err(&dev
->dev
, "fb_alloc_cmap failed\n");
599 platform_set_drvdata(dev
, fbi
);
601 printk(KERN_INFO
"fb%d: mbx frame buffer device\n", fbi
->node
);
603 if (mfbi
->platform_probe
)
604 mfbi
->platform_probe(fbi
);
606 enable_controller(fbi
);
608 mbxfb_debugfs_init(fbi
);
610 ret
= register_framebuffer(fbi
);
612 dev_err(&dev
->dev
, "register_framebuffer failed\n");
620 fb_dealloc_cmap(&fbi
->cmap
);
622 iounmap(mfbi
->fb_virt_addr
);
624 iounmap(mfbi
->reg_virt_addr
);
626 release_mem_region(mfbi
->reg_res
->start
, res_size(mfbi
->reg_res
));
628 release_mem_region(mfbi
->fb_res
->start
, res_size(mfbi
->fb_res
));
630 framebuffer_release(fbi
);
635 static int __devexit
mbxfb_remove(struct platform_device
*dev
)
637 struct fb_info
*fbi
= platform_get_drvdata(dev
);
639 writel(SYSRST_RST
, SYSRST
);
642 mbxfb_debugfs_remove(fbi
);
645 struct mbxfb_info
*mfbi
= fbi
->par
;
647 unregister_framebuffer(fbi
);
649 if (mfbi
->platform_remove
)
650 mfbi
->platform_remove(fbi
);
652 if (mfbi
->fb_virt_addr
)
653 iounmap(mfbi
->fb_virt_addr
);
654 if (mfbi
->reg_virt_addr
)
655 iounmap(mfbi
->reg_virt_addr
);
657 release_mem_region(mfbi
->reg_req
->start
,
658 res_size(mfbi
->reg_req
));
660 release_mem_region(mfbi
->fb_req
->start
,
661 res_size(mfbi
->fb_req
));
663 framebuffer_release(fbi
);
669 static struct platform_driver mbxfb_driver
= {
670 .probe
= mbxfb_probe
,
671 .remove
= mbxfb_remove
,
672 .suspend
= mbxfb_suspend
,
673 .resume
= mbxfb_resume
,
679 int __devinit
mbxfb_init(void)
681 return platform_driver_register(&mbxfb_driver
);
684 static void __devexit
mbxfb_exit(void)
686 platform_driver_unregister(&mbxfb_driver
);
689 module_init(mbxfb_init
);
690 module_exit(mbxfb_exit
);
692 MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
693 MODULE_AUTHOR("Mike Rapoport, Compulab");
694 MODULE_LICENSE("GPL");