Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.19-rc6 481 lines 11 kB view raw
1/* 2 * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device 3 * 4 * (C) 1999 Mihai Spatar 5 * (C) 2000 YAEGASHI Takeshi 6 * (C) 2003, 2004 Paul Mundt 7 * (C) 2003, 2004, 2006 Andriy Skulysh 8 * 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 11 * more details. 12 */ 13 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> 19#include <linux/mm.h> 20#include <linux/slab.h> 21#include <linux/delay.h> 22#include <linux/init.h> 23#include <linux/platform_device.h> 24#include <linux/fb.h> 25 26#include <asm/machvec.h> 27#include <asm/uaccess.h> 28#include <asm/pgtable.h> 29#include <asm/io.h> 30#include <asm/hd64461.h> 31#include <asm/cpu/dac.h> 32 33#define WIDTH 640 34 35static struct fb_var_screeninfo hitfb_var __initdata = { 36 .activate = FB_ACTIVATE_NOW, 37 .height = -1, 38 .width = -1, 39 .vmode = FB_VMODE_NONINTERLACED, 40}; 41 42static struct fb_fix_screeninfo hitfb_fix __initdata = { 43 .id = "Hitachi HD64461", 44 .type = FB_TYPE_PACKED_PIXELS, 45 .accel = FB_ACCEL_NONE, 46}; 47 48static u32 pseudo_palette[16]; 49static struct fb_info fb_info; 50 51static inline void hitfb_accel_wait(void) 52{ 53 while (fb_readw(HD64461_GRCFGR) & HD64461_GRCFGR_ACCSTATUS) ; 54} 55 56static inline void hitfb_accel_start(int truecolor) 57{ 58 if (truecolor) { 59 fb_writew(6, HD64461_GRCFGR); 60 } else { 61 fb_writew(7, HD64461_GRCFGR); 62 } 63} 64 65static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy, 66 u16 width, u16 height) 67{ 68 u32 saddr = WIDTH * dy + dx; 69 if (truecolor) 70 saddr <<= 1; 71 72 fb_writew(width-1, HD64461_BBTDWR); 73 fb_writew(height-1, HD64461_BBTDHR); 74 75 fb_writew(saddr & 0xffff, HD64461_BBTDSARL); 76 fb_writew(saddr >> 16, HD64461_BBTDSARH); 77 78} 79 80static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx, 81 u16 dy, u16 width, u16 height, u16 rop, 82 u32 mask_addr) 83{ 84 u32 saddr, daddr; 85 u32 maddr = 0; 86 87 height--; 88 width--; 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; 93 if (mask_addr) { 94 if (truecolor) 95 maddr = ((width >> 3) + 1) * (height + 1) - 1; 96 else 97 maddr = 98 (((width >> 4) + 1) * (height + 1) - 1) * 2; 99 100 fb_writew((1 << 5) | 1, HD64461_BBTMDR); 101 } else 102 fb_writew(1, HD64461_BBTMDR); 103 } else { 104 saddr = WIDTH * sy + sx; 105 daddr = WIDTH * dy + dx; 106 if (mask_addr) { 107 fb_writew((1 << 5), HD64461_BBTMDR); 108 } else { 109 fb_writew(0, HD64461_BBTMDR); 110 } 111 } 112 if (truecolor) { 113 saddr <<= 1; 114 daddr <<= 1; 115 } 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); 122 if (mask_addr) { 123 maddr += mask_addr; 124 fb_writew(maddr & 0xffff, HD64461_BBTMARL); 125 fb_writew(maddr >> 16, HD64461_BBTMARH); 126 } 127 hitfb_accel_start(truecolor); 128} 129 130static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 131{ 132 if (rect->rop != ROP_COPY) 133 cfb_fillrect(p, rect); 134 else { 135 hitfb_accel_wait(); 136 fb_writew(0x00f0, HD64461_BBTROPR); 137 fb_writew(16, HD64461_BBTMDR); 138 139 if (p->var.bits_per_pixel == 16) { 140 fb_writew(((u32 *) (p->pseudo_palette))[rect->color], 141 HD64461_GRSCR); 142 hitfb_accel_set_dest(1, rect->dx, rect->dy, rect->width, 143 rect->height); 144 hitfb_accel_start(1); 145 } else { 146 fb_writew(rect->color, HD64461_GRSCR); 147 hitfb_accel_set_dest(0, rect->dx, rect->dy, rect->width, 148 rect->height); 149 hitfb_accel_start(0); 150 } 151 } 152} 153 154static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 155{ 156 hitfb_accel_wait(); 157 hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy, 158 area->dx, area->dy, area->width, area->height, 159 0x00cc, 0); 160} 161 162static int hitfb_pan_display(struct fb_var_screeninfo *var, 163 struct fb_info *info) 164{ 165 int xoffset = var->xoffset; 166 int yoffset = var->yoffset; 167 168 if (xoffset != 0) 169 return -EINVAL; 170 171 fb_writew((yoffset*info->fix.line_length)>>10, HD64461_LCDCBAR); 172 173 return 0; 174} 175 176int hitfb_blank(int blank_mode, struct fb_info *info) 177{ 178 unsigned short v; 179 180 if (blank_mode) { 181 v = fb_readw(HD64461_LDR1); 182 v &= ~HD64461_LDR1_DON; 183 fb_writew(v, HD64461_LDR1); 184 185 v = fb_readw(HD64461_LCDCCR); 186 v |= HD64461_LCDCCR_MOFF; 187 fb_writew(v, HD64461_LCDCCR); 188 189 v = fb_readw(HD64461_STBCR); 190 v |= HD64461_STBCR_SLCDST; 191 fb_writew(v, HD64461_STBCR); 192 } else { 193 v = fb_readw(HD64461_STBCR); 194 v &= ~HD64461_STBCR_SLCDST; 195 fb_writew(v, HD64461_STBCR); 196 197 v = fb_readw(HD64461_LCDCCR); 198 v &= ~(HD64461_LCDCCR_MOFF | HD64461_LCDCCR_STREQ); 199 fb_writew(v, HD64461_LCDCCR); 200 201 do { 202 v = fb_readw(HD64461_LCDCCR); 203 } while(v&HD64461_LCDCCR_STBACK); 204 205 v = fb_readw(HD64461_LDR1); 206 v |= HD64461_LDR1_DON; 207 fb_writew(v, HD64461_LDR1); 208 } 209 return 0; 210} 211 212static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, 213 unsigned blue, unsigned transp, struct fb_info *info) 214{ 215 if (regno >= 256) 216 return 1; 217 218 switch (info->var.bits_per_pixel) { 219 case 8: 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); 224 break; 225 case 16: 226 if (regno >= 16) 227 return 1; 228 ((u32 *) (info->pseudo_palette))[regno] = 229 ((red & 0xf800)) | 230 ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); 231 break; 232 } 233 return 0; 234} 235 236static int hitfb_sync(struct fb_info *info) 237{ 238 hitfb_accel_wait(); 239 240 return 0; 241} 242 243static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 244{ 245 int maxy; 246 247 var->xres = info->var.xres; 248 var->xres_virtual = info->var.xres; 249 var->yres = info->var.yres; 250 251 if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16)) 252 var->bits_per_pixel = info->var.bits_per_pixel; 253 254 if (var->yres_virtual < var->yres) 255 var->yres_virtual = var->yres; 256 257 maxy = info->fix.smem_len / var->xres; 258 259 if (var->bits_per_pixel == 16) 260 maxy /= 2; 261 262 if (var->yres_virtual > maxy) 263 var->yres_virtual = maxy; 264 265 var->xoffset = 0; 266 var->yoffset = 0; 267 268 switch (var->bits_per_pixel) { 269 case 8: 270 var->red.offset = 0; 271 var->red.length = 8; 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; 278 break; 279 case 16: /* RGB 565 */ 280 var->red.offset = 11; 281 var->red.length = 5; 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; 288 break; 289 } 290 291 return 0; 292} 293 294static int hitfb_set_par(struct fb_info *info) 295{ 296 unsigned short ldr3; 297 298 switch (info->var.bits_per_pixel) { 299 case 8: 300 info->fix.line_length = info->var.xres; 301 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 302 info->fix.ypanstep = 16; 303 break; 304 case 16: 305 info->fix.line_length = info->var.xres*2; 306 info->fix.visual = FB_VISUAL_TRUECOLOR; 307 info->fix.ypanstep = 8; 308 break; 309 } 310 311 fb_writew(info->fix.line_length, HD64461_LCDCLOR); 312 ldr3 = fb_readw(HD64461_LDR3); 313 ldr3 &= ~15; 314 ldr3 |= (info->var.bits_per_pixel == 8) ? 4 : 8; 315 fb_writew(ldr3, HD64461_LDR3); 316 return 0; 317} 318 319static 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, 330}; 331 332static int __init hitfb_probe(struct platform_device *dev) 333{ 334 unsigned short lcdclor, ldr3, ldvndr; 335 336 if (fb_get_options("hitfb", NULL)) 337 return -ENODEV; 338 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; 343 344 lcdclor = fb_readw(HD64461_LCDCLOR); 345 ldvndr = fb_readw(HD64461_LDVNDR); 346 ldr3 = fb_readw(HD64461_LDR3); 347 348 switch (ldr3 & 15) { 349 default: 350 case 4: 351 hitfb_var.bits_per_pixel = 8; 352 hitfb_var.xres = lcdclor; 353 break; 354 case 8: 355 hitfb_var.bits_per_pixel = 16; 356 hitfb_var.xres = lcdclor / 2; 357 break; 358 } 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) { 366 case 8: 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; 375 break; 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; 385 break; 386 } 387 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; 394 395 fb_info.screen_base = (void *)hitfb_fix.smem_start; 396 397 fb_alloc_cmap(&fb_info.cmap, 256, 0); 398 399 if (register_framebuffer(&fb_info) < 0) 400 return -EINVAL; 401 402 printk(KERN_INFO "fb%d: %s frame buffer device\n", 403 fb_info.node, fb_info.fix.id); 404 return 0; 405} 406 407static int __devexit hitfb_remove(struct platform_device *dev) 408{ 409 return unregister_framebuffer(&fb_info); 410} 411 412#ifdef CONFIG_PM 413static int hitfb_suspend(struct platform_device *dev, pm_message_t state) 414{ 415 u16 v; 416 417 hitfb_blank(1,0); 418 v = fb_readw(HD64461_STBCR); 419 v |= HD64461_STBCR_SLCKE_IST; 420 fb_writew(v, HD64461_STBCR); 421 422 return 0; 423} 424 425static int hitfb_resume(struct platform_device *dev) 426{ 427 u16 v; 428 429 v = fb_readw(HD64461_STBCR); 430 v &= ~HD64461_STBCR_SLCKE_OST; 431 msleep(100); 432 v = fb_readw(HD64461_STBCR); 433 v &= ~HD64461_STBCR_SLCKE_IST; 434 fb_writew(v, HD64461_STBCR); 435 hitfb_blank(0,0); 436 437 return 0; 438} 439#endif 440 441static struct platform_driver hitfb_driver = { 442 .probe = hitfb_probe, 443 .remove = __devexit_p(hitfb_remove), 444#ifdef CONFIG_PM 445 .suspend = hitfb_suspend, 446 .resume = hitfb_resume, 447#endif 448 .driver = { 449 .name = "hitfb", 450 }, 451}; 452 453static struct platform_device hitfb_device = { 454 .name = "hitfb", 455 .id = -1, 456}; 457 458static int __init hitfb_init(void) 459{ 460 int ret; 461 462 ret = platform_driver_register(&hitfb_driver); 463 if (!ret) { 464 ret = platform_device_register(&hitfb_device); 465 if (ret) 466 platform_driver_unregister(&hitfb_driver); 467 } 468 return ret; 469} 470 471 472static void __exit hitfb_exit(void) 473{ 474 platform_device_unregister(&hitfb_device); 475 platform_driver_unregister(&hitfb_driver); 476} 477 478module_init(hitfb_init); 479module_exit(hitfb_exit); 480 481MODULE_LICENSE("GPL");