2 * Frame Buffer Driver for PKUnity-v3 Unigfx
3 * Code specific to PKUnity SoC and UniCore ISA
5 * Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
6 * Copyright (C) 2001-2010 Guan Xuetao
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/platform_device.h>
17 #include <linux/clk.h>
19 #include <linux/init.h>
20 #include <linux/console.h>
23 #include <asm/sizes.h>
24 #include <asm/pgtable.h>
25 #include <mach/hardware.h>
27 /* Platform_data reserved for unifb registers. */
28 #define UNIFB_REGS_NUM 10
29 /* RAM reserved for the frame buffer. */
30 #define UNIFB_MEMSIZE (SZ_4M) /* 4 MB for 1024*768*32b */
33 * cause UNIGFX don not have EDID
34 * all the modes are organized as follow
36 static const struct fb_videomode unifb_modes
[] = {
37 /* 0 640x480-60 VESA */
38 { "640x480@60", 60, 640, 480, 25175000, 48, 16, 34, 10, 96, 1,
39 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
40 /* 1 640x480-75 VESA */
41 { "640x480@75", 75, 640, 480, 31500000, 120, 16, 18, 1, 64, 1,
42 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
43 /* 2 800x600-60 VESA */
44 { "800x600@60", 60, 800, 600, 40000000, 88, 40, 26, 1, 128, 1,
45 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
46 /* 3 800x600-75 VESA */
47 { "800x600@75", 75, 800, 600, 49500000, 160, 16, 23, 1, 80, 1,
48 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
49 /* 4 1024x768-60 VESA */
50 { "1024x768@60", 60, 1024, 768, 65000000, 160, 24, 34, 3, 136, 1,
51 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
52 /* 5 1024x768-75 VESA */
53 { "1024x768@75", 75, 1024, 768, 78750000, 176, 16, 30, 1, 96, 1,
54 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
55 /* 6 1280x960-60 VESA */
56 { "1280x960@60", 60, 1280, 960, 108000000, 312, 96, 38, 1, 112, 1,
57 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
58 /* 7 1440x900-60 VESA */
59 { "1440x900@60", 60, 1440, 900, 106500000, 232, 80, 30, 3, 152, 1,
60 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
61 /* 8 FIXME 9 1024x600-60 VESA UNTESTED */
62 { "1024x600@60", 60, 1024, 600, 50650000, 160, 24, 26, 1, 136, 1,
63 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
64 /* 9 FIXME 10 1024x600-75 VESA UNTESTED */
65 { "1024x600@75", 75, 1024, 600, 61500000, 176, 16, 23, 1, 96, 1,
66 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
67 /* 10 FIXME 11 1366x768-60 VESA UNTESTED */
68 { "1366x768@60", 60, 1366, 768, 85500000, 256, 58, 18, 1, 112, 3,
69 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
72 static struct fb_var_screeninfo unifb_default
= {
81 .activate
= FB_ACTIVATE_NOW
,
91 .vmode
= FB_VMODE_NONINTERLACED
,
94 static struct fb_fix_screeninfo unifb_fix
= {
96 .type
= FB_TYPE_PACKED_PIXELS
,
97 .visual
= FB_VISUAL_TRUECOLOR
,
101 .accel
= FB_ACCEL_NONE
,
104 static void unifb_sync(struct fb_info
*info
)
106 /* TODO: may, this can be replaced by interrupt */
109 for (cnt
= 0; cnt
< 0x10000000; cnt
++) {
110 if (readl(UGE_COMMAND
) & 0x1000000)
115 dev_warn(info
->device
, "Warning: UniGFX GE time out ...\n");
118 static void unifb_prim_fillrect(struct fb_info
*info
,
119 const struct fb_fillrect
*region
)
121 int awidth
= region
->width
;
122 int aheight
= region
->height
;
123 int m_iBpp
= info
->var
.bits_per_pixel
;
124 int screen_width
= info
->var
.xres
;
125 int src_sel
= 1; /* from fg_color */
128 int dst_x0
= region
->dx
;
130 int dst_y0
= region
->dy
;
131 int rop_alpha_sel
= 0;
132 int rop_alpha_code
= 0xCC;
137 int dst_pitch
= screen_width
* (m_iBpp
/ 8);
138 int dst_offset
= dst_y0
* dst_pitch
+ dst_x0
* (m_iBpp
/ 8);
139 int src_pitch
= screen_width
* (m_iBpp
/ 8);
140 int src_offset
= src_y0
* src_pitch
+ src_x0
* (m_iBpp
/ 8);
141 unsigned int command
= 0;
146 int bottom
= info
->var
.yres
- 1;
147 int right
= info
->var
.xres
- 1;
150 bottom
= (bottom
<< 16) | right
;
151 command
= (rop_alpha_sel
<< 26) | (pat_sel
<< 18) | (src_sel
<< 16)
152 | (x_dir
<< 20) | (y_dir
<< 21) | (command
<< 24)
153 | (clip_region
<< 23) | (clip_en
<< 22) | (tp_en
<< 27);
154 src_pitch
= (dst_pitch
<< 16) | src_pitch
;
155 awidth
= awidth
| (aheight
<< 16);
156 alpha_r
= ((rop_alpha_code
& 0xff) << 8) | (alpha_r
& 0xff)
158 src_x0
= (src_x0
& 0x1fff) | ((src_y0
& 0x1fff) << 16);
159 dst_x0
= (dst_x0
& 0x1fff) | ((dst_y0
& 0x1fff) << 16);
160 fg_color
= region
->color
;
164 writel(((u32
*)(info
->pseudo_palette
))[fg_color
], UGE_FCOLOR
);
165 writel(0, UGE_BCOLOR
);
166 writel(src_pitch
, UGE_PITCH
);
167 writel(src_offset
, UGE_SRCSTART
);
168 writel(dst_offset
, UGE_DSTSTART
);
169 writel(awidth
, UGE_WIDHEIGHT
);
170 writel(top
, UGE_CLIP0
);
171 writel(bottom
, UGE_CLIP1
);
172 writel(alpha_r
, UGE_ROPALPHA
);
173 writel(src_x0
, UGE_SRCXY
);
174 writel(dst_x0
, UGE_DSTXY
);
175 writel(command
, UGE_COMMAND
);
178 static void unifb_fillrect(struct fb_info
*info
,
179 const struct fb_fillrect
*region
)
181 struct fb_fillrect modded
;
184 if (info
->flags
& FBINFO_HWACCEL_DISABLED
) {
185 sys_fillrect(info
, region
);
189 vxres
= info
->var
.xres_virtual
;
190 vyres
= info
->var
.yres_virtual
;
192 memcpy(&modded
, region
, sizeof(struct fb_fillrect
));
194 if (!modded
.width
|| !modded
.height
||
195 modded
.dx
>= vxres
|| modded
.dy
>= vyres
)
198 if (modded
.dx
+ modded
.width
> vxres
)
199 modded
.width
= vxres
- modded
.dx
;
200 if (modded
.dy
+ modded
.height
> vyres
)
201 modded
.height
= vyres
- modded
.dy
;
203 unifb_prim_fillrect(info
, &modded
);
206 static void unifb_prim_copyarea(struct fb_info
*info
,
207 const struct fb_copyarea
*area
)
209 int awidth
= area
->width
;
210 int aheight
= area
->height
;
211 int m_iBpp
= info
->var
.bits_per_pixel
;
212 int screen_width
= info
->var
.xres
;
213 int src_sel
= 2; /* from mem */
215 int src_x0
= area
->sx
;
216 int dst_x0
= area
->dx
;
217 int src_y0
= area
->sy
;
218 int dst_y0
= area
->dy
;
220 int rop_alpha_sel
= 0;
221 int rop_alpha_code
= 0xCC;
227 int dst_pitch
= screen_width
* (m_iBpp
/ 8);
228 int dst_offset
= dst_y0
* dst_pitch
+ dst_x0
* (m_iBpp
/ 8);
229 int src_pitch
= screen_width
* (m_iBpp
/ 8);
230 int src_offset
= src_y0
* src_pitch
+ src_x0
* (m_iBpp
/ 8);
231 unsigned int command
= 0;
236 int bottom
= info
->var
.yres
;
237 int right
= info
->var
.xres
;
246 if (src_y0
- dst_y0
> 0) {
250 src_offset
= (src_y0
+ aheight
) * src_pitch
+
251 src_x0
* (m_iBpp
/ 8);
252 dst_offset
= (dst_y0
+ aheight
) * dst_pitch
+
253 dst_x0
* (m_iBpp
/ 8);
258 command
= (rop_alpha_sel
<< 26) | (pat_sel
<< 18) | (src_sel
<< 16) |
259 (x_dir
<< 20) | (y_dir
<< 21) | (command
<< 24) |
260 (clip_region
<< 23) | (clip_en
<< 22) | (tp_en
<< 27);
261 src_pitch
= (dst_pitch
<< 16) | src_pitch
;
262 awidth
= awidth
| (aheight
<< 16);
263 alpha_r
= ((rop_alpha_code
& 0xff) << 8) | (alpha_r
& 0xff) |
265 src_x0
= (src_x0
& 0x1fff) | ((src_y0
& 0x1fff) << 16);
266 dst_x0
= (dst_x0
& 0x1fff) | ((dst_y0
& 0x1fff) << 16);
267 bottom
= (bottom
<< 16) | right
;
271 writel(src_pitch
, UGE_PITCH
);
272 writel(src_offset
, UGE_SRCSTART
);
273 writel(dst_offset
, UGE_DSTSTART
);
274 writel(awidth
, UGE_WIDHEIGHT
);
275 writel(top
, UGE_CLIP0
);
276 writel(bottom
, UGE_CLIP1
);
277 writel(bg_color
, UGE_BCOLOR
);
278 writel(fg_color
, UGE_FCOLOR
);
279 writel(alpha_r
, UGE_ROPALPHA
);
280 writel(src_x0
, UGE_SRCXY
);
281 writel(dst_x0
, UGE_DSTXY
);
282 writel(command
, UGE_COMMAND
);
285 static void unifb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
287 struct fb_copyarea modded
;
289 modded
.sx
= area
->sx
;
290 modded
.sy
= area
->sy
;
291 modded
.dx
= area
->dx
;
292 modded
.dy
= area
->dy
;
293 modded
.width
= area
->width
;
294 modded
.height
= area
->height
;
296 if (info
->flags
& FBINFO_HWACCEL_DISABLED
) {
297 sys_copyarea(info
, area
);
301 vxres
= info
->var
.xres_virtual
;
302 vyres
= info
->var
.yres_virtual
;
304 if (!modded
.width
|| !modded
.height
||
305 modded
.sx
>= vxres
|| modded
.sy
>= vyres
||
306 modded
.dx
>= vxres
|| modded
.dy
>= vyres
)
309 if (modded
.sx
+ modded
.width
> vxres
)
310 modded
.width
= vxres
- modded
.sx
;
311 if (modded
.dx
+ modded
.width
> vxres
)
312 modded
.width
= vxres
- modded
.dx
;
313 if (modded
.sy
+ modded
.height
> vyres
)
314 modded
.height
= vyres
- modded
.sy
;
315 if (modded
.dy
+ modded
.height
> vyres
)
316 modded
.height
= vyres
- modded
.dy
;
318 unifb_prim_copyarea(info
, &modded
);
321 static void unifb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
323 sys_imageblit(info
, image
);
326 static u_long
get_line_length(int xres_virtual
, int bpp
)
330 length
= xres_virtual
* bpp
;
331 length
= (length
+ 31) & ~31;
337 * Setting the video mode has been split into two parts.
338 * First part, xxxfb_check_var, must not write anything
339 * to hardware, it should only verify and adjust var.
340 * This means it doesn't alter par but it does use hardware
341 * data from it to check this var.
343 static int unifb_check_var(struct fb_var_screeninfo
*var
,
344 struct fb_info
*info
)
349 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
350 * as FB_VMODE_SMOOTH_XPAN is only used internally
353 if (var
->vmode
& FB_VMODE_CONUPDATE
) {
354 var
->vmode
|= FB_VMODE_YWRAP
;
355 var
->xoffset
= info
->var
.xoffset
;
356 var
->yoffset
= info
->var
.yoffset
;
360 * Some very basic checks
366 if (var
->xres
> var
->xres_virtual
)
367 var
->xres_virtual
= var
->xres
;
368 if (var
->yres
> var
->yres_virtual
)
369 var
->yres_virtual
= var
->yres
;
370 if (var
->bits_per_pixel
<= 1)
371 var
->bits_per_pixel
= 1;
372 else if (var
->bits_per_pixel
<= 8)
373 var
->bits_per_pixel
= 8;
374 else if (var
->bits_per_pixel
<= 16)
375 var
->bits_per_pixel
= 16;
376 else if (var
->bits_per_pixel
<= 24)
377 var
->bits_per_pixel
= 24;
378 else if (var
->bits_per_pixel
<= 32)
379 var
->bits_per_pixel
= 32;
383 if (var
->xres_virtual
< var
->xoffset
+ var
->xres
)
384 var
->xres_virtual
= var
->xoffset
+ var
->xres
;
385 if (var
->yres_virtual
< var
->yoffset
+ var
->yres
)
386 var
->yres_virtual
= var
->yoffset
+ var
->yres
;
392 get_line_length(var
->xres_virtual
, var
->bits_per_pixel
);
393 if (line_length
* var
->yres_virtual
> UNIFB_MEMSIZE
)
397 * Now that we checked it we alter var. The reason being is that the
398 * video mode passed in might not work but slight changes to it might
399 * make it work. This way we let the user know what is acceptable.
401 switch (var
->bits_per_pixel
) {
406 var
->green
.offset
= 0;
407 var
->green
.length
= 8;
408 var
->blue
.offset
= 0;
409 var
->blue
.length
= 8;
410 var
->transp
.offset
= 0;
411 var
->transp
.length
= 0;
413 case 16: /* RGBA 5551 */
414 if (var
->transp
.length
) {
417 var
->green
.offset
= 5;
418 var
->green
.length
= 5;
419 var
->blue
.offset
= 10;
420 var
->blue
.length
= 5;
421 var
->transp
.offset
= 15;
422 var
->transp
.length
= 1;
423 } else { /* RGB 565 */
424 var
->red
.offset
= 11;
426 var
->green
.offset
= 5;
427 var
->green
.length
= 6;
428 var
->blue
.offset
= 0;
429 var
->blue
.length
= 5;
430 var
->transp
.offset
= 0;
431 var
->transp
.length
= 0;
434 case 24: /* RGB 888 */
437 var
->green
.offset
= 8;
438 var
->green
.length
= 8;
439 var
->blue
.offset
= 16;
440 var
->blue
.length
= 8;
441 var
->transp
.offset
= 0;
442 var
->transp
.length
= 0;
444 case 32: /* RGBA 8888 */
445 var
->red
.offset
= 16;
447 var
->green
.offset
= 8;
448 var
->green
.length
= 8;
449 var
->blue
.offset
= 0;
450 var
->blue
.length
= 8;
451 var
->transp
.offset
= 24;
452 var
->transp
.length
= 8;
455 var
->red
.msb_right
= 0;
456 var
->green
.msb_right
= 0;
457 var
->blue
.msb_right
= 0;
458 var
->transp
.msb_right
= 0;
464 * This routine actually sets the video mode. It's in here where we
465 * the hardware state info->par and fix which can be affected by the
466 * change in par. For this driver it doesn't do much.
468 static int unifb_set_par(struct fb_info
*info
)
470 int hTotal
, vTotal
, hSyncStart
, hSyncEnd
, vSyncStart
, vSyncEnd
;
473 #ifdef CONFIG_PUV3_PM
478 for (i
= 0; i
<= 10; i
++) {
479 if (info
->var
.xres
== unifb_modes
[i
].xres
480 && info
->var
.yres
== unifb_modes
[i
].yres
481 && info
->var
.upper_margin
== unifb_modes
[i
].upper_margin
482 && info
->var
.lower_margin
== unifb_modes
[i
].lower_margin
483 && info
->var
.left_margin
== unifb_modes
[i
].left_margin
484 && info
->var
.right_margin
== unifb_modes
[i
].right_margin
485 && info
->var
.hsync_len
== unifb_modes
[i
].hsync_len
486 && info
->var
.vsync_len
== unifb_modes
[i
].vsync_len
) {
487 pixclk
= unifb_modes
[i
].pixclock
;
493 clk_vga
= clk_get(info
->device
, "VGA_CLK");
494 if (clk_vga
== ERR_PTR(-ENOENT
))
498 if (clk_set_rate(clk_vga
, pixclk
)) { /* set clock failed */
499 info
->fix
= unifb_fix
;
500 info
->var
= unifb_default
;
501 if (clk_set_rate(clk_vga
, unifb_default
.pixclock
))
507 info
->fix
.line_length
= get_line_length(info
->var
.xres_virtual
,
508 info
->var
.bits_per_pixel
);
510 hSyncStart
= info
->var
.xres
+ info
->var
.right_margin
;
511 hSyncEnd
= hSyncStart
+ info
->var
.hsync_len
;
512 hTotal
= hSyncEnd
+ info
->var
.left_margin
;
514 vSyncStart
= info
->var
.yres
+ info
->var
.lower_margin
;
515 vSyncEnd
= vSyncStart
+ info
->var
.vsync_len
;
516 vTotal
= vSyncEnd
+ info
->var
.upper_margin
;
518 switch (info
->var
.bits_per_pixel
) {
520 format
= UDE_CFG_DST8
;
523 format
= UDE_CFG_DST16
;
526 format
= UDE_CFG_DST24
;
529 format
= UDE_CFG_DST32
;
535 writel(info
->fix
.smem_start
, UDE_FSA
);
536 writel(info
->var
.yres
, UDE_LS
);
537 writel(get_line_length(info
->var
.xres
,
538 info
->var
.bits_per_pixel
) >> 3, UDE_PS
);
539 /* >> 3 for hardware required. */
540 writel((hTotal
<< 16) | (info
->var
.xres
), UDE_HAT
);
541 writel(((hTotal
- 1) << 16) | (info
->var
.xres
- 1), UDE_HBT
);
542 writel(((hSyncEnd
- 1) << 16) | (hSyncStart
- 1), UDE_HST
);
543 writel((vTotal
<< 16) | (info
->var
.yres
), UDE_VAT
);
544 writel(((vTotal
- 1) << 16) | (info
->var
.yres
- 1), UDE_VBT
);
545 writel(((vSyncEnd
- 1) << 16) | (vSyncStart
- 1), UDE_VST
);
546 writel(UDE_CFG_GDEN_ENABLE
| UDE_CFG_TIMEUP_ENABLE
547 | format
| 0xC0000001, UDE_CFG
);
553 * Set a single color register. The values supplied are already
554 * rounded down to the hardware's capabilities (according to the
555 * entries in the var structure). Return != 0 for invalid regno.
557 static int unifb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
558 u_int transp
, struct fb_info
*info
)
560 if (regno
>= 256) /* no. of hw registers */
563 /* grayscale works only partially under directcolor */
564 if (info
->var
.grayscale
) {
565 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
567 (red
* 77 + green
* 151 + blue
* 28) >> 8;
570 #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
571 switch (info
->fix
.visual
) {
572 case FB_VISUAL_TRUECOLOR
:
573 case FB_VISUAL_PSEUDOCOLOR
:
574 red
= CNVT_TOHW(red
, info
->var
.red
.length
);
575 green
= CNVT_TOHW(green
, info
->var
.green
.length
);
576 blue
= CNVT_TOHW(blue
, info
->var
.blue
.length
);
577 transp
= CNVT_TOHW(transp
, info
->var
.transp
.length
);
579 case FB_VISUAL_DIRECTCOLOR
:
580 red
= CNVT_TOHW(red
, 8); /* expect 8 bit DAC */
581 green
= CNVT_TOHW(green
, 8);
582 blue
= CNVT_TOHW(blue
, 8);
583 /* hey, there is bug in transp handling... */
584 transp
= CNVT_TOHW(transp
, 8);
588 /* Truecolor has hardware independent palette */
589 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
595 v
= (red
<< info
->var
.red
.offset
) |
596 (green
<< info
->var
.green
.offset
) |
597 (blue
<< info
->var
.blue
.offset
) |
598 (transp
<< info
->var
.transp
.offset
);
599 switch (info
->var
.bits_per_pixel
) {
605 ((u32
*) (info
->pseudo_palette
))[regno
] = v
;
616 * Pan or Wrap the Display
618 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
620 static int unifb_pan_display(struct fb_var_screeninfo
*var
,
621 struct fb_info
*info
)
623 if (var
->vmode
& FB_VMODE_YWRAP
) {
625 || var
->yoffset
>= info
->var
.yres_virtual
629 if (var
->xoffset
+ info
->var
.xres
> info
->var
.xres_virtual
||
630 var
->yoffset
+ info
->var
.yres
> info
->var
.yres_virtual
)
633 info
->var
.xoffset
= var
->xoffset
;
634 info
->var
.yoffset
= var
->yoffset
;
635 if (var
->vmode
& FB_VMODE_YWRAP
)
636 info
->var
.vmode
|= FB_VMODE_YWRAP
;
638 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
642 int unifb_mmap(struct fb_info
*info
,
643 struct vm_area_struct
*vma
)
645 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
647 return vm_iomap_memory(vma
, info
->fix
.smem_start
, info
->fix
.smem_len
);
650 static struct fb_ops unifb_ops
= {
651 .fb_read
= fb_sys_read
,
652 .fb_write
= fb_sys_write
,
653 .fb_check_var
= unifb_check_var
,
654 .fb_set_par
= unifb_set_par
,
655 .fb_setcolreg
= unifb_setcolreg
,
656 .fb_pan_display
= unifb_pan_display
,
657 .fb_fillrect
= unifb_fillrect
,
658 .fb_copyarea
= unifb_copyarea
,
659 .fb_imageblit
= unifb_imageblit
,
660 .fb_mmap
= unifb_mmap
,
666 static int unifb_probe(struct platform_device
*dev
)
668 struct fb_info
*info
;
669 u32 unifb_regs
[UNIFB_REGS_NUM
];
670 int retval
= -ENOMEM
;
671 struct resource
*iomem
;
674 videomemory
= (void *)__get_free_pages(GFP_KERNEL
| __GFP_COMP
,
675 get_order(UNIFB_MEMSIZE
));
679 memset(videomemory
, 0, UNIFB_MEMSIZE
);
681 unifb_fix
.smem_start
= virt_to_phys(videomemory
);
682 unifb_fix
.smem_len
= UNIFB_MEMSIZE
;
684 iomem
= platform_get_resource(dev
, IORESOURCE_MEM
, 0);
685 unifb_fix
.mmio_start
= iomem
->start
;
687 info
= framebuffer_alloc(sizeof(u32
)*256, &dev
->dev
);
691 info
->screen_base
= (char __iomem
*)videomemory
;
692 info
->fbops
= &unifb_ops
;
694 retval
= fb_find_mode(&info
->var
, info
, NULL
,
695 unifb_modes
, 10, &unifb_modes
[0], 16);
697 if (!retval
|| (retval
== 4))
698 info
->var
= unifb_default
;
700 info
->fix
= unifb_fix
;
701 info
->pseudo_palette
= info
->par
;
703 info
->flags
= FBINFO_FLAG_DEFAULT
;
704 #ifdef FB_ACCEL_PUV3_UNIGFX
705 info
->fix
.accel
= FB_ACCEL_PUV3_UNIGFX
;
708 retval
= fb_alloc_cmap(&info
->cmap
, 256, 0);
712 retval
= register_framebuffer(info
);
715 platform_set_drvdata(dev
, info
);
716 platform_device_add_data(dev
, unifb_regs
, sizeof(u32
) * UNIFB_REGS_NUM
);
718 fb_info(info
, "Virtual frame buffer device, using %dM of video memory\n",
719 UNIFB_MEMSIZE
>> 20);
722 fb_dealloc_cmap(&info
->cmap
);
724 framebuffer_release(info
);
729 static int unifb_remove(struct platform_device
*dev
)
731 struct fb_info
*info
= platform_get_drvdata(dev
);
734 unregister_framebuffer(info
);
735 fb_dealloc_cmap(&info
->cmap
);
736 framebuffer_release(info
);
742 static int unifb_resume(struct platform_device
*dev
)
745 u32
*unifb_regs
= dev
->dev
.platform_data
;
747 if (dev
->dev
.power
.power_state
.event
== PM_EVENT_ON
)
752 if (dev
->dev
.power
.power_state
.event
== PM_EVENT_SUSPEND
) {
753 writel(unifb_regs
[0], UDE_FSA
);
754 writel(unifb_regs
[1], UDE_LS
);
755 writel(unifb_regs
[2], UDE_PS
);
756 writel(unifb_regs
[3], UDE_HAT
);
757 writel(unifb_regs
[4], UDE_HBT
);
758 writel(unifb_regs
[5], UDE_HST
);
759 writel(unifb_regs
[6], UDE_VAT
);
760 writel(unifb_regs
[7], UDE_VBT
);
761 writel(unifb_regs
[8], UDE_VST
);
762 writel(unifb_regs
[9], UDE_CFG
);
764 dev
->dev
.power
.power_state
= PMSG_ON
;
771 static int unifb_suspend(struct platform_device
*dev
, pm_message_t mesg
)
773 u32
*unifb_regs
= dev
->dev
.platform_data
;
775 unifb_regs
[0] = readl(UDE_FSA
);
776 unifb_regs
[1] = readl(UDE_LS
);
777 unifb_regs
[2] = readl(UDE_PS
);
778 unifb_regs
[3] = readl(UDE_HAT
);
779 unifb_regs
[4] = readl(UDE_HBT
);
780 unifb_regs
[5] = readl(UDE_HST
);
781 unifb_regs
[6] = readl(UDE_VAT
);
782 unifb_regs
[7] = readl(UDE_VBT
);
783 unifb_regs
[8] = readl(UDE_VST
);
784 unifb_regs
[9] = readl(UDE_CFG
);
786 if (mesg
.event
== dev
->dev
.power
.power_state
.event
)
789 switch (mesg
.event
) {
790 case PM_EVENT_FREEZE
: /* about to take snapshot */
791 case PM_EVENT_PRETHAW
: /* before restoring snapshot */
802 dev
->dev
.power
.power_state
= mesg
;
807 #define unifb_resume NULL
808 #define unifb_suspend NULL
811 static struct platform_driver unifb_driver
= {
812 .probe
= unifb_probe
,
813 .remove
= unifb_remove
,
814 .resume
= unifb_resume
,
815 .suspend
= unifb_suspend
,
817 .name
= "PKUnity-v3-UNIGFX",
821 static int __init
unifb_init(void)
824 if (fb_get_options("unifb", NULL
))
828 return platform_driver_register(&unifb_driver
);
831 module_init(unifb_init
);
833 static void __exit
unifb_exit(void)
835 platform_driver_unregister(&unifb_driver
);
838 module_exit(unifb_exit
);
840 MODULE_LICENSE("GPL v2");