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/vmalloc.h>
17 #include <linux/platform_device.h>
18 #include <linux/clk.h>
20 #include <linux/init.h>
21 #include <linux/console.h>
23 #include <asm/sizes.h>
24 #include <mach/hardware.h>
26 /* Platform_data reserved for unifb registers. */
27 #define UNIFB_REGS_NUM 10
28 /* RAM reserved for the frame buffer. */
29 #define UNIFB_MEMSIZE (SZ_4M) /* 4 MB for 1024*768*32b */
32 * cause UNIGFX don not have EDID
33 * all the modes are organized as follow
35 static const struct fb_videomode unifb_modes
[] = {
36 /* 0 640x480-60 VESA */
37 { "640x480@60", 60, 640, 480, 25175000, 48, 16, 34, 10, 96, 1,
38 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
39 /* 1 640x480-75 VESA */
40 { "640x480@75", 75, 640, 480, 31500000, 120, 16, 18, 1, 64, 1,
41 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
42 /* 2 800x600-60 VESA */
43 { "800x600@60", 60, 800, 600, 40000000, 88, 40, 26, 1, 128, 1,
44 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
45 /* 3 800x600-75 VESA */
46 { "800x600@75", 75, 800, 600, 49500000, 160, 16, 23, 1, 80, 1,
47 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
48 /* 4 1024x768-60 VESA */
49 { "1024x768@60", 60, 1024, 768, 65000000, 160, 24, 34, 3, 136, 1,
50 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
51 /* 5 1024x768-75 VESA */
52 { "1024x768@75", 75, 1024, 768, 78750000, 176, 16, 30, 1, 96, 1,
53 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
54 /* 6 1280x960-60 VESA */
55 { "1280x960@60", 60, 1280, 960, 108000000, 312, 96, 38, 1, 112, 1,
56 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
57 /* 7 1440x900-60 VESA */
58 { "1440x900@60", 60, 1440, 900, 106500000, 232, 80, 30, 3, 152, 1,
59 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
60 /* 8 FIXME 9 1024x600-60 VESA UNTESTED */
61 { "1024x600@60", 60, 1024, 600, 50650000, 160, 24, 26, 1, 136, 1,
62 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
63 /* 9 FIXME 10 1024x600-75 VESA UNTESTED */
64 { "1024x600@75", 75, 1024, 600, 61500000, 176, 16, 23, 1, 96, 1,
65 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
66 /* 10 FIXME 11 1366x768-60 VESA UNTESTED */
67 { "1366x768@60", 60, 1366, 768, 85500000, 256, 58, 18, 1, 112, 3,
68 0, FB_VMODE_NONINTERLACED
, FB_MODE_IS_VESA
},
71 static struct fb_var_screeninfo unifb_default
= {
80 .activate
= FB_ACTIVATE_NOW
,
90 .vmode
= FB_VMODE_NONINTERLACED
,
93 static struct fb_fix_screeninfo unifb_fix
= {
95 .type
= FB_TYPE_PACKED_PIXELS
,
96 .visual
= FB_VISUAL_TRUECOLOR
,
100 .accel
= FB_ACCEL_NONE
,
103 static void unifb_sync(struct fb_info
*info
)
105 /* TODO: may, this can be replaced by interrupt */
108 for (cnt
= 0; cnt
< 0x10000000; cnt
++) {
109 if (readl(UGE_COMMAND
) & 0x1000000)
114 dev_warn(info
->device
, "Warning: UniGFX GE time out ...\n");
117 static void unifb_prim_fillrect(struct fb_info
*info
,
118 const struct fb_fillrect
*region
)
120 int awidth
= region
->width
;
121 int aheight
= region
->height
;
122 int m_iBpp
= info
->var
.bits_per_pixel
;
123 int screen_width
= info
->var
.xres
;
124 int src_sel
= 1; /* from fg_color */
127 int dst_x0
= region
->dx
;
129 int dst_y0
= region
->dy
;
130 int rop_alpha_sel
= 0;
131 int rop_alpha_code
= 0xCC;
136 int dst_pitch
= screen_width
* (m_iBpp
/ 8);
137 int dst_offset
= dst_y0
* dst_pitch
+ dst_x0
* (m_iBpp
/ 8);
138 int src_pitch
= screen_width
* (m_iBpp
/ 8);
139 int src_offset
= src_y0
* src_pitch
+ src_x0
* (m_iBpp
/ 8);
140 unsigned int command
= 0;
145 int bottom
= info
->var
.yres
- 1;
146 int right
= info
->var
.xres
- 1;
149 bottom
= (bottom
<< 16) | right
;
150 command
= (rop_alpha_sel
<< 26) | (pat_sel
<< 18) | (src_sel
<< 16)
151 | (x_dir
<< 20) | (y_dir
<< 21) | (command
<< 24)
152 | (clip_region
<< 23) | (clip_en
<< 22) | (tp_en
<< 27);
153 src_pitch
= (dst_pitch
<< 16) | src_pitch
;
154 awidth
= awidth
| (aheight
<< 16);
155 alpha_r
= ((rop_alpha_code
& 0xff) << 8) | (alpha_r
& 0xff)
157 src_x0
= (src_x0
& 0x1fff) | ((src_y0
& 0x1fff) << 16);
158 dst_x0
= (dst_x0
& 0x1fff) | ((dst_y0
& 0x1fff) << 16);
159 fg_color
= region
->color
;
163 writel(((u32
*)(info
->pseudo_palette
))[fg_color
], UGE_FCOLOR
);
164 writel(0, UGE_BCOLOR
);
165 writel(src_pitch
, UGE_PITCH
);
166 writel(src_offset
, UGE_SRCSTART
);
167 writel(dst_offset
, UGE_DSTSTART
);
168 writel(awidth
, UGE_WIDHEIGHT
);
169 writel(top
, UGE_CLIP0
);
170 writel(bottom
, UGE_CLIP1
);
171 writel(alpha_r
, UGE_ROPALPHA
);
172 writel(src_x0
, UGE_SRCXY
);
173 writel(dst_x0
, UGE_DSTXY
);
174 writel(command
, UGE_COMMAND
);
177 static void unifb_fillrect(struct fb_info
*info
,
178 const struct fb_fillrect
*region
)
180 struct fb_fillrect modded
;
183 if (info
->flags
& FBINFO_HWACCEL_DISABLED
) {
184 sys_fillrect(info
, region
);
188 vxres
= info
->var
.xres_virtual
;
189 vyres
= info
->var
.yres_virtual
;
191 memcpy(&modded
, region
, sizeof(struct fb_fillrect
));
193 if (!modded
.width
|| !modded
.height
||
194 modded
.dx
>= vxres
|| modded
.dy
>= vyres
)
197 if (modded
.dx
+ modded
.width
> vxres
)
198 modded
.width
= vxres
- modded
.dx
;
199 if (modded
.dy
+ modded
.height
> vyres
)
200 modded
.height
= vyres
- modded
.dy
;
202 unifb_prim_fillrect(info
, &modded
);
205 static void unifb_prim_copyarea(struct fb_info
*info
,
206 const struct fb_copyarea
*area
)
208 int awidth
= area
->width
;
209 int aheight
= area
->height
;
210 int m_iBpp
= info
->var
.bits_per_pixel
;
211 int screen_width
= info
->var
.xres
;
212 int src_sel
= 2; /* from mem */
214 int src_x0
= area
->sx
;
215 int dst_x0
= area
->dx
;
216 int src_y0
= area
->sy
;
217 int dst_y0
= area
->dy
;
219 int rop_alpha_sel
= 0;
220 int rop_alpha_code
= 0xCC;
226 int dst_pitch
= screen_width
* (m_iBpp
/ 8);
227 int dst_offset
= dst_y0
* dst_pitch
+ dst_x0
* (m_iBpp
/ 8);
228 int src_pitch
= screen_width
* (m_iBpp
/ 8);
229 int src_offset
= src_y0
* src_pitch
+ src_x0
* (m_iBpp
/ 8);
230 unsigned int command
= 0;
235 int bottom
= info
->var
.yres
;
236 int right
= info
->var
.xres
;
245 if (src_y0
- dst_y0
> 0) {
249 src_offset
= (src_y0
+ aheight
) * src_pitch
+
250 src_x0
* (m_iBpp
/ 8);
251 dst_offset
= (dst_y0
+ aheight
) * dst_pitch
+
252 dst_x0
* (m_iBpp
/ 8);
257 command
= (rop_alpha_sel
<< 26) | (pat_sel
<< 18) | (src_sel
<< 16) |
258 (x_dir
<< 20) | (y_dir
<< 21) | (command
<< 24) |
259 (clip_region
<< 23) | (clip_en
<< 22) | (tp_en
<< 27);
260 src_pitch
= (dst_pitch
<< 16) | src_pitch
;
261 awidth
= awidth
| (aheight
<< 16);
262 alpha_r
= ((rop_alpha_code
& 0xff) << 8) | (alpha_r
& 0xff) |
264 src_x0
= (src_x0
& 0x1fff) | ((src_y0
& 0x1fff) << 16);
265 dst_x0
= (dst_x0
& 0x1fff) | ((dst_y0
& 0x1fff) << 16);
266 bottom
= (bottom
<< 16) | right
;
270 writel(src_pitch
, UGE_PITCH
);
271 writel(src_offset
, UGE_SRCSTART
);
272 writel(dst_offset
, UGE_DSTSTART
);
273 writel(awidth
, UGE_WIDHEIGHT
);
274 writel(top
, UGE_CLIP0
);
275 writel(bottom
, UGE_CLIP1
);
276 writel(bg_color
, UGE_BCOLOR
);
277 writel(fg_color
, UGE_FCOLOR
);
278 writel(alpha_r
, UGE_ROPALPHA
);
279 writel(src_x0
, UGE_SRCXY
);
280 writel(dst_x0
, UGE_DSTXY
);
281 writel(command
, UGE_COMMAND
);
284 static void unifb_copyarea(struct fb_info
*info
, const struct fb_copyarea
*area
)
286 struct fb_copyarea modded
;
288 modded
.sx
= area
->sx
;
289 modded
.sy
= area
->sy
;
290 modded
.dx
= area
->dx
;
291 modded
.dy
= area
->dy
;
292 modded
.width
= area
->width
;
293 modded
.height
= area
->height
;
295 if (info
->flags
& FBINFO_HWACCEL_DISABLED
) {
296 sys_copyarea(info
, area
);
300 vxres
= info
->var
.xres_virtual
;
301 vyres
= info
->var
.yres_virtual
;
303 if (!modded
.width
|| !modded
.height
||
304 modded
.sx
>= vxres
|| modded
.sy
>= vyres
||
305 modded
.dx
>= vxres
|| modded
.dy
>= vyres
)
308 if (modded
.sx
+ modded
.width
> vxres
)
309 modded
.width
= vxres
- modded
.sx
;
310 if (modded
.dx
+ modded
.width
> vxres
)
311 modded
.width
= vxres
- modded
.dx
;
312 if (modded
.sy
+ modded
.height
> vyres
)
313 modded
.height
= vyres
- modded
.sy
;
314 if (modded
.dy
+ modded
.height
> vyres
)
315 modded
.height
= vyres
- modded
.dy
;
317 unifb_prim_copyarea(info
, &modded
);
320 static void unifb_imageblit(struct fb_info
*info
, const struct fb_image
*image
)
322 sys_imageblit(info
, image
);
325 static u_long
get_line_length(int xres_virtual
, int bpp
)
329 length
= xres_virtual
* bpp
;
330 length
= (length
+ 31) & ~31;
336 * Setting the video mode has been split into two parts.
337 * First part, xxxfb_check_var, must not write anything
338 * to hardware, it should only verify and adjust var.
339 * This means it doesn't alter par but it does use hardware
340 * data from it to check this var.
342 static int unifb_check_var(struct fb_var_screeninfo
*var
,
343 struct fb_info
*info
)
348 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
349 * as FB_VMODE_SMOOTH_XPAN is only used internally
352 if (var
->vmode
& FB_VMODE_CONUPDATE
) {
353 var
->vmode
|= FB_VMODE_YWRAP
;
354 var
->xoffset
= info
->var
.xoffset
;
355 var
->yoffset
= info
->var
.yoffset
;
359 * Some very basic checks
365 if (var
->xres
> var
->xres_virtual
)
366 var
->xres_virtual
= var
->xres
;
367 if (var
->yres
> var
->yres_virtual
)
368 var
->yres_virtual
= var
->yres
;
369 if (var
->bits_per_pixel
<= 1)
370 var
->bits_per_pixel
= 1;
371 else if (var
->bits_per_pixel
<= 8)
372 var
->bits_per_pixel
= 8;
373 else if (var
->bits_per_pixel
<= 16)
374 var
->bits_per_pixel
= 16;
375 else if (var
->bits_per_pixel
<= 24)
376 var
->bits_per_pixel
= 24;
377 else if (var
->bits_per_pixel
<= 32)
378 var
->bits_per_pixel
= 32;
382 if (var
->xres_virtual
< var
->xoffset
+ var
->xres
)
383 var
->xres_virtual
= var
->xoffset
+ var
->xres
;
384 if (var
->yres_virtual
< var
->yoffset
+ var
->yres
)
385 var
->yres_virtual
= var
->yoffset
+ var
->yres
;
391 get_line_length(var
->xres_virtual
, var
->bits_per_pixel
);
392 if (line_length
* var
->yres_virtual
> UNIFB_MEMSIZE
)
396 * Now that we checked it we alter var. The reason being is that the
397 * video mode passed in might not work but slight changes to it might
398 * make it work. This way we let the user know what is acceptable.
400 switch (var
->bits_per_pixel
) {
405 var
->green
.offset
= 0;
406 var
->green
.length
= 8;
407 var
->blue
.offset
= 0;
408 var
->blue
.length
= 8;
409 var
->transp
.offset
= 0;
410 var
->transp
.length
= 0;
412 case 16: /* RGBA 5551 */
413 if (var
->transp
.length
) {
416 var
->green
.offset
= 5;
417 var
->green
.length
= 5;
418 var
->blue
.offset
= 10;
419 var
->blue
.length
= 5;
420 var
->transp
.offset
= 15;
421 var
->transp
.length
= 1;
422 } else { /* RGB 565 */
423 var
->red
.offset
= 11;
425 var
->green
.offset
= 5;
426 var
->green
.length
= 6;
427 var
->blue
.offset
= 0;
428 var
->blue
.length
= 5;
429 var
->transp
.offset
= 0;
430 var
->transp
.length
= 0;
433 case 24: /* RGB 888 */
436 var
->green
.offset
= 8;
437 var
->green
.length
= 8;
438 var
->blue
.offset
= 16;
439 var
->blue
.length
= 8;
440 var
->transp
.offset
= 0;
441 var
->transp
.length
= 0;
443 case 32: /* RGBA 8888 */
444 var
->red
.offset
= 16;
446 var
->green
.offset
= 8;
447 var
->green
.length
= 8;
448 var
->blue
.offset
= 0;
449 var
->blue
.length
= 8;
450 var
->transp
.offset
= 24;
451 var
->transp
.length
= 8;
454 var
->red
.msb_right
= 0;
455 var
->green
.msb_right
= 0;
456 var
->blue
.msb_right
= 0;
457 var
->transp
.msb_right
= 0;
463 * This routine actually sets the video mode. It's in here where we
464 * the hardware state info->par and fix which can be affected by the
465 * change in par. For this driver it doesn't do much.
467 static int unifb_set_par(struct fb_info
*info
)
469 int hTotal
, vTotal
, hSyncStart
, hSyncEnd
, vSyncStart
, vSyncEnd
;
472 #ifdef CONFIG_PUV3_PM
477 for (i
= 0; i
<= 10; i
++) {
478 if (info
->var
.xres
== unifb_modes
[i
].xres
479 && info
->var
.yres
== unifb_modes
[i
].yres
480 && info
->var
.upper_margin
== unifb_modes
[i
].upper_margin
481 && info
->var
.lower_margin
== unifb_modes
[i
].lower_margin
482 && info
->var
.left_margin
== unifb_modes
[i
].left_margin
483 && info
->var
.right_margin
== unifb_modes
[i
].right_margin
484 && info
->var
.hsync_len
== unifb_modes
[i
].hsync_len
485 && info
->var
.vsync_len
== unifb_modes
[i
].vsync_len
) {
486 pixclk
= unifb_modes
[i
].pixclock
;
492 clk_vga
= clk_get(info
->device
, "VGA_CLK");
493 if (clk_vga
== ERR_PTR(-ENOENT
))
497 if (clk_set_rate(clk_vga
, pixclk
)) { /* set clock failed */
498 info
->fix
= unifb_fix
;
499 info
->var
= unifb_default
;
500 if (clk_set_rate(clk_vga
, unifb_default
.pixclock
))
506 info
->fix
.line_length
= get_line_length(info
->var
.xres_virtual
,
507 info
->var
.bits_per_pixel
);
509 hSyncStart
= info
->var
.xres
+ info
->var
.right_margin
;
510 hSyncEnd
= hSyncStart
+ info
->var
.hsync_len
;
511 hTotal
= hSyncEnd
+ info
->var
.left_margin
;
513 vSyncStart
= info
->var
.yres
+ info
->var
.lower_margin
;
514 vSyncEnd
= vSyncStart
+ info
->var
.vsync_len
;
515 vTotal
= vSyncEnd
+ info
->var
.upper_margin
;
517 switch (info
->var
.bits_per_pixel
) {
519 format
= UDE_CFG_DST8
;
522 format
= UDE_CFG_DST16
;
525 format
= UDE_CFG_DST24
;
528 format
= UDE_CFG_DST32
;
534 writel(PKUNITY_UNIGFX_MMAP_BASE
, UDE_FSA
);
535 writel(info
->var
.yres
, UDE_LS
);
536 writel(get_line_length(info
->var
.xres
,
537 info
->var
.bits_per_pixel
) >> 3, UDE_PS
);
538 /* >> 3 for hardware required. */
539 writel((hTotal
<< 16) | (info
->var
.xres
), UDE_HAT
);
540 writel(((hTotal
- 1) << 16) | (info
->var
.xres
- 1), UDE_HBT
);
541 writel(((hSyncEnd
- 1) << 16) | (hSyncStart
- 1), UDE_HST
);
542 writel((vTotal
<< 16) | (info
->var
.yres
), UDE_VAT
);
543 writel(((vTotal
- 1) << 16) | (info
->var
.yres
- 1), UDE_VBT
);
544 writel(((vSyncEnd
- 1) << 16) | (vSyncStart
- 1), UDE_VST
);
545 writel(UDE_CFG_GDEN_ENABLE
| UDE_CFG_TIMEUP_ENABLE
546 | format
| 0xC0000001, UDE_CFG
);
552 * Set a single color register. The values supplied are already
553 * rounded down to the hardware's capabilities (according to the
554 * entries in the var structure). Return != 0 for invalid regno.
556 static int unifb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
557 u_int transp
, struct fb_info
*info
)
559 if (regno
>= 256) /* no. of hw registers */
562 /* grayscale works only partially under directcolor */
563 if (info
->var
.grayscale
) {
564 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
566 (red
* 77 + green
* 151 + blue
* 28) >> 8;
569 #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
570 switch (info
->fix
.visual
) {
571 case FB_VISUAL_TRUECOLOR
:
572 case FB_VISUAL_PSEUDOCOLOR
:
573 red
= CNVT_TOHW(red
, info
->var
.red
.length
);
574 green
= CNVT_TOHW(green
, info
->var
.green
.length
);
575 blue
= CNVT_TOHW(blue
, info
->var
.blue
.length
);
576 transp
= CNVT_TOHW(transp
, info
->var
.transp
.length
);
578 case FB_VISUAL_DIRECTCOLOR
:
579 red
= CNVT_TOHW(red
, 8); /* expect 8 bit DAC */
580 green
= CNVT_TOHW(green
, 8);
581 blue
= CNVT_TOHW(blue
, 8);
582 /* hey, there is bug in transp handling... */
583 transp
= CNVT_TOHW(transp
, 8);
587 /* Truecolor has hardware independent palette */
588 if (info
->fix
.visual
== FB_VISUAL_TRUECOLOR
) {
594 v
= (red
<< info
->var
.red
.offset
) |
595 (green
<< info
->var
.green
.offset
) |
596 (blue
<< info
->var
.blue
.offset
) |
597 (transp
<< info
->var
.transp
.offset
);
598 switch (info
->var
.bits_per_pixel
) {
604 ((u32
*) (info
->pseudo_palette
))[regno
] = v
;
615 * Pan or Wrap the Display
617 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
619 static int unifb_pan_display(struct fb_var_screeninfo
*var
,
620 struct fb_info
*info
)
622 if (var
->vmode
& FB_VMODE_YWRAP
) {
624 || var
->yoffset
>= info
->var
.yres_virtual
628 if (var
->xoffset
+ var
->xres
> info
->var
.xres_virtual
||
629 var
->yoffset
+ var
->yres
> info
->var
.yres_virtual
)
632 info
->var
.xoffset
= var
->xoffset
;
633 info
->var
.yoffset
= var
->yoffset
;
634 if (var
->vmode
& FB_VMODE_YWRAP
)
635 info
->var
.vmode
|= FB_VMODE_YWRAP
;
637 info
->var
.vmode
&= ~FB_VMODE_YWRAP
;
641 int unifb_mmap(struct fb_info
*info
,
642 struct vm_area_struct
*vma
)
644 unsigned long size
= vma
->vm_end
- vma
->vm_start
;
645 unsigned long offset
= vma
->vm_pgoff
<< PAGE_SHIFT
;
646 unsigned long pos
= info
->fix
.smem_start
+ offset
;
648 if (offset
+ size
> info
->fix
.smem_len
)
651 vma
->vm_page_prot
= pgprot_noncached(vma
->vm_page_prot
);
653 if (io_remap_pfn_range(vma
, vma
->vm_start
, pos
>> PAGE_SHIFT
, size
,
657 vma
->vm_flags
|= VM_RESERVED
; /* avoid to swap out this VMA */
662 static struct fb_ops unifb_ops
= {
663 .fb_read
= fb_sys_read
,
664 .fb_write
= fb_sys_write
,
665 .fb_check_var
= unifb_check_var
,
666 .fb_set_par
= unifb_set_par
,
667 .fb_setcolreg
= unifb_setcolreg
,
668 .fb_pan_display
= unifb_pan_display
,
669 .fb_fillrect
= unifb_fillrect
,
670 .fb_copyarea
= unifb_copyarea
,
671 .fb_imageblit
= unifb_imageblit
,
672 .fb_mmap
= unifb_mmap
,
678 static int unifb_probe(struct platform_device
*dev
)
680 struct fb_info
*info
;
681 u32 unifb_regs
[UNIFB_REGS_NUM
];
682 int retval
= -ENOMEM
;
683 struct resource
*iomem
, *mapmem
;
685 info
= framebuffer_alloc(sizeof(u32
)*256, &dev
->dev
);
689 info
->screen_base
= (char __iomem
*)KUSER_UNIGFX_BASE
;
690 info
->fbops
= &unifb_ops
;
692 retval
= fb_find_mode(&info
->var
, info
, NULL
,
693 unifb_modes
, 10, &unifb_modes
[0], 16);
695 if (!retval
|| (retval
== 4))
696 info
->var
= unifb_default
;
698 iomem
= platform_get_resource(dev
, IORESOURCE_MEM
, 0);
699 unifb_fix
.mmio_start
= iomem
->start
;
701 mapmem
= platform_get_resource(dev
, IORESOURCE_MEM
, 1);
702 unifb_fix
.smem_start
= mapmem
->start
;
703 unifb_fix
.smem_len
= UNIFB_MEMSIZE
;
705 info
->fix
= unifb_fix
;
706 info
->pseudo_palette
= info
->par
;
708 info
->flags
= FBINFO_FLAG_DEFAULT
;
709 #ifdef FB_ACCEL_PUV3_UNIGFX
710 info
->fix
.accel
= FB_ACCEL_PUV3_UNIGFX
;
713 retval
= fb_alloc_cmap(&info
->cmap
, 256, 0);
717 retval
= register_framebuffer(info
);
720 platform_set_drvdata(dev
, info
);
721 platform_device_add_data(dev
, unifb_regs
, sizeof(u32
) * UNIFB_REGS_NUM
);
724 "fb%d: Virtual frame buffer device, using %dM of video memory\n",
725 info
->node
, UNIFB_MEMSIZE
>> 20);
728 fb_dealloc_cmap(&info
->cmap
);
730 framebuffer_release(info
);
735 static int unifb_remove(struct platform_device
*dev
)
737 struct fb_info
*info
= platform_get_drvdata(dev
);
740 unregister_framebuffer(info
);
741 fb_dealloc_cmap(&info
->cmap
);
742 framebuffer_release(info
);
748 static int unifb_resume(struct platform_device
*dev
)
751 u32
*unifb_regs
= dev
->dev
.platform_data
;
753 if (dev
->dev
.power
.power_state
.event
== PM_EVENT_ON
)
758 if (dev
->dev
.power
.power_state
.event
== PM_EVENT_SUSPEND
) {
759 writel(unifb_regs
[0], UDE_FSA
);
760 writel(unifb_regs
[1], UDE_LS
);
761 writel(unifb_regs
[2], UDE_PS
);
762 writel(unifb_regs
[3], UDE_HAT
);
763 writel(unifb_regs
[4], UDE_HBT
);
764 writel(unifb_regs
[5], UDE_HST
);
765 writel(unifb_regs
[6], UDE_VAT
);
766 writel(unifb_regs
[7], UDE_VBT
);
767 writel(unifb_regs
[8], UDE_VST
);
768 writel(unifb_regs
[9], UDE_CFG
);
770 dev
->dev
.power
.power_state
= PMSG_ON
;
777 static int unifb_suspend(struct platform_device
*dev
, pm_message_t mesg
)
779 u32
*unifb_regs
= dev
->dev
.platform_data
;
781 unifb_regs
[0] = readl(UDE_FSA
);
782 unifb_regs
[1] = readl(UDE_LS
);
783 unifb_regs
[2] = readl(UDE_PS
);
784 unifb_regs
[3] = readl(UDE_HAT
);
785 unifb_regs
[4] = readl(UDE_HBT
);
786 unifb_regs
[5] = readl(UDE_HST
);
787 unifb_regs
[6] = readl(UDE_VAT
);
788 unifb_regs
[7] = readl(UDE_VBT
);
789 unifb_regs
[8] = readl(UDE_VST
);
790 unifb_regs
[9] = readl(UDE_CFG
);
792 if (mesg
.event
== dev
->dev
.power
.power_state
.event
)
795 switch (mesg
.event
) {
796 case PM_EVENT_FREEZE
: /* about to take snapshot */
797 case PM_EVENT_PRETHAW
: /* before restoring snapshot */
808 dev
->dev
.power
.power_state
= mesg
;
813 #define unifb_resume NULL
814 #define unifb_suspend NULL
817 static struct platform_driver unifb_driver
= {
818 .probe
= unifb_probe
,
819 .remove
= unifb_remove
,
820 .resume
= unifb_resume
,
821 .suspend
= unifb_suspend
,
823 .name
= "PKUnity-v3-UNIGFX",
827 static int __init
unifb_init(void)
830 if (fb_get_options("unifb", NULL
))
834 return platform_driver_register(&unifb_driver
);
837 module_init(unifb_init
);
839 static void __exit
unifb_exit(void)
841 platform_driver_unregister(&unifb_driver
);
844 module_exit(unifb_exit
);
846 MODULE_LICENSE("GPL v2");