1 /* cg3.c: CGTHREE frame buffer driver
 
   3  * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
 
   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)
 
   8  * Driver layout based loosely on tgafb.c, see that file for credits.
 
  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>
 
  22 #include <asm/oplib.h>
 
  24 #include <asm/of_device.h>
 
  33 static int cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,
 
  34                          unsigned, struct fb_info *);
 
  35 static int cg3_blank(int, struct fb_info *);
 
  37 static int cg3_mmap(struct fb_info *, struct vm_area_struct *);
 
  38 static int cg3_ioctl(struct fb_info *, unsigned int, unsigned long);
 
  41  *  Frame buffer operations
 
  44 static struct fb_ops cg3_ops = {
 
  46         .fb_setcolreg           = cg3_setcolreg,
 
  47         .fb_blank               = cg3_blank,
 
  48         .fb_fillrect            = cfb_fillrect,
 
  49         .fb_copyarea            = cfb_copyarea,
 
  50         .fb_imageblit           = cfb_imageblit,
 
  52         .fb_ioctl               = cg3_ioctl,
 
  54         .fb_compat_ioctl        = sbusfb_compat_ioctl,
 
  59 /* Control Register Constants */
 
  60 #define CG3_CR_ENABLE_INTS      0x80
 
  61 #define CG3_CR_ENABLE_VIDEO     0x40
 
  62 #define CG3_CR_ENABLE_TIMING    0x20
 
  63 #define CG3_CR_ENABLE_CURCMP    0x10
 
  64 #define CG3_CR_XTAL_MASK        0x0c
 
  65 #define CG3_CR_DIVISOR_MASK     0x03
 
  67 /* Status Register Constants */
 
  68 #define CG3_SR_PENDING_INT      0x80
 
  69 #define CG3_SR_RES_MASK         0x70
 
  70 #define CG3_SR_1152_900_76_A    0x40
 
  71 #define CG3_SR_1152_900_76_B    0x60
 
  72 #define CG3_SR_ID_MASK          0x0f
 
  73 #define CG3_SR_ID_COLOR         0x01
 
  74 #define CG3_SR_ID_MONO          0x02
 
  75 #define CG3_SR_ID_MONO_ECL      0x03
 
 101         u8      v_blank_start_high;
 
 102         u8      v_blank_start_low;
 
 106         u8      xfer_holdoff_start;
 
 110 /* Offset of interesting structures in the OBIO space */
 
 111 #define CG3_REGS_OFFSET      0x400000UL
 
 112 #define CG3_RAM_OFFSET       0x800000UL
 
 116         struct cg3_regs         __iomem *regs;
 
 117         u32                     sw_cmap[((256 * 3) + 3) / 4];
 
 120 #define CG3_FLAG_BLANKED        0x00000001
 
 121 #define CG3_FLAG_RDI            0x00000002
 
 123         unsigned long           physbase;
 
 124         unsigned long           which_io;
 
 125         unsigned long           fbsize;
 
 129  *      cg3_setcolreg - Optional function. Sets a color register.
 
 130  *      @regno: boolean, 0 copy local, 1 get_user() function
 
 131  *      @red: frame buffer colormap structure
 
 132  *      @green: The green value which can be up to 16 bits wide
 
 133  *      @blue:  The blue value which can be up to 16 bits wide.
 
 134  *      @transp: If supported the alpha value which can be up to 16 bits wide.
 
 135  *      @info: frame buffer info structure
 
 137  * The cg3 palette is loaded with 4 color values at each time
 
 138  * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.
 
 139  * We keep a sw copy of the hw cmap to assist us in this esoteric
 
 142 static int cg3_setcolreg(unsigned regno,
 
 143                          unsigned red, unsigned green, unsigned blue,
 
 144                          unsigned transp, struct fb_info *info)
 
 146         struct cg3_par *par = (struct cg3_par *) info->par;
 
 147         struct bt_regs __iomem *bt = &par->regs->cmap;
 
 160         spin_lock_irqsave(&par->lock, flags);
 
 162         p8 = (u8 *)par->sw_cmap + (regno * 3);
 
 167 #define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
 
 168 #define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
 
 171         p32 = &par->sw_cmap[D4M3(regno)];
 
 172         sbus_writel(D4M4(regno), &bt->addr);
 
 174                 sbus_writel(*p32++, &bt->color_map);
 
 179         spin_unlock_irqrestore(&par->lock, flags);
 
 185  *      cg3_blank - Optional function.  Blanks the display.
 
 186  *      @blank_mode: the blank mode we want.
 
 187  *      @info: frame buffer structure that represents a single frame buffer
 
 190 cg3_blank(int blank, struct fb_info *info)
 
 192         struct cg3_par *par = (struct cg3_par *) info->par;
 
 193         struct cg3_regs __iomem *regs = par->regs;
 
 197         spin_lock_irqsave(&par->lock, flags);
 
 200         case FB_BLANK_UNBLANK: /* Unblanking */
 
 201                 val = sbus_readb(®s->control);
 
 202                 val |= CG3_CR_ENABLE_VIDEO;
 
 203                 sbus_writeb(val, ®s->control);
 
 204                 par->flags &= ~CG3_FLAG_BLANKED;
 
 207         case FB_BLANK_NORMAL: /* Normal blanking */
 
 208         case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
 
 209         case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
 
 210         case FB_BLANK_POWERDOWN: /* Poweroff */
 
 211                 val = sbus_readb(®s->control);
 
 212                 val &= ~CG3_CR_ENABLE_VIDEO;
 
 213                 sbus_writeb(val, ®s->control);
 
 214                 par->flags |= CG3_FLAG_BLANKED;
 
 218         spin_unlock_irqrestore(&par->lock, flags);
 
 223 static struct sbus_mmap_map cg3_mmap_map[] = {
 
 225                 .voff   = CG3_MMAP_OFFSET,
 
 226                 .poff   = CG3_RAM_OFFSET,
 
 227                 .size   = SBUS_MMAP_FBSIZE(1)
 
 232 static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma)
 
 234         struct cg3_par *par = (struct cg3_par *)info->par;
 
 236         return sbusfb_mmap_helper(cg3_mmap_map,
 
 237                                   par->physbase, par->fbsize,
 
 242 static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 
 244         struct cg3_par *par = (struct cg3_par *) info->par;
 
 246         return sbusfb_ioctl_helper(cmd, arg, info,
 
 247                                    FBTYPE_SUN3COLOR, 8, par->fbsize);
 
 255 cg3_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
 
 257         strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
 
 259         info->fix.type = FB_TYPE_PACKED_PIXELS;
 
 260         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 
 262         info->fix.line_length = linebytes;
 
 264         info->fix.accel = FB_ACCEL_SUN_CGTHREE;
 
 267 static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
 
 268                                     struct device_node *dp)
 
 274         params = of_get_property(dp, "params", NULL);
 
 276                 ww = simple_strtoul(params, &p, 10);
 
 277                 if (ww && *p == 'x') {
 
 278                         hh = simple_strtoul(p + 1, &p, 10);
 
 279                         if (hh && *p == '-') {
 
 280                                 if (var->xres != ww ||
 
 282                                         var->xres = var->xres_virtual = ww;
 
 283                                         var->yres = var->yres_virtual = hh;
 
 290 static u8 cg3regvals_66hz[] __initdata = {      /* 1152 x 900, 66 Hz */
 
 291         0x14, 0xbb,     0x15, 0x2b,     0x16, 0x04,     0x17, 0x14,
 
 292         0x18, 0xae,     0x19, 0x03,     0x1a, 0xa8,     0x1b, 0x24,
 
 293         0x1c, 0x01,     0x1d, 0x05,     0x1e, 0xff,     0x1f, 0x01,
 
 297 static u8 cg3regvals_76hz[] __initdata = {      /* 1152 x 900, 76 Hz */
 
 298         0x14, 0xb7,     0x15, 0x27,     0x16, 0x03,     0x17, 0x0f,
 
 299         0x18, 0xae,     0x19, 0x03,     0x1a, 0xae,     0x1b, 0x2a,
 
 300         0x1c, 0x01,     0x1d, 0x09,     0x1e, 0xff,     0x1f, 0x01,
 
 304 static u8 cg3regvals_rdi[] __initdata = {       /* 640 x 480, cgRDI */
 
 305         0x14, 0x70,     0x15, 0x20,     0x16, 0x08,     0x17, 0x10,
 
 306         0x18, 0x06,     0x19, 0x02,     0x1a, 0x31,     0x1b, 0x51,
 
 307         0x1c, 0x06,     0x1d, 0x0c,     0x1e, 0xff,     0x1f, 0x01,
 
 311 static u8 *cg3_regvals[] __initdata = {
 
 312         cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
 
 315 static u_char cg3_dacvals[] __initdata = {
 
 316         4, 0xff,        5, 0x00,        6, 0x70,        7, 0x00,        0
 
 319 static void cg3_do_default_mode(struct cg3_par *par)
 
 324         if (par->flags & CG3_FLAG_RDI)
 
 327                 u8 status = sbus_readb(&par->regs->status), mon;
 
 328                 if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
 
 329                         mon = status & CG3_SR_RES_MASK;
 
 330                         if (mon == CG3_SR_1152_900_76_A ||
 
 331                             mon == CG3_SR_1152_900_76_B)
 
 336                         prom_printf("cgthree: can't handle SR %02x\n",
 
 343         for (p = cg3_regvals[type]; *p; p += 2) {
 
 344                 u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
 
 345                 sbus_writeb(p[1], regp);
 
 347         for (p = cg3_dacvals; *p; p += 2) {
 
 350                 regp = (u8 __iomem *)&par->regs->cmap.addr;
 
 351                 sbus_writeb(p[0], regp);
 
 352                 regp = (u8 __iomem *)&par->regs->cmap.control;
 
 353                 sbus_writeb(p[1], regp);
 
 362 static int __devinit cg3_init_one(struct of_device *op)
 
 364         struct device_node *dp = op->node;
 
 365         struct all_info *all;
 
 368         all = kzalloc(sizeof(*all), GFP_KERNEL);
 
 372         spin_lock_init(&all->par.lock);
 
 374         all->par.physbase = op->resource[0].start;
 
 375         all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
 
 377         sbusfb_fill_var(&all->info.var, dp->node, 8);
 
 378         all->info.var.red.length = 8;
 
 379         all->info.var.green.length = 8;
 
 380         all->info.var.blue.length = 8;
 
 381         if (!strcmp(dp->name, "cgRDI"))
 
 382                 all->par.flags |= CG3_FLAG_RDI;
 
 383         if (all->par.flags & CG3_FLAG_RDI)
 
 384                 cg3_rdi_maybe_fixup_var(&all->info.var, dp);
 
 386         linebytes = of_getintprop_default(dp, "linebytes",
 
 388         all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
 
 390         all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
 
 391                                    sizeof(struct cg3_regs), "cg3 regs");
 
 393         all->info.flags = FBINFO_DEFAULT;
 
 394         all->info.fbops = &cg3_ops;
 
 395         all->info.screen_base =
 
 396                 of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
 
 397                            all->par.fbsize, "cg3 ram");
 
 398         all->info.par = &all->par;
 
 400         cg3_blank(0, &all->info);
 
 402         if (!of_find_property(dp, "width", NULL))
 
 403                 cg3_do_default_mode(&all->par);
 
 405         if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
 
 406                 of_iounmap(&op->resource[0],
 
 407                            all->par.regs, sizeof(struct cg3_regs));
 
 408                 of_iounmap(&op->resource[0],
 
 409                            all->info.screen_base, all->par.fbsize);
 
 413         fb_set_cmap(&all->info.cmap, &all->info);
 
 415         cg3_init_fix(&all->info, linebytes, dp);
 
 417         err = register_framebuffer(&all->info);
 
 419                 fb_dealloc_cmap(&all->info.cmap);
 
 420                 of_iounmap(&op->resource[0],
 
 421                            all->par.regs, sizeof(struct cg3_regs));
 
 422                 of_iounmap(&op->resource[0],
 
 423                            all->info.screen_base, all->par.fbsize);
 
 428         dev_set_drvdata(&op->dev, all);
 
 430         printk("%s: cg3 at %lx:%lx\n",
 
 431                dp->full_name, all->par.which_io, all->par.physbase);
 
 436 static int __devinit cg3_probe(struct of_device *dev, const struct of_device_id *match)
 
 438         struct of_device *op = to_of_device(&dev->dev);
 
 440         return cg3_init_one(op);
 
 443 static int __devexit cg3_remove(struct of_device *op)
 
 445         struct all_info *all = dev_get_drvdata(&op->dev);
 
 447         unregister_framebuffer(&all->info);
 
 448         fb_dealloc_cmap(&all->info.cmap);
 
 450         of_iounmap(&op->resource[0], all->par.regs, sizeof(struct cg3_regs));
 
 451         of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize);
 
 455         dev_set_drvdata(&op->dev, NULL);
 
 460 static struct of_device_id cg3_match[] = {
 
 469 MODULE_DEVICE_TABLE(of, cg3_match);
 
 471 static struct of_platform_driver cg3_driver = {
 
 473         .match_table    = cg3_match,
 
 475         .remove         = __devexit_p(cg3_remove),
 
 478 static int __init cg3_init(void)
 
 480         if (fb_get_options("cg3fb", NULL))
 
 483         return of_register_driver(&cg3_driver, &of_bus_type);
 
 486 static void __exit cg3_exit(void)
 
 488         of_unregister_driver(&cg3_driver);
 
 491 module_init(cg3_init);
 
 492 module_exit(cg3_exit);
 
 494 MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
 
 495 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
 
 496 MODULE_VERSION("2.0");
 
 497 MODULE_LICENSE("GPL");