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/errno.h>
17 #include <linux/string.h>
19 #include <linux/delay.h>
20 #include <linux/init.h>
21 #include <linux/platform_device.h>
24 #include <asm/machvec.h>
25 #include <linux/uaccess.h>
27 #include <asm/hd64461.h>
32 static struct fb_var_screeninfo hitfb_var
= {
33 .activate
= FB_ACTIVATE_NOW
,
36 .vmode
= FB_VMODE_NONINTERLACED
,
39 static struct fb_fix_screeninfo hitfb_fix
= {
40 .id
= "Hitachi HD64461",
41 .type
= FB_TYPE_PACKED_PIXELS
,
42 .accel
= FB_ACCEL_NONE
,
45 static volatile void __iomem
*hitfb_offset_to_addr(unsigned int offset
)
47 return (__force
volatile void __iomem
*)(uintptr_t)offset
;
50 static u16
hitfb_readw(unsigned int offset
)
52 return fb_readw(hitfb_offset_to_addr(offset
));
55 static void hitfb_writew(u16 value
, unsigned int offset
)
57 fb_writew(value
, hitfb_offset_to_addr(offset
));
60 static inline void hitfb_accel_wait(void)
62 while (hitfb_readw(HD64461_GRCFGR
) & HD64461_GRCFGR_ACCSTATUS
)
66 static inline void hitfb_accel_start(int truecolor
)
69 hitfb_writew(6, HD64461_GRCFGR
);
71 hitfb_writew(7, HD64461_GRCFGR
);
75 static inline void hitfb_accel_set_dest(int truecolor
, u16 dx
, u16 dy
,
76 u16 width
, u16 height
)
78 u32 saddr
= WIDTH
* dy
+ dx
;
82 hitfb_writew(width
-1, HD64461_BBTDWR
);
83 hitfb_writew(height
-1, HD64461_BBTDHR
);
85 hitfb_writew(saddr
& 0xffff, HD64461_BBTDSARL
);
86 hitfb_writew(saddr
>> 16, HD64461_BBTDSARH
);
90 static inline void hitfb_accel_bitblt(int truecolor
, u16 sx
, u16 sy
, u16 dx
,
91 u16 dy
, u16 width
, u16 height
, u16 rop
,
99 hitfb_writew(rop
, HD64461_BBTROPR
);
100 if ((sy
< dy
) || ((sy
== dy
) && (sx
<= dx
))) {
101 saddr
= WIDTH
* (sy
+ height
) + sx
+ width
;
102 daddr
= WIDTH
* (dy
+ height
) + dx
+ width
;
105 maddr
= ((width
>> 3) + 1) * (height
+ 1) - 1;
108 (((width
>> 4) + 1) * (height
+ 1) - 1) * 2;
110 hitfb_writew((1 << 5) | 1, HD64461_BBTMDR
);
112 hitfb_writew(1, HD64461_BBTMDR
);
114 saddr
= WIDTH
* sy
+ sx
;
115 daddr
= WIDTH
* dy
+ dx
;
117 hitfb_writew((1 << 5), HD64461_BBTMDR
);
119 hitfb_writew(0, HD64461_BBTMDR
);
126 hitfb_writew(width
, HD64461_BBTDWR
);
127 hitfb_writew(height
, HD64461_BBTDHR
);
128 hitfb_writew(saddr
& 0xffff, HD64461_BBTSSARL
);
129 hitfb_writew(saddr
>> 16, HD64461_BBTSSARH
);
130 hitfb_writew(daddr
& 0xffff, HD64461_BBTDSARL
);
131 hitfb_writew(daddr
>> 16, HD64461_BBTDSARH
);
134 hitfb_writew(maddr
& 0xffff, HD64461_BBTMARL
);
135 hitfb_writew(maddr
>> 16, HD64461_BBTMARH
);
137 hitfb_accel_start(truecolor
);
140 static void hitfb_fillrect(struct fb_info
*p
, const struct fb_fillrect
*rect
)
142 if (rect
->rop
!= ROP_COPY
)
143 cfb_fillrect(p
, rect
);
146 hitfb_writew(0x00f0, HD64461_BBTROPR
);
147 hitfb_writew(16, HD64461_BBTMDR
);
149 if (p
->var
.bits_per_pixel
== 16) {
150 hitfb_writew(((u32
*) (p
->pseudo_palette
))[rect
->color
],
152 hitfb_accel_set_dest(1, rect
->dx
, rect
->dy
, rect
->width
,
154 hitfb_accel_start(1);
156 hitfb_writew(rect
->color
, HD64461_GRSCR
);
157 hitfb_accel_set_dest(0, rect
->dx
, rect
->dy
, rect
->width
,
159 hitfb_accel_start(0);
164 static void hitfb_copyarea(struct fb_info
*p
, const struct fb_copyarea
*area
)
167 hitfb_accel_bitblt(p
->var
.bits_per_pixel
== 16, area
->sx
, area
->sy
,
168 area
->dx
, area
->dy
, area
->width
, area
->height
,
172 static int hitfb_pan_display(struct fb_var_screeninfo
*var
,
173 struct fb_info
*info
)
175 int xoffset
= var
->xoffset
;
176 int yoffset
= var
->yoffset
;
181 hitfb_writew((yoffset
*info
->fix
.line_length
)>>10, HD64461_LCDCBAR
);
186 static int hitfb_blank(int blank_mode
, struct fb_info
*info
)
191 v
= hitfb_readw(HD64461_LDR1
);
192 v
&= ~HD64461_LDR1_DON
;
193 hitfb_writew(v
, HD64461_LDR1
);
195 v
= hitfb_readw(HD64461_LCDCCR
);
196 v
|= HD64461_LCDCCR_MOFF
;
197 hitfb_writew(v
, HD64461_LCDCCR
);
199 v
= hitfb_readw(HD64461_STBCR
);
200 v
|= HD64461_STBCR_SLCDST
;
201 hitfb_writew(v
, HD64461_STBCR
);
203 v
= hitfb_readw(HD64461_STBCR
);
204 v
&= ~HD64461_STBCR_SLCDST
;
205 hitfb_writew(v
, HD64461_STBCR
);
207 v
= hitfb_readw(HD64461_LCDCCR
);
208 v
&= ~(HD64461_LCDCCR_MOFF
| HD64461_LCDCCR_STREQ
);
209 hitfb_writew(v
, HD64461_LCDCCR
);
212 v
= hitfb_readw(HD64461_LCDCCR
);
213 } while(v
&HD64461_LCDCCR_STBACK
);
215 v
= hitfb_readw(HD64461_LDR1
);
216 v
|= HD64461_LDR1_DON
;
217 hitfb_writew(v
, HD64461_LDR1
);
222 static int hitfb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
223 unsigned blue
, unsigned transp
, struct fb_info
*info
)
228 switch (info
->var
.bits_per_pixel
) {
230 hitfb_writew(regno
<< 8, HD64461_CPTWAR
);
231 hitfb_writew(red
>> 10, HD64461_CPTWDR
);
232 hitfb_writew(green
>> 10, HD64461_CPTWDR
);
233 hitfb_writew(blue
>> 10, HD64461_CPTWDR
);
238 ((u32
*) (info
->pseudo_palette
))[regno
] =
240 ((green
& 0xfc00) >> 5) | ((blue
& 0xf800) >> 11);
246 static int hitfb_sync(struct fb_info
*info
)
253 static int hitfb_check_var(struct fb_var_screeninfo
*var
, struct fb_info
*info
)
257 var
->xres
= info
->var
.xres
;
258 var
->xres_virtual
= info
->var
.xres
;
259 var
->yres
= info
->var
.yres
;
261 if ((var
->bits_per_pixel
!= 8) && (var
->bits_per_pixel
!= 16))
262 var
->bits_per_pixel
= info
->var
.bits_per_pixel
;
264 if (var
->yres_virtual
< var
->yres
)
265 var
->yres_virtual
= var
->yres
;
267 maxy
= info
->fix
.smem_len
/ var
->xres
;
269 if (var
->bits_per_pixel
== 16)
272 if (var
->yres_virtual
> maxy
)
273 var
->yres_virtual
= maxy
;
278 switch (var
->bits_per_pixel
) {
282 var
->green
.offset
= 0;
283 var
->green
.length
= 8;
284 var
->blue
.offset
= 0;
285 var
->blue
.length
= 8;
286 var
->transp
.offset
= 0;
287 var
->transp
.length
= 0;
289 case 16: /* RGB 565 */
290 var
->red
.offset
= 11;
292 var
->green
.offset
= 5;
293 var
->green
.length
= 6;
294 var
->blue
.offset
= 0;
295 var
->blue
.length
= 5;
296 var
->transp
.offset
= 0;
297 var
->transp
.length
= 0;
304 static int hitfb_set_par(struct fb_info
*info
)
308 switch (info
->var
.bits_per_pixel
) {
310 info
->fix
.line_length
= info
->var
.xres
;
311 info
->fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
312 info
->fix
.ypanstep
= 16;
315 info
->fix
.line_length
= info
->var
.xres
*2;
316 info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
317 info
->fix
.ypanstep
= 8;
321 hitfb_writew(info
->fix
.line_length
, HD64461_LCDCLOR
);
322 ldr3
= hitfb_readw(HD64461_LDR3
);
324 ldr3
|= (info
->var
.bits_per_pixel
== 8) ? 4 : 8;
325 hitfb_writew(ldr3
, HD64461_LDR3
);
329 static const struct fb_ops hitfb_ops
= {
330 .owner
= THIS_MODULE
,
331 __FB_DEFAULT_IOMEM_OPS_RDWR
,
332 .fb_check_var
= hitfb_check_var
,
333 .fb_set_par
= hitfb_set_par
,
334 .fb_setcolreg
= hitfb_setcolreg
,
335 .fb_blank
= hitfb_blank
,
336 .fb_sync
= hitfb_sync
,
337 .fb_pan_display
= hitfb_pan_display
,
338 .fb_fillrect
= hitfb_fillrect
,
339 .fb_copyarea
= hitfb_copyarea
,
340 .fb_imageblit
= cfb_imageblit
,
341 __FB_DEFAULT_IOMEM_OPS_MMAP
,
344 static int hitfb_probe(struct platform_device
*dev
)
346 unsigned short lcdclor
, ldr3
, ldvndr
;
347 struct fb_info
*info
;
350 if (fb_get_options("hitfb", NULL
))
353 hitfb_fix
.mmio_start
= HD64461_IO_OFFSET(0x1000);
354 hitfb_fix
.mmio_len
= 0x1000;
355 hitfb_fix
.smem_start
= HD64461_IO_OFFSET(0x02000000);
356 hitfb_fix
.smem_len
= 512 * 1024;
358 lcdclor
= hitfb_readw(HD64461_LCDCLOR
);
359 ldvndr
= hitfb_readw(HD64461_LDVNDR
);
360 ldr3
= hitfb_readw(HD64461_LDR3
);
365 hitfb_var
.bits_per_pixel
= 8;
366 hitfb_var
.xres
= lcdclor
;
369 hitfb_var
.bits_per_pixel
= 16;
370 hitfb_var
.xres
= lcdclor
/ 2;
373 hitfb_fix
.line_length
= lcdclor
;
374 hitfb_fix
.visual
= (hitfb_var
.bits_per_pixel
== 8) ?
375 FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_TRUECOLOR
;
376 hitfb_var
.yres
= ldvndr
+ 1;
377 hitfb_var
.xres_virtual
= hitfb_var
.xres
;
378 hitfb_var
.yres_virtual
= hitfb_fix
.smem_len
/ lcdclor
;
379 switch (hitfb_var
.bits_per_pixel
) {
381 hitfb_var
.red
.offset
= 0;
382 hitfb_var
.red
.length
= 8;
383 hitfb_var
.green
.offset
= 0;
384 hitfb_var
.green
.length
= 8;
385 hitfb_var
.blue
.offset
= 0;
386 hitfb_var
.blue
.length
= 8;
387 hitfb_var
.transp
.offset
= 0;
388 hitfb_var
.transp
.length
= 0;
390 case 16: /* RGB 565 */
391 hitfb_var
.red
.offset
= 11;
392 hitfb_var
.red
.length
= 5;
393 hitfb_var
.green
.offset
= 5;
394 hitfb_var
.green
.length
= 6;
395 hitfb_var
.blue
.offset
= 0;
396 hitfb_var
.blue
.length
= 5;
397 hitfb_var
.transp
.offset
= 0;
398 hitfb_var
.transp
.length
= 0;
402 info
= framebuffer_alloc(sizeof(u32
) * 16, &dev
->dev
);
406 info
->fbops
= &hitfb_ops
;
407 info
->var
= hitfb_var
;
408 info
->fix
= hitfb_fix
;
409 info
->pseudo_palette
= info
->par
;
410 info
->flags
= FBINFO_HWACCEL_YPAN
|
411 FBINFO_HWACCEL_FILLRECT
| FBINFO_HWACCEL_COPYAREA
;
413 info
->screen_base
= (char __iomem
*)(uintptr_t)hitfb_fix
.smem_start
;
415 ret
= fb_alloc_cmap(&info
->cmap
, 256, 0);
416 if (unlikely(ret
< 0))
419 ret
= register_framebuffer(info
);
420 if (unlikely(ret
< 0))
423 platform_set_drvdata(dev
, info
);
425 fb_info(info
, "%s frame buffer device\n", info
->fix
.id
);
430 fb_dealloc_cmap(&info
->cmap
);
432 framebuffer_release(info
);
436 static void hitfb_remove(struct platform_device
*dev
)
438 struct fb_info
*info
= platform_get_drvdata(dev
);
440 unregister_framebuffer(info
);
441 fb_dealloc_cmap(&info
->cmap
);
442 framebuffer_release(info
);
445 static int hitfb_suspend(struct device
*dev
)
449 hitfb_blank(1, NULL
);
450 v
= hitfb_readw(HD64461_STBCR
);
451 v
|= HD64461_STBCR_SLCKE_IST
;
452 hitfb_writew(v
, HD64461_STBCR
);
457 static int hitfb_resume(struct device
*dev
)
461 v
= hitfb_readw(HD64461_STBCR
);
462 v
&= ~HD64461_STBCR_SLCKE_OST
;
464 v
= hitfb_readw(HD64461_STBCR
);
465 v
&= ~HD64461_STBCR_SLCKE_IST
;
466 hitfb_writew(v
, HD64461_STBCR
);
467 hitfb_blank(0, NULL
);
472 static const struct dev_pm_ops hitfb_dev_pm_ops
= {
473 .suspend
= hitfb_suspend
,
474 .resume
= hitfb_resume
,
477 static struct platform_driver hitfb_driver
= {
478 .probe
= hitfb_probe
,
479 .remove
= hitfb_remove
,
482 .pm
= &hitfb_dev_pm_ops
,
486 static struct platform_device hitfb_device
= {
491 static int __init
hitfb_init(void)
495 ret
= platform_driver_register(&hitfb_driver
);
497 ret
= platform_device_register(&hitfb_device
);
499 platform_driver_unregister(&hitfb_driver
);
505 static void __exit
hitfb_exit(void)
507 platform_device_unregister(&hitfb_device
);
508 platform_driver_unregister(&hitfb_driver
);
511 module_init(hitfb_init
);
512 module_exit(hitfb_exit
);
514 MODULE_LICENSE("GPL");