2 * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device
4 * (C) 1999 Mihai Spatar
5 * (C) 2000 YAEGASHI Takeshi
6 * (C) 2003, 2004 Paul Mundt
7 * (C) 2003, 2004, 2006 Andriy Skulysh
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
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/sched.h>
17 #include <linux/errno.h>
18 #include <linux/string.h>
20 #include <linux/slab.h>
21 #include <linux/delay.h>
22 #include <linux/init.h>
23 #include <linux/platform_device.h>
26 #include <asm/machvec.h>
27 #include <asm/uaccess.h>
28 #include <asm/pgtable.h>
30 #include <asm/hd64461.h>
31 #include <asm/cpu/dac.h>
35 static struct fb_var_screeninfo hitfb_var __initdata
= {
36 .activate
= FB_ACTIVATE_NOW
,
39 .vmode
= FB_VMODE_NONINTERLACED
,
42 static struct fb_fix_screeninfo hitfb_fix __initdata
= {
43 .id
= "Hitachi HD64461",
44 .type
= FB_TYPE_PACKED_PIXELS
,
45 .accel
= FB_ACCEL_NONE
,
48 static u32 pseudo_palette
[16];
49 static struct fb_info fb_info
;
51 static inline void hitfb_accel_wait(void)
53 while (fb_readw(HD64461_GRCFGR
) & HD64461_GRCFGR_ACCSTATUS
) ;
56 static inline void hitfb_accel_start(int truecolor
)
59 fb_writew(6, HD64461_GRCFGR
);
61 fb_writew(7, HD64461_GRCFGR
);
65 static inline void hitfb_accel_set_dest(int truecolor
, u16 dx
, u16 dy
,
66 u16 width
, u16 height
)
68 u32 saddr
= WIDTH
* dy
+ dx
;
72 fb_writew(width
-1, HD64461_BBTDWR
);
73 fb_writew(height
-1, HD64461_BBTDHR
);
75 fb_writew(saddr
& 0xffff, HD64461_BBTDSARL
);
76 fb_writew(saddr
>> 16, HD64461_BBTDSARH
);
80 static inline void hitfb_accel_bitblt(int truecolor
, u16 sx
, u16 sy
, u16 dx
,
81 u16 dy
, u16 width
, u16 height
, u16 rop
,
89 fb_writew(rop
, HD64461_BBTROPR
);
90 if ((sy
< dy
) || ((sy
== dy
) && (sx
<= dx
))) {
91 saddr
= WIDTH
* (sy
+ height
) + sx
+ width
;
92 daddr
= WIDTH
* (dy
+ height
) + dx
+ width
;
95 maddr
= ((width
>> 3) + 1) * (height
+ 1) - 1;
98 (((width
>> 4) + 1) * (height
+ 1) - 1) * 2;
100 fb_writew((1 << 5) | 1, HD64461_BBTMDR
);
102 fb_writew(1, HD64461_BBTMDR
);
104 saddr
= WIDTH
* sy
+ sx
;
105 daddr
= WIDTH
* dy
+ dx
;
107 fb_writew((1 << 5), HD64461_BBTMDR
);
109 fb_writew(0, HD64461_BBTMDR
);
116 fb_writew(width
, HD64461_BBTDWR
);
117 fb_writew(height
, HD64461_BBTDHR
);
118 fb_writew(saddr
& 0xffff, HD64461_BBTSSARL
);
119 fb_writew(saddr
>> 16, HD64461_BBTSSARH
);
120 fb_writew(daddr
& 0xffff, HD64461_BBTDSARL
);
121 fb_writew(daddr
>> 16, HD64461_BBTDSARH
);
124 fb_writew(maddr
& 0xffff, HD64461_BBTMARL
);
125 fb_writew(maddr
>> 16, HD64461_BBTMARH
);
127 hitfb_accel_start(truecolor
);
130 static void hitfb_fillrect(struct fb_info
*p
, const struct fb_fillrect
*rect
)
132 if (rect
->rop
!= ROP_COPY
)
133 cfb_fillrect(p
, rect
);
136 fb_writew(0x00f0, HD64461_BBTROPR
);
137 fb_writew(16, HD64461_BBTMDR
);
139 if (p
->var
.bits_per_pixel
== 16) {
140 fb_writew(((u32
*) (p
->pseudo_palette
))[rect
->color
],
142 hitfb_accel_set_dest(1, rect
->dx
, rect
->dy
, rect
->width
,
144 hitfb_accel_start(1);
146 fb_writew(rect
->color
, HD64461_GRSCR
);
147 hitfb_accel_set_dest(0, rect
->dx
, rect
->dy
, rect
->width
,
149 hitfb_accel_start(0);
154 static void hitfb_copyarea(struct fb_info
*p
, const struct fb_copyarea
*area
)
157 hitfb_accel_bitblt(p
->var
.bits_per_pixel
== 16, area
->sx
, area
->sy
,
158 area
->dx
, area
->dy
, area
->width
, area
->height
,
162 static int hitfb_pan_display(struct fb_var_screeninfo
*var
,
163 struct fb_info
*info
)
165 int xoffset
= var
->xoffset
;
166 int yoffset
= var
->yoffset
;
171 fb_writew((yoffset
*info
->fix
.line_length
)>>10, HD64461_LCDCBAR
);
176 int hitfb_blank(int blank_mode
, struct fb_info
*info
)
181 v
= fb_readw(HD64461_LDR1
);
182 v
&= ~HD64461_LDR1_DON
;
183 fb_writew(v
, HD64461_LDR1
);
185 v
= fb_readw(HD64461_LCDCCR
);
186 v
|= HD64461_LCDCCR_MOFF
;
187 fb_writew(v
, HD64461_LCDCCR
);
189 v
= fb_readw(HD64461_STBCR
);
190 v
|= HD64461_STBCR_SLCDST
;
191 fb_writew(v
, HD64461_STBCR
);
193 v
= fb_readw(HD64461_STBCR
);
194 v
&= ~HD64461_STBCR_SLCDST
;
195 fb_writew(v
, HD64461_STBCR
);
197 v
= fb_readw(HD64461_LCDCCR
);
198 v
&= ~(HD64461_LCDCCR_MOFF
| HD64461_LCDCCR_STREQ
);
199 fb_writew(v
, HD64461_LCDCCR
);
202 v
= fb_readw(HD64461_LCDCCR
);
203 } while(v
&HD64461_LCDCCR_STBACK
);
205 v
= fb_readw(HD64461_LDR1
);
206 v
|= HD64461_LDR1_DON
;
207 fb_writew(v
, HD64461_LDR1
);
212 static int hitfb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
213 unsigned blue
, unsigned transp
, struct fb_info
*info
)
218 switch (info
->var
.bits_per_pixel
) {
220 fb_writew(regno
<< 8, HD64461_CPTWAR
);
221 fb_writew(red
>> 10, HD64461_CPTWDR
);
222 fb_writew(green
>> 10, HD64461_CPTWDR
);
223 fb_writew(blue
>> 10, HD64461_CPTWDR
);
228 ((u32
*) (info
->pseudo_palette
))[regno
] =
230 ((green
& 0xfc00) >> 5) | ((blue
& 0xf800) >> 11);
236 static int hitfb_sync(struct fb_info
*info
)
243 static int hitfb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
247 var
->xres
= info
->var
.xres
;
248 var
->xres_virtual
= info
->var
.xres
;
249 var
->yres
= info
->var
.yres
;
251 if ((var
->bits_per_pixel
!= 8) && (var
->bits_per_pixel
!= 16))
252 var
->bits_per_pixel
= info
->var
.bits_per_pixel
;
254 if (var
->yres_virtual
< var
->yres
)
255 var
->yres_virtual
= var
->yres
;
257 maxy
= info
->fix
.smem_len
/ var
->xres
;
259 if (var
->bits_per_pixel
== 16)
262 if (var
->yres_virtual
> maxy
)
263 var
->yres_virtual
= maxy
;
268 switch (var
->bits_per_pixel
) {
272 var
->green
.offset
= 0;
273 var
->green
.length
= 8;
274 var
->blue
.offset
= 0;
275 var
->blue
.length
= 8;
276 var
->transp
.offset
= 0;
277 var
->transp
.length
= 0;
279 case 16: /* RGB 565 */
280 var
->red
.offset
= 11;
282 var
->green
.offset
= 5;
283 var
->green
.length
= 6;
284 var
->blue
.offset
= 0;
285 var
->blue
.length
= 5;
286 var
->transp
.offset
= 0;
287 var
->transp
.length
= 0;
294 static int hitfb_set_par(struct fb_info
*info
)
298 switch (info
->var
.bits_per_pixel
) {
300 info
->fix
.line_length
= info
->var
.xres
;
301 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
302 info
->fix
.ypanstep
= 16;
305 info
->fix
.line_length
= info
->var
.xres
*2;
306 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
307 info
->fix
.ypanstep
= 8;
311 fb_writew(info
->fix
.line_length
, HD64461_LCDCLOR
);
312 ldr3
= fb_readw(HD64461_LDR3
);
314 ldr3
|= (info
->var
.bits_per_pixel
== 8) ? 4 : 8;
315 fb_writew(ldr3
, HD64461_LDR3
);
319 static struct fb_ops hitfb_ops
= {
320 .owner
= THIS_MODULE
,
321 .fb_check_var
= hitfb_check_var
,
322 .fb_set_par
= hitfb_set_par
,
323 .fb_setcolreg
= hitfb_setcolreg
,
324 .fb_blank
= hitfb_blank
,
325 .fb_sync
= hitfb_sync
,
326 .fb_pan_display
= hitfb_pan_display
,
327 .fb_fillrect
= hitfb_fillrect
,
328 .fb_copyarea
= hitfb_copyarea
,
329 .fb_imageblit
= cfb_imageblit
,
332 static int __init
hitfb_probe(struct platform_device
*dev
)
334 unsigned short lcdclor
, ldr3
, ldvndr
;
336 if (fb_get_options("hitfb", NULL
))
339 hitfb_fix
.mmio_start
= CONFIG_HD64461_IOBASE
+0x1000;
340 hitfb_fix
.mmio_len
= 0x1000;
341 hitfb_fix
.smem_start
= CONFIG_HD64461_IOBASE
+ 0x02000000;
342 hitfb_fix
.smem_len
= 512 * 1024;
344 lcdclor
= fb_readw(HD64461_LCDCLOR
);
345 ldvndr
= fb_readw(HD64461_LDVNDR
);
346 ldr3
= fb_readw(HD64461_LDR3
);
351 hitfb_var
.bits_per_pixel
= 8;
352 hitfb_var
.xres
= lcdclor
;
355 hitfb_var
.bits_per_pixel
= 16;
356 hitfb_var
.xres
= lcdclor
/ 2;
359 hitfb_fix
.line_length
= lcdclor
;
360 hitfb_fix
.visual
= (hitfb_var
.bits_per_pixel
== 8) ?
361 FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_TRUECOLOR
;
362 hitfb_var
.yres
= ldvndr
+ 1;
363 hitfb_var
.xres_virtual
= hitfb_var
.xres
;
364 hitfb_var
.yres_virtual
= hitfb_fix
.smem_len
/ lcdclor
;
365 switch (hitfb_var
.bits_per_pixel
) {
367 hitfb_var
.red
.offset
= 0;
368 hitfb_var
.red
.length
= 8;
369 hitfb_var
.green
.offset
= 0;
370 hitfb_var
.green
.length
= 8;
371 hitfb_var
.blue
.offset
= 0;
372 hitfb_var
.blue
.length
= 8;
373 hitfb_var
.transp
.offset
= 0;
374 hitfb_var
.transp
.length
= 0;
376 case 16: /* RGB 565 */
377 hitfb_var
.red
.offset
= 11;
378 hitfb_var
.red
.length
= 5;
379 hitfb_var
.green
.offset
= 5;
380 hitfb_var
.green
.length
= 6;
381 hitfb_var
.blue
.offset
= 0;
382 hitfb_var
.blue
.length
= 5;
383 hitfb_var
.transp
.offset
= 0;
384 hitfb_var
.transp
.length
= 0;
388 fb_info
.fbops
= &hitfb_ops
;
389 fb_info
.var
= hitfb_var
;
390 fb_info
.fix
= hitfb_fix
;
391 fb_info
.pseudo_palette
= pseudo_palette
;
392 fb_info
.flags
= FBINFO_DEFAULT
| FBINFO_HWACCEL_YPAN
|
393 FBINFO_HWACCEL_FILLRECT
| FBINFO_HWACCEL_COPYAREA
;
395 fb_info
.screen_base
= (void *)hitfb_fix
.smem_start
;
397 fb_alloc_cmap(&fb_info
.cmap
, 256, 0);
399 if (register_framebuffer(&fb_info
) < 0)
402 printk(KERN_INFO
"fb%d: %s frame buffer device\n",
403 fb_info
.node
, fb_info
.fix
.id
);
407 static int __devexit
hitfb_remove(struct platform_device
*dev
)
409 return unregister_framebuffer(&fb_info
);
413 static int hitfb_suspend(struct platform_device
*dev
, pm_message_t state
)
418 v
= fb_readw(HD64461_STBCR
);
419 v
|= HD64461_STBCR_SLCKE_IST
;
420 fb_writew(v
, HD64461_STBCR
);
425 static int hitfb_resume(struct platform_device
*dev
)
429 v
= fb_readw(HD64461_STBCR
);
430 v
&= ~HD64461_STBCR_SLCKE_OST
;
432 v
= fb_readw(HD64461_STBCR
);
433 v
&= ~HD64461_STBCR_SLCKE_IST
;
434 fb_writew(v
, HD64461_STBCR
);
441 static struct platform_driver hitfb_driver
= {
442 .probe
= hitfb_probe
,
443 .remove
= __devexit_p(hitfb_remove
),
445 .suspend
= hitfb_suspend
,
446 .resume
= hitfb_resume
,
453 static struct platform_device hitfb_device
= {
458 static int __init
hitfb_init(void)
462 ret
= platform_driver_register(&hitfb_driver
);
464 ret
= platform_device_register(&hitfb_device
);
466 platform_driver_unregister(&hitfb_driver
);
472 static void __exit
hitfb_exit(void)
474 platform_device_unregister(&hitfb_device
);
475 platform_driver_unregister(&hitfb_driver
);
478 module_init(hitfb_init
);
479 module_exit(hitfb_exit
);
481 MODULE_LICENSE("GPL");