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-rc3 385 lines 9.7 kB view raw
1/* p9100.c: P9100 frame buffer driver 2 * 3 * Copyright (C) 2003 David S. Miller (davem@redhat.com) 4 * Copyright 1999 Derrick J Brashear (shadow@dementia.org) 5 * 6 * Driver layout based loosely on tgafb.c, see that file for credits. 7 */ 8 9#include <linux/module.h> 10#include <linux/kernel.h> 11#include <linux/errno.h> 12#include <linux/string.h> 13#include <linux/slab.h> 14#include <linux/delay.h> 15#include <linux/init.h> 16#include <linux/fb.h> 17#include <linux/mm.h> 18 19#include <asm/io.h> 20#include <asm/sbus.h> 21#include <asm/oplib.h> 22#include <asm/fbio.h> 23 24#include "sbuslib.h" 25 26/* 27 * Local functions. 28 */ 29 30static int p9100_setcolreg(unsigned, unsigned, unsigned, unsigned, 31 unsigned, struct fb_info *); 32static int p9100_blank(int, struct fb_info *); 33 34static int p9100_mmap(struct fb_info *, struct file *, struct vm_area_struct *); 35static int p9100_ioctl(struct inode *, struct file *, unsigned int, 36 unsigned long, struct fb_info *); 37 38/* 39 * Frame buffer operations 40 */ 41 42static struct fb_ops p9100_ops = { 43 .owner = THIS_MODULE, 44 .fb_setcolreg = p9100_setcolreg, 45 .fb_blank = p9100_blank, 46 .fb_fillrect = cfb_fillrect, 47 .fb_copyarea = cfb_copyarea, 48 .fb_imageblit = cfb_imageblit, 49 .fb_mmap = p9100_mmap, 50 .fb_ioctl = p9100_ioctl, 51#ifdef CONFIG_COMPAT 52 .fb_compat_ioctl = sbusfb_compat_ioctl, 53#endif 54}; 55 56/* P9100 control registers */ 57#define P9100_SYSCTL_OFF 0x0UL 58#define P9100_VIDEOCTL_OFF 0x100UL 59#define P9100_VRAMCTL_OFF 0x180UL 60#define P9100_RAMDAC_OFF 0x200UL 61#define P9100_VIDEOCOPROC_OFF 0x400UL 62 63/* P9100 command registers */ 64#define P9100_CMD_OFF 0x0UL 65 66/* P9100 framebuffer memory */ 67#define P9100_FB_OFF 0x0UL 68 69/* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */ 70#define SYS_CONFIG_PIXELSIZE_SHIFT 26 71 72#define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */ 73 74struct p9100_regs { 75 /* Registers for the system control */ 76 volatile u32 sys_base; 77 volatile u32 sys_config; 78 volatile u32 sys_intr; 79 volatile u32 sys_int_ena; 80 volatile u32 sys_alt_rd; 81 volatile u32 sys_alt_wr; 82 volatile u32 sys_xxx[58]; 83 84 /* Registers for the video control */ 85 volatile u32 vid_base; 86 volatile u32 vid_hcnt; 87 volatile u32 vid_htotal; 88 volatile u32 vid_hsync_rise; 89 volatile u32 vid_hblank_rise; 90 volatile u32 vid_hblank_fall; 91 volatile u32 vid_hcnt_preload; 92 volatile u32 vid_vcnt; 93 volatile u32 vid_vlen; 94 volatile u32 vid_vsync_rise; 95 volatile u32 vid_vblank_rise; 96 volatile u32 vid_vblank_fall; 97 volatile u32 vid_vcnt_preload; 98 volatile u32 vid_screenpaint_addr; 99 volatile u32 vid_screenpaint_timectl1; 100 volatile u32 vid_screenpaint_qsfcnt; 101 volatile u32 vid_screenpaint_timectl2; 102 volatile u32 vid_xxx[15]; 103 104 /* Registers for the video control */ 105 volatile u32 vram_base; 106 volatile u32 vram_memcfg; 107 volatile u32 vram_refresh_pd; 108 volatile u32 vram_refresh_cnt; 109 volatile u32 vram_raslo_max; 110 volatile u32 vram_raslo_cur; 111 volatile u32 pwrup_cfg; 112 volatile u32 vram_xxx[25]; 113 114 /* Registers for IBM RGB528 Palette */ 115 volatile u32 ramdac_cmap_wridx; 116 volatile u32 ramdac_palette_data; 117 volatile u32 ramdac_pixel_mask; 118 volatile u32 ramdac_palette_rdaddr; 119 volatile u32 ramdac_idx_lo; 120 volatile u32 ramdac_idx_hi; 121 volatile u32 ramdac_idx_data; 122 volatile u32 ramdac_idx_ctl; 123 volatile u32 ramdac_xxx[1784]; 124}; 125 126struct p9100_cmd_parameng { 127 volatile u32 parameng_status; 128 volatile u32 parameng_bltcmd; 129 volatile u32 parameng_quadcmd; 130}; 131 132struct p9100_par { 133 spinlock_t lock; 134 struct p9100_regs __iomem *regs; 135 136 u32 flags; 137#define P9100_FLAG_BLANKED 0x00000001 138 139 unsigned long physbase; 140 unsigned long fbsize; 141 142 struct sbus_dev *sdev; 143 struct list_head list; 144}; 145 146/** 147 * p9100_setcolreg - Optional function. Sets a color register. 148 * @regno: boolean, 0 copy local, 1 get_user() function 149 * @red: frame buffer colormap structure 150 * @green: The green value which can be up to 16 bits wide 151 * @blue: The blue value which can be up to 16 bits wide. 152 * @transp: If supported the alpha value which can be up to 16 bits wide. 153 * @info: frame buffer info structure 154 */ 155static int p9100_setcolreg(unsigned regno, 156 unsigned red, unsigned green, unsigned blue, 157 unsigned transp, struct fb_info *info) 158{ 159 struct p9100_par *par = (struct p9100_par *) info->par; 160 struct p9100_regs __iomem *regs = par->regs; 161 unsigned long flags; 162 163 if (regno >= 256) 164 return 1; 165 166 red >>= 8; 167 green >>= 8; 168 blue >>= 8; 169 170 spin_lock_irqsave(&par->lock, flags); 171 172 sbus_writel((regno << 16), &regs->ramdac_cmap_wridx); 173 sbus_writel((red << 16), &regs->ramdac_palette_data); 174 sbus_writel((green << 16), &regs->ramdac_palette_data); 175 sbus_writel((blue << 16), &regs->ramdac_palette_data); 176 177 spin_unlock_irqrestore(&par->lock, flags); 178 179 return 0; 180} 181 182/** 183 * p9100_blank - Optional function. Blanks the display. 184 * @blank_mode: the blank mode we want. 185 * @info: frame buffer structure that represents a single frame buffer 186 */ 187static int 188p9100_blank(int blank, struct fb_info *info) 189{ 190 struct p9100_par *par = (struct p9100_par *) info->par; 191 struct p9100_regs __iomem *regs = par->regs; 192 unsigned long flags; 193 u32 val; 194 195 spin_lock_irqsave(&par->lock, flags); 196 197 switch (blank) { 198 case FB_BLANK_UNBLANK: /* Unblanking */ 199 val = sbus_readl(&regs->vid_screenpaint_timectl1); 200 val |= SCREENPAINT_TIMECTL1_ENABLE_VIDEO; 201 sbus_writel(val, &regs->vid_screenpaint_timectl1); 202 par->flags &= ~P9100_FLAG_BLANKED; 203 break; 204 205 case FB_BLANK_NORMAL: /* Normal blanking */ 206 case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ 207 case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ 208 case FB_BLANK_POWERDOWN: /* Poweroff */ 209 val = sbus_readl(&regs->vid_screenpaint_timectl1); 210 val &= ~SCREENPAINT_TIMECTL1_ENABLE_VIDEO; 211 sbus_writel(val, &regs->vid_screenpaint_timectl1); 212 par->flags |= P9100_FLAG_BLANKED; 213 break; 214 } 215 216 spin_unlock_irqrestore(&par->lock, flags); 217 218 return 0; 219} 220 221static struct sbus_mmap_map p9100_mmap_map[] = { 222 { CG3_MMAP_OFFSET, 0, SBUS_MMAP_FBSIZE(1) }, 223 { 0, 0, 0 } 224}; 225 226static int p9100_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma) 227{ 228 struct p9100_par *par = (struct p9100_par *)info->par; 229 230 return sbusfb_mmap_helper(p9100_mmap_map, 231 par->physbase, par->fbsize, 232 par->sdev->reg_addrs[0].which_io, 233 vma); 234} 235 236static int p9100_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 237 unsigned long arg, struct fb_info *info) 238{ 239 struct p9100_par *par = (struct p9100_par *) info->par; 240 241 /* Make it look like a cg3. */ 242 return sbusfb_ioctl_helper(cmd, arg, info, 243 FBTYPE_SUN3COLOR, 8, par->fbsize); 244} 245 246/* 247 * Initialisation 248 */ 249 250static void 251p9100_init_fix(struct fb_info *info, int linebytes) 252{ 253 struct p9100_par *par = (struct p9100_par *)info->par; 254 255 strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id)); 256 257 info->fix.type = FB_TYPE_PACKED_PIXELS; 258 info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 259 260 info->fix.line_length = linebytes; 261 262 info->fix.accel = FB_ACCEL_SUN_CGTHREE; 263} 264 265struct all_info { 266 struct fb_info info; 267 struct p9100_par par; 268 struct list_head list; 269}; 270static LIST_HEAD(p9100_list); 271 272static void p9100_init_one(struct sbus_dev *sdev) 273{ 274 struct all_info *all; 275 int linebytes; 276 277 all = kmalloc(sizeof(*all), GFP_KERNEL); 278 if (!all) { 279 printk(KERN_ERR "p9100: Cannot allocate memory.\n"); 280 return; 281 } 282 memset(all, 0, sizeof(*all)); 283 284 INIT_LIST_HEAD(&all->list); 285 286 spin_lock_init(&all->par.lock); 287 all->par.sdev = sdev; 288 289 /* This is the framebuffer and the only resource apps can mmap. */ 290 all->par.physbase = sdev->reg_addrs[2].phys_addr; 291 292 sbusfb_fill_var(&all->info.var, sdev->prom_node, 8); 293 all->info.var.red.length = 8; 294 all->info.var.green.length = 8; 295 all->info.var.blue.length = 8; 296 297 linebytes = prom_getintdefault(sdev->prom_node, "linebytes", 298 all->info.var.xres); 299 all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); 300 301 all->par.regs = sbus_ioremap(&sdev->resource[0], 0, 302 sizeof(struct p9100_regs), "p9100 regs"); 303 304 all->info.flags = FBINFO_DEFAULT; 305 all->info.fbops = &p9100_ops; 306#ifdef CONFIG_SPARC32 307 all->info.screen_base = (char __iomem *) 308 prom_getintdefault(sdev->prom_node, "address", 0); 309#endif 310 if (!all->info.screen_base) 311 all->info.screen_base = sbus_ioremap(&sdev->resource[2], 0, 312 all->par.fbsize, "p9100 ram"); 313 all->info.par = &all->par; 314 315 p9100_blank(0, &all->info); 316 317 if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { 318 printk(KERN_ERR "p9100: Could not allocate color map.\n"); 319 kfree(all); 320 return; 321 } 322 323 p9100_init_fix(&all->info, linebytes); 324 325 if (register_framebuffer(&all->info) < 0) { 326 printk(KERN_ERR "p9100: Could not register framebuffer.\n"); 327 fb_dealloc_cmap(&all->info.cmap); 328 kfree(all); 329 return; 330 } 331 fb_set_cmap(&all->info.cmap, &all->info); 332 333 list_add(&all->list, &p9100_list); 334 335 printk("p9100: %s at %lx:%lx\n", 336 sdev->prom_name, 337 (long) sdev->reg_addrs[0].which_io, 338 (long) sdev->reg_addrs[0].phys_addr); 339} 340 341int __init p9100_init(void) 342{ 343 struct sbus_bus *sbus; 344 struct sbus_dev *sdev; 345 346 if (fb_get_options("p9100fb", NULL)) 347 return -ENODEV; 348 349 for_all_sbusdev(sdev, sbus) { 350 if (!strcmp(sdev->prom_name, "p9100")) 351 p9100_init_one(sdev); 352 } 353 354 return 0; 355} 356 357void __exit p9100_exit(void) 358{ 359 struct list_head *pos, *tmp; 360 361 list_for_each_safe(pos, tmp, &p9100_list) { 362 struct all_info *all = list_entry(pos, typeof(*all), list); 363 364 unregister_framebuffer(&all->info); 365 fb_dealloc_cmap(&all->info.cmap); 366 kfree(all); 367 } 368} 369 370int __init 371p9100_setup(char *arg) 372{ 373 /* No cmdline options yet... */ 374 return 0; 375} 376 377module_init(p9100_init); 378 379#ifdef MODULE 380module_exit(p9100_exit); 381#endif 382 383MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets"); 384MODULE_AUTHOR("David S. Miller <davem@redhat.com>"); 385MODULE_LICENSE("GPL");