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.13-rc4 428 lines 10 kB view raw
1/* bw2.c: BWTWO 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) 1997 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#ifdef CONFIG_SPARC32 27#include <asm/sun4paddr.h> 28#endif 29 30#include "sbuslib.h" 31 32/* 33 * Local functions. 34 */ 35 36static int bw2_blank(int, struct fb_info *); 37 38static int bw2_mmap(struct fb_info *, struct file *, struct vm_area_struct *); 39static int bw2_ioctl(struct inode *, struct file *, unsigned int, 40 unsigned long, struct fb_info *); 41 42/* 43 * Frame buffer operations 44 */ 45 46static struct fb_ops bw2_ops = { 47 .owner = THIS_MODULE, 48 .fb_blank = bw2_blank, 49 .fb_fillrect = cfb_fillrect, 50 .fb_copyarea = cfb_copyarea, 51 .fb_imageblit = cfb_imageblit, 52 .fb_mmap = bw2_mmap, 53 .fb_ioctl = bw2_ioctl, 54 .fb_cursor = soft_cursor, 55}; 56 57/* OBio addresses for the bwtwo registers */ 58#define BWTWO_REGISTER_OFFSET 0x400000 59 60struct bt_regs { 61 volatile u32 addr; 62 volatile u32 color_map; 63 volatile u32 control; 64 volatile u32 cursor; 65}; 66 67struct bw2_regs { 68 struct bt_regs cmap; 69 volatile u8 control; 70 volatile u8 status; 71 volatile u8 cursor_start; 72 volatile u8 cursor_end; 73 volatile u8 h_blank_start; 74 volatile u8 h_blank_end; 75 volatile u8 h_sync_start; 76 volatile u8 h_sync_end; 77 volatile u8 comp_sync_end; 78 volatile u8 v_blank_start_high; 79 volatile u8 v_blank_start_low; 80 volatile u8 v_blank_end; 81 volatile u8 v_sync_start; 82 volatile u8 v_sync_end; 83 volatile u8 xfer_holdoff_start; 84 volatile u8 xfer_holdoff_end; 85}; 86 87/* Status Register Constants */ 88#define BWTWO_SR_RES_MASK 0x70 89#define BWTWO_SR_1600_1280 0x50 90#define BWTWO_SR_1152_900_76_A 0x40 91#define BWTWO_SR_1152_900_76_B 0x60 92#define BWTWO_SR_ID_MASK 0x0f 93#define BWTWO_SR_ID_MONO 0x02 94#define BWTWO_SR_ID_MONO_ECL 0x03 95#define BWTWO_SR_ID_MSYNC 0x04 96#define BWTWO_SR_ID_NOCONN 0x0a 97 98/* Control Register Constants */ 99#define BWTWO_CTL_ENABLE_INTS 0x80 100#define BWTWO_CTL_ENABLE_VIDEO 0x40 101#define BWTWO_CTL_ENABLE_TIMING 0x20 102#define BWTWO_CTL_ENABLE_CURCMP 0x10 103#define BWTWO_CTL_XTAL_MASK 0x0C 104#define BWTWO_CTL_DIVISOR_MASK 0x03 105 106/* Status Register Constants */ 107#define BWTWO_STAT_PENDING_INT 0x80 108#define BWTWO_STAT_MSENSE_MASK 0x70 109#define BWTWO_STAT_ID_MASK 0x0f 110 111struct bw2_par { 112 spinlock_t lock; 113 struct bw2_regs __iomem *regs; 114 115 u32 flags; 116#define BW2_FLAG_BLANKED 0x00000001 117 118 unsigned long physbase; 119 unsigned long fbsize; 120 121 struct sbus_dev *sdev; 122 struct list_head list; 123}; 124 125/** 126 * bw2_blank - Optional function. Blanks the display. 127 * @blank_mode: the blank mode we want. 128 * @info: frame buffer structure that represents a single frame buffer 129 */ 130static int 131bw2_blank(int blank, struct fb_info *info) 132{ 133 struct bw2_par *par = (struct bw2_par *) info->par; 134 struct bw2_regs __iomem *regs = par->regs; 135 unsigned long flags; 136 u8 val; 137 138 spin_lock_irqsave(&par->lock, flags); 139 140 switch (blank) { 141 case FB_BLANK_UNBLANK: /* Unblanking */ 142 val = sbus_readb(&regs->control); 143 val |= BWTWO_CTL_ENABLE_VIDEO; 144 sbus_writeb(val, &regs->control); 145 par->flags &= ~BW2_FLAG_BLANKED; 146 break; 147 148 case FB_BLANK_NORMAL: /* Normal blanking */ 149 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ 150 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ 151 case FB_BLANK_POWERDOWN: /* Poweroff */ 152 val = sbus_readb(&regs->control); 153 val &= ~BWTWO_CTL_ENABLE_VIDEO; 154 sbus_writeb(val, &regs->control); 155 par->flags |= BW2_FLAG_BLANKED; 156 break; 157 } 158 159 spin_unlock_irqrestore(&par->lock, flags); 160 161 return 0; 162} 163 164static struct sbus_mmap_map bw2_mmap_map[] = { 165 { 166 .size = SBUS_MMAP_FBSIZE(1) 167 }, 168 { .size = 0 } 169}; 170 171static int bw2_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) 172{ 173 struct bw2_par *par = (struct bw2_par *)info->par; 174 175 return sbusfb_mmap_helper(bw2_mmap_map, 176 par->physbase, par->fbsize, 177 (par->sdev ? 178 par->sdev->reg_addrs[0].which_io : 179 0), 180 vma); 181} 182 183static int bw2_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 184 unsigned long arg, struct fb_info *info) 185{ 186 struct bw2_par *par = (struct bw2_par *) info->par; 187 188 return sbusfb_ioctl_helper(cmd, arg, info, 189 FBTYPE_SUN2BW, 1, par->fbsize); 190} 191 192/* 193 * Initialisation 194 */ 195 196static void 197bw2_init_fix(struct fb_info *info, int linebytes) 198{ 199 strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id)); 200 201 info->fix.type = FB_TYPE_PACKED_PIXELS; 202 info->fix.visual = FB_VISUAL_MONO01; 203 204 info->fix.line_length = linebytes; 205 206 info->fix.accel = FB_ACCEL_SUN_BWTWO; 207} 208 209static u8 bw2regs_1600[] __initdata = { 210 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13, 211 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e, 212 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01, 213 0x10, 0x21, 0 214}; 215 216static u8 bw2regs_ecl[] __initdata = { 217 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c, 218 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23, 219 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01, 220 0x10, 0x20, 0 221}; 222 223static u8 bw2regs_analog[] __initdata = { 224 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13, 225 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22, 226 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, 227 0x10, 0x20, 0 228}; 229 230static u8 bw2regs_76hz[] __initdata = { 231 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f, 232 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a, 233 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01, 234 0x10, 0x24, 0 235}; 236 237static u8 bw2regs_66hz[] __initdata = { 238 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14, 239 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24, 240 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, 241 0x10, 0x20, 0 242}; 243 244static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info, 245 int *linebytes) 246{ 247 u8 status, mon; 248 u8 *p; 249 250 status = sbus_readb(&par->regs->status); 251 mon = status & BWTWO_SR_RES_MASK; 252 switch (status & BWTWO_SR_ID_MASK) { 253 case BWTWO_SR_ID_MONO_ECL: 254 if (mon == BWTWO_SR_1600_1280) { 255 p = bw2regs_1600; 256 info->var.xres = info->var.xres_virtual = 1600; 257 info->var.yres = info->var.yres_virtual = 1280; 258 *linebytes = 1600 / 8; 259 } else 260 p = bw2regs_ecl; 261 break; 262 263 case BWTWO_SR_ID_MONO: 264 p = bw2regs_analog; 265 break; 266 267 case BWTWO_SR_ID_MSYNC: 268 if (mon == BWTWO_SR_1152_900_76_A || 269 mon == BWTWO_SR_1152_900_76_B) 270 p = bw2regs_76hz; 271 else 272 p = bw2regs_66hz; 273 break; 274 275 case BWTWO_SR_ID_NOCONN: 276 return; 277 278 default: 279 prom_printf("bw2: can't handle SR %02x\n", 280 status); 281 prom_halt(); 282 } 283 for ( ; *p; p += 2) { 284 u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]]; 285 sbus_writeb(p[1], regp); 286 } 287} 288 289struct all_info { 290 struct fb_info info; 291 struct bw2_par par; 292 struct list_head list; 293}; 294static LIST_HEAD(bw2_list); 295 296static void bw2_init_one(struct sbus_dev *sdev) 297{ 298 struct all_info *all; 299 struct resource *resp; 300#ifdef CONFIG_SUN4 301 struct resource res; 302#endif 303 int linebytes; 304 305 all = kmalloc(sizeof(*all), GFP_KERNEL); 306 if (!all) { 307 printk(KERN_ERR "bw2: Cannot allocate memory.\n"); 308 return; 309 } 310 memset(all, 0, sizeof(*all)); 311 312 INIT_LIST_HEAD(&all->list); 313 314 spin_lock_init(&all->par.lock); 315 all->par.sdev = sdev; 316 317#ifdef CONFIG_SUN4 318 if (!sdev) { 319 all->par.physbase = sun4_bwtwo_physaddr; 320 res.start = sun4_bwtwo_physaddr; 321 res.end = res.start + BWTWO_REGISTER_OFFSET + sizeof(struct bw2_regs) - 1; 322 res.flags = IORESOURCE_IO; 323 resp = &res; 324 all->info.var.xres = all->info.var.xres_virtual = 1152; 325 all->info.var.yres = all->info.var.yres_virtual = 900; 326 all->info.var.bits_per_pixel = 1; 327 linebytes = 1152 / 8; 328 } else 329#else 330 { 331 if (!sdev) 332 BUG(); 333 all->par.physbase = sdev->reg_addrs[0].phys_addr; 334 resp = &sdev->resource[0]; 335 sbusfb_fill_var(&all->info.var, (sdev ? sdev->prom_node : 0), 1); 336 linebytes = prom_getintdefault(sdev->prom_node, "linebytes", 337 all->info.var.xres); 338 } 339#endif 340 all->info.var.red.length = all->info.var.green.length = 341 all->info.var.blue.length = all->info.var.bits_per_pixel; 342 all->info.var.red.offset = all->info.var.green.offset = 343 all->info.var.blue.offset = 0; 344 345 all->par.regs = sbus_ioremap(resp, BWTWO_REGISTER_OFFSET, 346 sizeof(struct bw2_regs), "bw2 regs"); 347 348 if (sdev && !prom_getbool(sdev->prom_node, "width")) 349 bw2_do_default_mode(&all->par, &all->info, &linebytes); 350 351 all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); 352 353 all->info.flags = FBINFO_DEFAULT; 354 all->info.fbops = &bw2_ops; 355#if defined(CONFIG_SPARC32) 356 if (sdev) 357 all->info.screen_base = (char __iomem *) 358 prom_getintdefault(sdev->prom_node, "address", 0); 359#endif 360 if (!all->info.screen_base) 361 all->info.screen_base = 362 sbus_ioremap(resp, 0, all->par.fbsize, "bw2 ram"); 363 all->info.par = &all->par; 364 365 bw2_blank(0, &all->info); 366 367 bw2_init_fix(&all->info, linebytes); 368 369 if (register_framebuffer(&all->info) < 0) { 370 printk(KERN_ERR "bw2: Could not register framebuffer.\n"); 371 kfree(all); 372 return; 373 } 374 375 list_add(&all->list, &bw2_list); 376 377 printk("bw2: bwtwo at %lx:%lx\n", 378 (long) (sdev ? sdev->reg_addrs[0].which_io : 0), 379 (long) all->par.physbase); 380} 381 382int __init bw2_init(void) 383{ 384 struct sbus_bus *sbus; 385 struct sbus_dev *sdev; 386 387 if (fb_get_options("bw2fb", NULL)) 388 return -ENODEV; 389 390#ifdef CONFIG_SUN4 391 bw2_init_one(NULL); 392#endif 393 for_all_sbusdev(sdev, sbus) { 394 if (!strcmp(sdev->prom_name, "bwtwo")) 395 bw2_init_one(sdev); 396 } 397 398 return 0; 399} 400 401void __exit bw2_exit(void) 402{ 403 struct list_head *pos, *tmp; 404 405 list_for_each_safe(pos, tmp, &bw2_list) { 406 struct all_info *all = list_entry(pos, typeof(*all), list); 407 408 unregister_framebuffer(&all->info); 409 kfree(all); 410 } 411} 412 413int __init 414bw2_setup(char *arg) 415{ 416 /* No cmdline options yet... */ 417 return 0; 418} 419 420module_init(bw2_init); 421 422#ifdef MODULE 423module_exit(bw2_exit); 424#endif 425 426MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets"); 427MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); 428MODULE_LICENSE("GPL");