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.15-rc7 517 lines 12 kB view raw
1/* tcx.c: TCX frame buffer driver 2 * 3 * Copyright (C) 2003 David S. Miller (davem@redhat.com) 4 * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) 5 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) 6 * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) 7 * 8 * Driver layout based loosely on tgafb.c, see that file for credits. 9 */ 10 11#include <linux/module.h> 12#include <linux/kernel.h> 13#include <linux/errno.h> 14#include <linux/string.h> 15#include <linux/slab.h> 16#include <linux/delay.h> 17#include <linux/init.h> 18#include <linux/fb.h> 19#include <linux/mm.h> 20 21#include <asm/io.h> 22#include <asm/sbus.h> 23#include <asm/oplib.h> 24#include <asm/fbio.h> 25 26#include "sbuslib.h" 27 28/* 29 * Local functions. 30 */ 31 32static int tcx_setcolreg(unsigned, unsigned, unsigned, unsigned, 33 unsigned, struct fb_info *); 34static int tcx_blank(int, struct fb_info *); 35 36static int tcx_mmap(struct fb_info *, struct file *, struct vm_area_struct *); 37static int tcx_ioctl(struct inode *, struct file *, unsigned int, 38 unsigned long, struct fb_info *); 39static int tcx_pan_display(struct fb_var_screeninfo *, struct fb_info *); 40 41/* 42 * Frame buffer operations 43 */ 44 45static struct fb_ops tcx_ops = { 46 .owner = THIS_MODULE, 47 .fb_setcolreg = tcx_setcolreg, 48 .fb_blank = tcx_blank, 49 .fb_pan_display = tcx_pan_display, 50 .fb_fillrect = cfb_fillrect, 51 .fb_copyarea = cfb_copyarea, 52 .fb_imageblit = cfb_imageblit, 53 .fb_mmap = tcx_mmap, 54 .fb_ioctl = tcx_ioctl, 55#ifdef CONFIG_COMPAT 56 .fb_compat_ioctl = sbusfb_compat_ioctl, 57#endif 58}; 59 60/* THC definitions */ 61#define TCX_THC_MISC_REV_SHIFT 16 62#define TCX_THC_MISC_REV_MASK 15 63#define TCX_THC_MISC_VSYNC_DIS (1 << 25) 64#define TCX_THC_MISC_HSYNC_DIS (1 << 24) 65#define TCX_THC_MISC_RESET (1 << 12) 66#define TCX_THC_MISC_VIDEO (1 << 10) 67#define TCX_THC_MISC_SYNC (1 << 9) 68#define TCX_THC_MISC_VSYNC (1 << 8) 69#define TCX_THC_MISC_SYNC_ENAB (1 << 7) 70#define TCX_THC_MISC_CURS_RES (1 << 6) 71#define TCX_THC_MISC_INT_ENAB (1 << 5) 72#define TCX_THC_MISC_INT (1 << 4) 73#define TCX_THC_MISC_INIT 0x9f 74#define TCX_THC_REV_REV_SHIFT 20 75#define TCX_THC_REV_REV_MASK 15 76#define TCX_THC_REV_MINREV_SHIFT 28 77#define TCX_THC_REV_MINREV_MASK 15 78 79/* The contents are unknown */ 80struct tcx_tec { 81 volatile u32 tec_matrix; 82 volatile u32 tec_clip; 83 volatile u32 tec_vdc; 84}; 85 86struct tcx_thc { 87 volatile u32 thc_rev; 88 u32 thc_pad0[511]; 89 volatile u32 thc_hs; /* hsync timing */ 90 volatile u32 thc_hsdvs; 91 volatile u32 thc_hd; 92 volatile u32 thc_vs; /* vsync timing */ 93 volatile u32 thc_vd; 94 volatile u32 thc_refresh; 95 volatile u32 thc_misc; 96 u32 thc_pad1[56]; 97 volatile u32 thc_cursxy; /* cursor x,y position (16 bits each) */ 98 volatile u32 thc_cursmask[32]; /* cursor mask bits */ 99 volatile u32 thc_cursbits[32]; /* what to show where mask enabled */ 100}; 101 102struct bt_regs { 103 volatile u32 addr; 104 volatile u32 color_map; 105 volatile u32 control; 106 volatile u32 cursor; 107}; 108 109#define TCX_MMAP_ENTRIES 14 110 111struct tcx_par { 112 spinlock_t lock; 113 struct bt_regs __iomem *bt; 114 struct tcx_thc __iomem *thc; 115 struct tcx_tec __iomem *tec; 116 volatile u32 __iomem *cplane; 117 118 u32 flags; 119#define TCX_FLAG_BLANKED 0x00000001 120 121 unsigned long physbase; 122 unsigned long fbsize; 123 124 struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES]; 125 int lowdepth; 126 127 struct sbus_dev *sdev; 128}; 129 130/* Reset control plane so that WID is 8-bit plane. */ 131static void __tcx_set_control_plane (struct tcx_par *par) 132{ 133 volatile u32 __iomem *p, *pend; 134 135 if (par->lowdepth) 136 return; 137 138 p = par->cplane; 139 if (p == NULL) 140 return; 141 for (pend = p + par->fbsize; p < pend; p++) { 142 u32 tmp = sbus_readl(p); 143 144 tmp &= 0xffffff; 145 sbus_writel(tmp, p); 146 } 147} 148 149static void tcx_reset (struct fb_info *info) 150{ 151 struct tcx_par *par = (struct tcx_par *) info->par; 152 unsigned long flags; 153 154 spin_lock_irqsave(&par->lock, flags); 155 __tcx_set_control_plane(par); 156 spin_unlock_irqrestore(&par->lock, flags); 157} 158 159static int tcx_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 160{ 161 tcx_reset(info); 162 return 0; 163} 164 165/** 166 * tcx_setcolreg - Optional function. Sets a color register. 167 * @regno: boolean, 0 copy local, 1 get_user() function 168 * @red: frame buffer colormap structure 169 * @green: The green value which can be up to 16 bits wide 170 * @blue: The blue value which can be up to 16 bits wide. 171 * @transp: If supported the alpha value which can be up to 16 bits wide. 172 * @info: frame buffer info structure 173 */ 174static int tcx_setcolreg(unsigned regno, 175 unsigned red, unsigned green, unsigned blue, 176 unsigned transp, struct fb_info *info) 177{ 178 struct tcx_par *par = (struct tcx_par *) info->par; 179 struct bt_regs __iomem *bt = par->bt; 180 unsigned long flags; 181 182 if (regno >= 256) 183 return 1; 184 185 red >>= 8; 186 green >>= 8; 187 blue >>= 8; 188 189 spin_lock_irqsave(&par->lock, flags); 190 191 sbus_writel(regno << 24, &bt->addr); 192 sbus_writel(red << 24, &bt->color_map); 193 sbus_writel(green << 24, &bt->color_map); 194 sbus_writel(blue << 24, &bt->color_map); 195 196 spin_unlock_irqrestore(&par->lock, flags); 197 198 return 0; 199} 200 201/** 202 * tcx_blank - Optional function. Blanks the display. 203 * @blank_mode: the blank mode we want. 204 * @info: frame buffer structure that represents a single frame buffer 205 */ 206static int 207tcx_blank(int blank, struct fb_info *info) 208{ 209 struct tcx_par *par = (struct tcx_par *) info->par; 210 struct tcx_thc __iomem *thc = par->thc; 211 unsigned long flags; 212 u32 val; 213 214 spin_lock_irqsave(&par->lock, flags); 215 216 val = sbus_readl(&thc->thc_misc); 217 218 switch (blank) { 219 case FB_BLANK_UNBLANK: /* Unblanking */ 220 val &= ~(TCX_THC_MISC_VSYNC_DIS | 221 TCX_THC_MISC_HSYNC_DIS); 222 val |= TCX_THC_MISC_VIDEO; 223 par->flags &= ~TCX_FLAG_BLANKED; 224 break; 225 226 case FB_BLANK_NORMAL: /* Normal blanking */ 227 val &= ~TCX_THC_MISC_VIDEO; 228 par->flags |= TCX_FLAG_BLANKED; 229 break; 230 231 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ 232 val |= TCX_THC_MISC_VSYNC_DIS; 233 break; 234 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ 235 val |= TCX_THC_MISC_HSYNC_DIS; 236 break; 237 238 case FB_BLANK_POWERDOWN: /* Poweroff */ 239 break; 240 }; 241 242 sbus_writel(val, &thc->thc_misc); 243 244 spin_unlock_irqrestore(&par->lock, flags); 245 246 return 0; 247} 248 249static struct sbus_mmap_map __tcx_mmap_map[TCX_MMAP_ENTRIES] = { 250 { 251 .voff = TCX_RAM8BIT, 252 .size = SBUS_MMAP_FBSIZE(1) 253 }, 254 { 255 .voff = TCX_RAM24BIT, 256 .size = SBUS_MMAP_FBSIZE(4) 257 }, 258 { 259 .voff = TCX_UNK3, 260 .size = SBUS_MMAP_FBSIZE(8) 261 }, 262 { 263 .voff = TCX_UNK4, 264 .size = SBUS_MMAP_FBSIZE(8) 265 }, 266 { 267 .voff = TCX_CONTROLPLANE, 268 .size = SBUS_MMAP_FBSIZE(4) 269 }, 270 { 271 .voff = TCX_UNK6, 272 .size = SBUS_MMAP_FBSIZE(8) 273 }, 274 { 275 .voff = TCX_UNK7, 276 .size = SBUS_MMAP_FBSIZE(8) 277 }, 278 { 279 .voff = TCX_TEC, 280 .size = PAGE_SIZE 281 }, 282 { 283 .voff = TCX_BTREGS, 284 .size = PAGE_SIZE 285 }, 286 { 287 .voff = TCX_THC, 288 .size = PAGE_SIZE 289 }, 290 { 291 .voff = TCX_DHC, 292 .size = PAGE_SIZE 293 }, 294 { 295 .voff = TCX_ALT, 296 .size = PAGE_SIZE 297 }, 298 { 299 .voff = TCX_UNK2, 300 .size = 0x20000 301 }, 302 { .size = 0 } 303}; 304 305static int tcx_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) 306{ 307 struct tcx_par *par = (struct tcx_par *)info->par; 308 309 return sbusfb_mmap_helper(par->mmap_map, 310 par->physbase, par->fbsize, 311 par->sdev->reg_addrs[0].which_io, 312 vma); 313} 314 315static int tcx_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 316 unsigned long arg, struct fb_info *info) 317{ 318 struct tcx_par *par = (struct tcx_par *) info->par; 319 320 return sbusfb_ioctl_helper(cmd, arg, info, 321 FBTYPE_TCXCOLOR, 322 (par->lowdepth ? 8 : 24), 323 par->fbsize); 324} 325 326/* 327 * Initialisation 328 */ 329 330static void 331tcx_init_fix(struct fb_info *info, int linebytes) 332{ 333 struct tcx_par *par = (struct tcx_par *)info->par; 334 const char *tcx_name; 335 336 if (par->lowdepth) 337 tcx_name = "TCX8"; 338 else 339 tcx_name = "TCX24"; 340 341 strlcpy(info->fix.id, tcx_name, sizeof(info->fix.id)); 342 343 info->fix.type = FB_TYPE_PACKED_PIXELS; 344 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 345 346 info->fix.line_length = linebytes; 347 348 info->fix.accel = FB_ACCEL_SUN_TCX; 349} 350 351struct all_info { 352 struct fb_info info; 353 struct tcx_par par; 354 struct list_head list; 355}; 356static LIST_HEAD(tcx_list); 357 358static void tcx_init_one(struct sbus_dev *sdev) 359{ 360 struct all_info *all; 361 int linebytes, i; 362 363 all = kmalloc(sizeof(*all), GFP_KERNEL); 364 if (!all) { 365 printk(KERN_ERR "tcx: Cannot allocate memory.\n"); 366 return; 367 } 368 memset(all, 0, sizeof(*all)); 369 370 INIT_LIST_HEAD(&all->list); 371 372 spin_lock_init(&all->par.lock); 373 all->par.sdev = sdev; 374 375 all->par.lowdepth = prom_getbool(sdev->prom_node, "tcx-8-bit"); 376 377 sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); 378 all->info.var.red.length = 8; 379 all->info.var.green.length = 8; 380 all->info.var.blue.length = 8; 381 382 linebytes = prom_getintdefault(sdev->prom_node, "linebytes", 383 all->info.var.xres); 384 all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); 385 386 all->par.tec = sbus_ioremap(&sdev->resource[7], 0, 387 sizeof(struct tcx_tec), "tcx tec"); 388 all->par.thc = sbus_ioremap(&sdev->resource[9], 0, 389 sizeof(struct tcx_thc), "tcx thc"); 390 all->par.bt = sbus_ioremap(&sdev->resource[8], 0, 391 sizeof(struct bt_regs), "tcx dac"); 392 memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map)); 393 if (!all->par.lowdepth) { 394 all->par.cplane = sbus_ioremap(&sdev->resource[4], 0, 395 all->par.fbsize * sizeof(u32), "tcx cplane"); 396 } else { 397 all->par.mmap_map[1].size = SBUS_MMAP_EMPTY; 398 all->par.mmap_map[4].size = SBUS_MMAP_EMPTY; 399 all->par.mmap_map[5].size = SBUS_MMAP_EMPTY; 400 all->par.mmap_map[6].size = SBUS_MMAP_EMPTY; 401 } 402 403 all->par.physbase = 0; 404 for (i = 0; i < TCX_MMAP_ENTRIES; i++) { 405 int j; 406 407 switch (i) { 408 case 10: 409 j = 12; 410 break; 411 412 case 11: case 12: 413 j = i - 1; 414 break; 415 416 default: 417 j = i; 418 break; 419 }; 420 all->par.mmap_map[i].poff = sdev->reg_addrs[j].phys_addr; 421 } 422 423 all->info.flags = FBINFO_DEFAULT; 424 all->info.fbops = &tcx_ops; 425#ifdef CONFIG_SPARC32 426 all->info.screen_base = (char __iomem *) 427 prom_getintdefault(sdev->prom_node, "address", 0); 428#endif 429 if (!all->info.screen_base) 430 all->info.screen_base = sbus_ioremap(&sdev->resource[0], 0, 431 all->par.fbsize, "tcx ram"); 432 all->info.par = &all->par; 433 434 /* Initialize brooktree DAC. */ 435 sbus_writel(0x04 << 24, &all->par.bt->addr); /* color planes */ 436 sbus_writel(0xff << 24, &all->par.bt->control); 437 sbus_writel(0x05 << 24, &all->par.bt->addr); 438 sbus_writel(0x00 << 24, &all->par.bt->control); 439 sbus_writel(0x06 << 24, &all->par.bt->addr); /* overlay plane */ 440 sbus_writel(0x73 << 24, &all->par.bt->control); 441 sbus_writel(0x07 << 24, &all->par.bt->addr); 442 sbus_writel(0x00 << 24, &all->par.bt->control); 443 444 tcx_reset(&all->info); 445 446 tcx_blank(FB_BLANK_UNBLANK, &all->info); 447 448 if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { 449 printk(KERN_ERR "tcx: Could not allocate color map.\n"); 450 kfree(all); 451 return; 452 } 453 454 fb_set_cmap(&all->info.cmap, &all->info); 455 tcx_init_fix(&all->info, linebytes); 456 457 if (register_framebuffer(&all->info) < 0) { 458 printk(KERN_ERR "tcx: Could not register framebuffer.\n"); 459 fb_dealloc_cmap(&all->info.cmap); 460 kfree(all); 461 return; 462 } 463 464 list_add(&all->list, &tcx_list); 465 466 printk("tcx: %s at %lx:%lx, %s\n", 467 sdev->prom_name, 468 (long) sdev->reg_addrs[0].which_io, 469 (long) sdev->reg_addrs[0].phys_addr, 470 all->par.lowdepth ? "8-bit only" : "24-bit depth"); 471} 472 473int __init tcx_init(void) 474{ 475 struct sbus_bus *sbus; 476 struct sbus_dev *sdev; 477 478 if (fb_get_options("tcxfb", NULL)) 479 return -ENODEV; 480 481 for_all_sbusdev(sdev, sbus) { 482 if (!strcmp(sdev->prom_name, "SUNW,tcx")) 483 tcx_init_one(sdev); 484 } 485 486 return 0; 487} 488 489void __exit tcx_exit(void) 490{ 491 struct list_head *pos, *tmp; 492 493 list_for_each_safe(pos, tmp, &tcx_list) { 494 struct all_info *all = list_entry(pos, typeof(*all), list); 495 496 unregister_framebuffer(&all->info); 497 fb_dealloc_cmap(&all->info.cmap); 498 kfree(all); 499 } 500} 501 502int __init 503tcx_setup(char *arg) 504{ 505 /* No cmdline options yet... */ 506 return 0; 507} 508 509module_init(tcx_init); 510 511#ifdef MODULE 512module_exit(tcx_exit); 513#endif 514 515MODULE_DESCRIPTION("framebuffer driver for TCX chipsets"); 516MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); 517MODULE_LICENSE("GPL");