1 /* cg6.c: CGSIX (GX, GXplus, TGX) 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) 1996 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/of_device.h>
 
  31 static int cg6_setcolreg(unsigned, unsigned, unsigned, unsigned,
 
  32                          unsigned, struct fb_info *);
 
  33 static int cg6_blank(int, struct fb_info *);
 
  35 static void cg6_imageblit(struct fb_info *, const struct fb_image *);
 
  36 static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
 
  37 static int cg6_sync(struct fb_info *);
 
  38 static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
 
  39 static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
 
  40 static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 
  43  *  Frame buffer operations
 
  46 static struct fb_ops cg6_ops = {
 
  48         .fb_setcolreg           = cg6_setcolreg,
 
  49         .fb_blank               = cg6_blank,
 
  50         .fb_fillrect            = cg6_fillrect,
 
  51         .fb_copyarea            = cg6_copyarea,
 
  52         .fb_imageblit           = cg6_imageblit,
 
  55         .fb_ioctl               = cg6_ioctl,
 
  57         .fb_compat_ioctl        = sbusfb_compat_ioctl,
 
  61 /* Offset of interesting structures in the OBIO space */
 
  63  * Brooktree is the video dac and is funny to program on the cg6.
 
  64  * (it's even funnier on the cg3)
 
  65  * The FBC could be the frame buffer control
 
  66  * The FHC could is the frame buffer hardware control.
 
  68 #define CG6_ROM_OFFSET                  0x0UL
 
  69 #define CG6_BROOKTREE_OFFSET            0x200000UL
 
  70 #define CG6_DHC_OFFSET                  0x240000UL
 
  71 #define CG6_ALT_OFFSET                  0x280000UL
 
  72 #define CG6_FHC_OFFSET                  0x300000UL
 
  73 #define CG6_THC_OFFSET                  0x301000UL
 
  74 #define CG6_FBC_OFFSET                  0x700000UL
 
  75 #define CG6_TEC_OFFSET                  0x701000UL
 
  76 #define CG6_RAM_OFFSET                  0x800000UL
 
  79 #define CG6_FHC_FBID_SHIFT              24
 
  80 #define CG6_FHC_FBID_MASK               255
 
  81 #define CG6_FHC_REV_SHIFT               20
 
  82 #define CG6_FHC_REV_MASK                15
 
  83 #define CG6_FHC_FROP_DISABLE            (1 << 19)
 
  84 #define CG6_FHC_ROW_DISABLE             (1 << 18)
 
  85 #define CG6_FHC_SRC_DISABLE             (1 << 17)
 
  86 #define CG6_FHC_DST_DISABLE             (1 << 16)
 
  87 #define CG6_FHC_RESET                   (1 << 15)
 
  88 #define CG6_FHC_LITTLE_ENDIAN           (1 << 13)
 
  89 #define CG6_FHC_RES_MASK                (3 << 11)
 
  90 #define CG6_FHC_1024                    (0 << 11)
 
  91 #define CG6_FHC_1152                    (1 << 11)
 
  92 #define CG6_FHC_1280                    (2 << 11)
 
  93 #define CG6_FHC_1600                    (3 << 11)
 
  94 #define CG6_FHC_CPU_MASK                (3 << 9)
 
  95 #define CG6_FHC_CPU_SPARC               (0 << 9)
 
  96 #define CG6_FHC_CPU_68020               (1 << 9)
 
  97 #define CG6_FHC_CPU_386                 (2 << 9)
 
  98 #define CG6_FHC_TEST                    (1 << 8)
 
  99 #define CG6_FHC_TEST_X_SHIFT            4
 
 100 #define CG6_FHC_TEST_X_MASK             15
 
 101 #define CG6_FHC_TEST_Y_SHIFT            0
 
 102 #define CG6_FHC_TEST_Y_MASK             15
 
 104 /* FBC mode definitions */
 
 105 #define CG6_FBC_BLIT_IGNORE             0x00000000
 
 106 #define CG6_FBC_BLIT_NOSRC              0x00100000
 
 107 #define CG6_FBC_BLIT_SRC                0x00200000
 
 108 #define CG6_FBC_BLIT_ILLEGAL            0x00300000
 
 109 #define CG6_FBC_BLIT_MASK               0x00300000
 
 111 #define CG6_FBC_VBLANK                  0x00080000
 
 113 #define CG6_FBC_MODE_IGNORE             0x00000000
 
 114 #define CG6_FBC_MODE_COLOR8             0x00020000
 
 115 #define CG6_FBC_MODE_COLOR1             0x00040000
 
 116 #define CG6_FBC_MODE_HRMONO             0x00060000
 
 117 #define CG6_FBC_MODE_MASK               0x00060000
 
 119 #define CG6_FBC_DRAW_IGNORE             0x00000000
 
 120 #define CG6_FBC_DRAW_RENDER             0x00008000
 
 121 #define CG6_FBC_DRAW_PICK               0x00010000
 
 122 #define CG6_FBC_DRAW_ILLEGAL            0x00018000
 
 123 #define CG6_FBC_DRAW_MASK               0x00018000
 
 125 #define CG6_FBC_BWRITE0_IGNORE          0x00000000
 
 126 #define CG6_FBC_BWRITE0_ENABLE          0x00002000
 
 127 #define CG6_FBC_BWRITE0_DISABLE         0x00004000
 
 128 #define CG6_FBC_BWRITE0_ILLEGAL         0x00006000
 
 129 #define CG6_FBC_BWRITE0_MASK            0x00006000
 
 131 #define CG6_FBC_BWRITE1_IGNORE          0x00000000
 
 132 #define CG6_FBC_BWRITE1_ENABLE          0x00000800
 
 133 #define CG6_FBC_BWRITE1_DISABLE         0x00001000
 
 134 #define CG6_FBC_BWRITE1_ILLEGAL         0x00001800
 
 135 #define CG6_FBC_BWRITE1_MASK            0x00001800
 
 137 #define CG6_FBC_BREAD_IGNORE            0x00000000
 
 138 #define CG6_FBC_BREAD_0                 0x00000200
 
 139 #define CG6_FBC_BREAD_1                 0x00000400
 
 140 #define CG6_FBC_BREAD_ILLEGAL           0x00000600
 
 141 #define CG6_FBC_BREAD_MASK              0x00000600
 
 143 #define CG6_FBC_BDISP_IGNORE            0x00000000
 
 144 #define CG6_FBC_BDISP_0                 0x00000080
 
 145 #define CG6_FBC_BDISP_1                 0x00000100
 
 146 #define CG6_FBC_BDISP_ILLEGAL           0x00000180
 
 147 #define CG6_FBC_BDISP_MASK              0x00000180
 
 149 #define CG6_FBC_INDEX_MOD               0x00000040
 
 150 #define CG6_FBC_INDEX_MASK              0x00000030
 
 152 /* THC definitions */
 
 153 #define CG6_THC_MISC_REV_SHIFT          16
 
 154 #define CG6_THC_MISC_REV_MASK           15
 
 155 #define CG6_THC_MISC_RESET              (1 << 12)
 
 156 #define CG6_THC_MISC_VIDEO              (1 << 10)
 
 157 #define CG6_THC_MISC_SYNC               (1 << 9)
 
 158 #define CG6_THC_MISC_VSYNC              (1 << 8)
 
 159 #define CG6_THC_MISC_SYNC_ENAB          (1 << 7)
 
 160 #define CG6_THC_MISC_CURS_RES           (1 << 6)
 
 161 #define CG6_THC_MISC_INT_ENAB           (1 << 5)
 
 162 #define CG6_THC_MISC_INT                (1 << 4)
 
 163 #define CG6_THC_MISC_INIT               0x9f
 
 165 /* The contents are unknown */
 
 174         u32     thc_hs;         /* hsync timing */
 
 177         u32     thc_vs;         /* vsync timing */
 
 182         u32     thc_cursxy;     /* cursor x,y position (16 bits each) */
 
 183         u32     thc_cursmask[32];       /* cursor mask bits */
 
 184         u32     thc_cursbits[32];       /* what to show where mask enabled */
 
 197         u32     x0, y0, z0, color0;
 
 198         u32     x1, y1, z1, color1;
 
 199         u32     x2, y2, z2, color2;
 
 200         u32     x3, y3, z3, color3;
 
 205         u32     clipminx, clipminy;
 
 207         u32     clipmaxx, clipmaxy;
 
 218         u32     apointx, apointy, apointz;
 
 220         u32     rpointx, rpointy, rpointz;
 
 222         u32     pointr, pointg, pointb, pointa;
 
 223         u32     alinex, aliney, alinez;
 
 225         u32     rlinex, rliney, rlinez;
 
 227         u32     liner, lineg, lineb, linea;
 
 228         u32     atrix, atriy, atriz;
 
 230         u32     rtrix, rtriy, rtriz;
 
 232         u32     trir, trig, trib, tria;
 
 233         u32     aquadx, aquady, aquadz;
 
 235         u32     rquadx, rquady, rquadz;
 
 237         u32     quadr, quadg, quadb, quada;
 
 238         u32     arectx, arecty, arectz;
 
 240         u32     rrectx, rrecty, rrectz;
 
 242         u32     rectr, rectg, rectb, recta;
 
 254         struct bt_regs          __iomem *bt;
 
 255         struct cg6_fbc          __iomem *fbc;
 
 256         struct cg6_thc          __iomem *thc;
 
 257         struct cg6_tec          __iomem *tec;
 
 261 #define CG6_FLAG_BLANKED        0x00000001
 
 263         unsigned long           physbase;
 
 264         unsigned long           which_io;
 
 265         unsigned long           fbsize;
 
 268 static int cg6_sync(struct fb_info *info)
 
 270         struct cg6_par *par = (struct cg6_par *)info->par;
 
 271         struct cg6_fbc __iomem *fbc = par->fbc;
 
 275                 if (!(sbus_readl(&fbc->s) & 0x10000000))
 
 278         } while (--limit > 0);
 
 284  *      cg6_fillrect -  Draws a rectangle on the screen.
 
 286  *      @info: frame buffer structure that represents a single frame buffer
 
 287  *      @rect: structure defining the rectagle and operation.
 
 289 static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 
 291         struct cg6_par *par = (struct cg6_par *)info->par;
 
 292         struct cg6_fbc __iomem *fbc = par->fbc;
 
 296         /* CG6 doesn't handle ROP_XOR */
 
 298         spin_lock_irqsave(&par->lock, flags);
 
 302         sbus_writel(rect->color, &fbc->fg);
 
 303         sbus_writel(~(u32)0, &fbc->pixelm);
 
 304         sbus_writel(0xea80ff00, &fbc->alu);
 
 305         sbus_writel(0, &fbc->s);
 
 306         sbus_writel(0, &fbc->clip);
 
 307         sbus_writel(~(u32)0, &fbc->pm);
 
 308         sbus_writel(rect->dy, &fbc->arecty);
 
 309         sbus_writel(rect->dx, &fbc->arectx);
 
 310         sbus_writel(rect->dy + rect->height, &fbc->arecty);
 
 311         sbus_writel(rect->dx + rect->width, &fbc->arectx);
 
 313                 val = sbus_readl(&fbc->draw);
 
 314         } while (val < 0 && (val & 0x20000000));
 
 315         spin_unlock_irqrestore(&par->lock, flags);
 
 319  *      cg6_copyarea - Copies one area of the screen to another area.
 
 321  *      @info: frame buffer structure that represents a single frame buffer
 
 322  *      @area: Structure providing the data to copy the framebuffer contents
 
 323  *              from one region to another.
 
 325  *      This drawing operation copies a rectangular area from one area of the
 
 326  *      screen to another area.
 
 328 static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 
 330         struct cg6_par *par = (struct cg6_par *)info->par;
 
 331         struct cg6_fbc __iomem *fbc = par->fbc;
 
 335         spin_lock_irqsave(&par->lock, flags);
 
 339         sbus_writel(0xff, &fbc->fg);
 
 340         sbus_writel(0x00, &fbc->bg);
 
 341         sbus_writel(~0, &fbc->pixelm);
 
 342         sbus_writel(0xe880cccc, &fbc->alu);
 
 343         sbus_writel(0, &fbc->s);
 
 344         sbus_writel(0, &fbc->clip);
 
 346         sbus_writel(area->sy, &fbc->y0);
 
 347         sbus_writel(area->sx, &fbc->x0);
 
 348         sbus_writel(area->sy + area->height - 1, &fbc->y1);
 
 349         sbus_writel(area->sx + area->width - 1, &fbc->x1);
 
 350         sbus_writel(area->dy, &fbc->y2);
 
 351         sbus_writel(area->dx, &fbc->x2);
 
 352         sbus_writel(area->dy + area->height - 1, &fbc->y3);
 
 353         sbus_writel(area->dx + area->width - 1, &fbc->x3);
 
 355                 i = sbus_readl(&fbc->blit);
 
 356         } while (i < 0 && (i & 0x20000000));
 
 357         spin_unlock_irqrestore(&par->lock, flags);
 
 361  *      cg6_imageblit - Copies a image from system memory to the screen.
 
 363  *      @info: frame buffer structure that represents a single frame buffer
 
 364  *      @image: structure defining the image.
 
 366 static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
 
 368         struct cg6_par *par = (struct cg6_par *)info->par;
 
 369         struct cg6_fbc __iomem *fbc = par->fbc;
 
 370         const u8 *data = image->data;
 
 375         if (image->depth > 1) {
 
 376                 cfb_imageblit(info, image);
 
 380         spin_lock_irqsave(&par->lock, flags);
 
 384         sbus_writel(image->fg_color, &fbc->fg);
 
 385         sbus_writel(image->bg_color, &fbc->bg);
 
 386         sbus_writel(0x140000, &fbc->mode);
 
 387         sbus_writel(0xe880fc30, &fbc->alu);
 
 388         sbus_writel(~(u32)0, &fbc->pixelm);
 
 389         sbus_writel(0, &fbc->s);
 
 390         sbus_writel(0, &fbc->clip);
 
 391         sbus_writel(0xff, &fbc->pm);
 
 392         sbus_writel(32, &fbc->incx);
 
 393         sbus_writel(0, &fbc->incy);
 
 397         for (i = 0; i < image->height; i++) {
 
 398                 width = image->width;
 
 400                 while (width >= 32) {
 
 403                         sbus_writel(y, &fbc->y0);
 
 404                         sbus_writel(x, &fbc->x0);
 
 405                         sbus_writel(x + 32 - 1, &fbc->x1);
 
 407                         val = ((u32)data[0] << 24) |
 
 408                               ((u32)data[1] << 16) |
 
 409                               ((u32)data[2] <<  8) |
 
 411                         sbus_writel(val, &fbc->font);
 
 420                         sbus_writel(y, &fbc->y0);
 
 421                         sbus_writel(x, &fbc->x0);
 
 422                         sbus_writel(x + width - 1, &fbc->x1);
 
 424                                 val = (u32) data[0] << 24;
 
 426                         } else if (width <= 16) {
 
 427                                 val = ((u32) data[0] << 24) |
 
 428                                       ((u32) data[1] << 16);
 
 431                                 val = ((u32) data[0] << 24) |
 
 432                                       ((u32) data[1] << 16) |
 
 433                                       ((u32) data[2] <<  8);
 
 436                         sbus_writel(val, &fbc->font);
 
 443         spin_unlock_irqrestore(&par->lock, flags);
 
 447  *      cg6_setcolreg - Sets a color register.
 
 449  *      @regno: boolean, 0 copy local, 1 get_user() function
 
 450  *      @red: frame buffer colormap structure
 
 451  *      @green: The green value which can be up to 16 bits wide
 
 452  *      @blue:  The blue value which can be up to 16 bits wide.
 
 453  *      @transp: If supported the alpha value which can be up to 16 bits wide.
 
 454  *      @info: frame buffer info structure
 
 456 static int cg6_setcolreg(unsigned regno,
 
 457                          unsigned red, unsigned green, unsigned blue,
 
 458                          unsigned transp, struct fb_info *info)
 
 460         struct cg6_par *par = (struct cg6_par *)info->par;
 
 461         struct bt_regs __iomem *bt = par->bt;
 
 471         spin_lock_irqsave(&par->lock, flags);
 
 473         sbus_writel((u32)regno << 24, &bt->addr);
 
 474         sbus_writel((u32)red << 24, &bt->color_map);
 
 475         sbus_writel((u32)green << 24, &bt->color_map);
 
 476         sbus_writel((u32)blue << 24, &bt->color_map);
 
 478         spin_unlock_irqrestore(&par->lock, flags);
 
 484  *      cg6_blank - Blanks the display.
 
 486  *      @blank_mode: the blank mode we want.
 
 487  *      @info: frame buffer structure that represents a single frame buffer
 
 489 static int cg6_blank(int blank, struct fb_info *info)
 
 491         struct cg6_par *par = (struct cg6_par *)info->par;
 
 492         struct cg6_thc __iomem *thc = par->thc;
 
 496         spin_lock_irqsave(&par->lock, flags);
 
 497         val = sbus_readl(&thc->thc_misc);
 
 500         case FB_BLANK_UNBLANK: /* Unblanking */
 
 501                 val |= CG6_THC_MISC_VIDEO;
 
 502                 par->flags &= ~CG6_FLAG_BLANKED;
 
 505         case FB_BLANK_NORMAL: /* Normal blanking */
 
 506         case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
 
 507         case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
 
 508         case FB_BLANK_POWERDOWN: /* Poweroff */
 
 509                 val &= ~CG6_THC_MISC_VIDEO;
 
 510                 par->flags |= CG6_FLAG_BLANKED;
 
 514         sbus_writel(val, &thc->thc_misc);
 
 515         spin_unlock_irqrestore(&par->lock, flags);
 
 520 static struct sbus_mmap_map cg6_mmap_map[] = {
 
 523                 .poff   = CG6_FBC_OFFSET,
 
 528                 .poff   = CG6_TEC_OFFSET,
 
 533                 .poff   = CG6_BROOKTREE_OFFSET,
 
 538                 .poff   = CG6_FHC_OFFSET,
 
 543                 .poff   = CG6_THC_OFFSET,
 
 548                 .poff   = CG6_ROM_OFFSET,
 
 553                 .poff   = CG6_RAM_OFFSET,
 
 554                 .size   = SBUS_MMAP_FBSIZE(1)
 
 558                 .poff   = CG6_DHC_OFFSET,
 
 564 static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
 
 566         struct cg6_par *par = (struct cg6_par *)info->par;
 
 568         return sbusfb_mmap_helper(cg6_mmap_map,
 
 569                                   par->physbase, par->fbsize,
 
 573 static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 
 575         struct cg6_par *par = (struct cg6_par *)info->par;
 
 577         return sbusfb_ioctl_helper(cmd, arg, info,
 
 578                                    FBTYPE_SUNFAST_COLOR, 8, par->fbsize);
 
 585 static void __devinit cg6_init_fix(struct fb_info *info, int linebytes)
 
 587         struct cg6_par *par = (struct cg6_par *)info->par;
 
 588         const char *cg6_cpu_name, *cg6_card_name;
 
 591         conf = sbus_readl(par->fhc);
 
 592         switch (conf & CG6_FHC_CPU_MASK) {
 
 593         case CG6_FHC_CPU_SPARC:
 
 594                 cg6_cpu_name = "sparc";
 
 596         case CG6_FHC_CPU_68020:
 
 597                 cg6_cpu_name = "68020";
 
 600                 cg6_cpu_name = "i386";
 
 603         if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
 
 604                 if (par->fbsize <= 0x100000)
 
 605                         cg6_card_name = "TGX";
 
 607                         cg6_card_name = "TGX+";
 
 609                 if (par->fbsize <= 0x100000)
 
 610                         cg6_card_name = "GX";
 
 612                         cg6_card_name = "GX+";
 
 615         sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name);
 
 616         info->fix.id[sizeof(info->fix.id) - 1] = 0;
 
 618         info->fix.type = FB_TYPE_PACKED_PIXELS;
 
 619         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 
 621         info->fix.line_length = linebytes;
 
 623         info->fix.accel = FB_ACCEL_SUN_CGSIX;
 
 626 /* Initialize Brooktree DAC */
 
 627 static void __devinit cg6_bt_init(struct cg6_par *par)
 
 629         struct bt_regs __iomem *bt = par->bt;
 
 631         sbus_writel(0x04 << 24, &bt->addr);      /* color planes */
 
 632         sbus_writel(0xff << 24, &bt->control);
 
 633         sbus_writel(0x05 << 24, &bt->addr);
 
 634         sbus_writel(0x00 << 24, &bt->control);
 
 635         sbus_writel(0x06 << 24, &bt->addr);      /* overlay plane */
 
 636         sbus_writel(0x73 << 24, &bt->control);
 
 637         sbus_writel(0x07 << 24, &bt->addr);
 
 638         sbus_writel(0x00 << 24, &bt->control);
 
 641 static void __devinit cg6_chip_init(struct fb_info *info)
 
 643         struct cg6_par *par = (struct cg6_par *)info->par;
 
 644         struct cg6_tec __iomem *tec = par->tec;
 
 645         struct cg6_fbc __iomem *fbc = par->fbc;
 
 649         /* Turn off stuff in the Transform Engine. */
 
 650         sbus_writel(0, &tec->tec_matrix);
 
 651         sbus_writel(0, &tec->tec_clip);
 
 652         sbus_writel(0, &tec->tec_vdc);
 
 654         /* Take care of bugs in old revisions. */
 
 655         rev = (sbus_readl(par->fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
 
 657                 conf = (sbus_readl(par->fhc) & CG6_FHC_RES_MASK) |
 
 658                         CG6_FHC_CPU_68020 | CG6_FHC_TEST |
 
 659                         (11 << CG6_FHC_TEST_X_SHIFT) |
 
 660                         (11 << CG6_FHC_TEST_Y_SHIFT);
 
 662                         conf |= CG6_FHC_DST_DISABLE;
 
 663                 sbus_writel(conf, par->fhc);
 
 666         /* Set things in the FBC. Bad things appear to happen if we do
 
 667          * back to back store/loads on the mode register, so copy it
 
 669         mode = sbus_readl(&fbc->mode);
 
 671                 i = sbus_readl(&fbc->s);
 
 672         } while (i & 0x10000000);
 
 673         mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
 
 674                   CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
 
 675                   CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
 
 677         mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
 
 678                  CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
 
 679                  CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
 
 681         sbus_writel(mode, &fbc->mode);
 
 683         sbus_writel(0, &fbc->clip);
 
 684         sbus_writel(0, &fbc->offx);
 
 685         sbus_writel(0, &fbc->offy);
 
 686         sbus_writel(0, &fbc->clipminx);
 
 687         sbus_writel(0, &fbc->clipminy);
 
 688         sbus_writel(info->var.xres - 1, &fbc->clipmaxx);
 
 689         sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
 
 692 static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
 
 696                 of_iounmap(&op->resource[0], par->fbc, 4096);
 
 698                 of_iounmap(&op->resource[0], par->tec, sizeof(struct cg6_tec));
 
 700                 of_iounmap(&op->resource[0], par->thc, sizeof(struct cg6_thc));
 
 702                 of_iounmap(&op->resource[0], par->bt, sizeof(struct bt_regs));
 
 704                 of_iounmap(&op->resource[0], par->fhc, sizeof(u32));
 
 706         if (info->screen_base)
 
 707                 of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
 
 710 static int __devinit cg6_probe(struct of_device *op,
 
 711                                 const struct of_device_id *match)
 
 713         struct device_node *dp = op->node;
 
 714         struct fb_info *info;
 
 719         info = framebuffer_alloc(sizeof(struct cg6_par), &op->dev);
 
 726         spin_lock_init(&par->lock);
 
 728         par->physbase = op->resource[0].start;
 
 729         par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
 731         sbusfb_fill_var(&info->var, dp->node, 8);
 
 732         info->var.red.length = 8;
 
 733         info->var.green.length = 8;
 
 734         info->var.blue.length = 8;
 
 736         linebytes = of_getintprop_default(dp, "linebytes",
 
 738         par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
 
 740         dblbuf = of_getintprop_default(dp, "dblbuf", 0);
 
 744         par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
 
 746         par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
 
 747                                 sizeof(struct cg6_tec), "cgsix tec");
 
 748         par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
 
 749                                 sizeof(struct cg6_thc), "cgsix thc");
 
 750         par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
 
 751                                 sizeof(struct bt_regs), "cgsix dac");
 
 752         par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
 
 753                                 sizeof(u32), "cgsix fhc");
 
 755         info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
 
 756                         FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
 
 758         info->fbops = &cg6_ops;
 
 760         info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
 
 761                                         par->fbsize, "cgsix ram");
 
 762         if (!par->fbc || !par->tec || !par->thc ||
 
 763             !par->bt || !par->fhc || !info->screen_base)
 
 766         info->var.accel_flags = FB_ACCELF_TEXT;
 
 772         if (fb_alloc_cmap(&info->cmap, 256, 0))
 
 775         fb_set_cmap(&info->cmap, info);
 
 776         cg6_init_fix(info, linebytes);
 
 778         err = register_framebuffer(info);
 
 780                 goto out_dealloc_cmap;
 
 782         dev_set_drvdata(&op->dev, info);
 
 784         printk("%s: CGsix [%s] at %lx:%lx\n",
 
 785                dp->full_name, info->fix.id,
 
 786                par->which_io, par->physbase);
 
 791         fb_dealloc_cmap(&info->cmap);
 
 794         cg6_unmap_regs(op, info, par);
 
 800 static int __devexit cg6_remove(struct of_device *op)
 
 802         struct fb_info *info = dev_get_drvdata(&op->dev);
 
 803         struct cg6_par *par = info->par;
 
 805         unregister_framebuffer(info);
 
 806         fb_dealloc_cmap(&info->cmap);
 
 808         cg6_unmap_regs(op, info, par);
 
 810         framebuffer_release(info);
 
 812         dev_set_drvdata(&op->dev, NULL);
 
 817 static struct of_device_id cg6_match[] = {
 
 826 MODULE_DEVICE_TABLE(of, cg6_match);
 
 828 static struct of_platform_driver cg6_driver = {
 
 830         .match_table    = cg6_match,
 
 832         .remove         = __devexit_p(cg6_remove),
 
 835 static int __init cg6_init(void)
 
 837         if (fb_get_options("cg6fb", NULL))
 
 840         return of_register_driver(&cg6_driver, &of_bus_type);
 
 843 static void __exit cg6_exit(void)
 
 845         of_unregister_driver(&cg6_driver);
 
 848 module_init(cg6_init);
 
 849 module_exit(cg6_exit);
 
 851 MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets");
 
 852 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
 
 853 MODULE_VERSION("2.0");
 
 854 MODULE_LICENSE("GPL");