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