root/drivers/video/fbdev/cg6.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cg6_sync
  2. cg6_switch_from_graph
  3. cg6_pan_display
  4. cg6_fillrect
  5. cg6_copyarea
  6. cg6_imageblit
  7. cg6_setcolreg
  8. cg6_blank
  9. cg6_mmap
  10. cg6_ioctl
  11. cg6_init_fix
  12. cg6_bt_init
  13. cg6_chip_init
  14. cg6_unmap_regs
  15. cg6_probe
  16. cg6_remove
  17. cg6_init
  18. cg6_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* cg6.c: CGSIX (GX, GXplus, TGX) frame buffer driver
   3  *
   4  * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
   5  * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
   6  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
   7  * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
   8  *
   9  * Driver layout based loosely on tgafb.c, see that file for credits.
  10  */
  11 
  12 #include <linux/module.h>
  13 #include <linux/kernel.h>
  14 #include <linux/errno.h>
  15 #include <linux/string.h>
  16 #include <linux/delay.h>
  17 #include <linux/init.h>
  18 #include <linux/fb.h>
  19 #include <linux/mm.h>
  20 #include <linux/of_device.h>
  21 
  22 #include <asm/io.h>
  23 #include <asm/fbio.h>
  24 
  25 #include "sbuslib.h"
  26 
  27 /*
  28  * Local functions.
  29  */
  30 
  31 static int cg6_setcolreg(unsigned, unsigned, unsigned, unsigned,
  32                          unsigned, struct fb_info *);
  33 static int cg6_blank(int, struct fb_info *);
  34 
  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 void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
  38 static int cg6_sync(struct fb_info *);
  39 static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
  40 static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
  41 static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *);
  42 
  43 /*
  44  *  Frame buffer operations
  45  */
  46 
  47 static struct fb_ops cg6_ops = {
  48         .owner                  = THIS_MODULE,
  49         .fb_setcolreg           = cg6_setcolreg,
  50         .fb_blank               = cg6_blank,
  51         .fb_pan_display         = cg6_pan_display,
  52         .fb_fillrect            = cg6_fillrect,
  53         .fb_copyarea            = cg6_copyarea,
  54         .fb_imageblit           = cg6_imageblit,
  55         .fb_sync                = cg6_sync,
  56         .fb_mmap                = cg6_mmap,
  57         .fb_ioctl               = cg6_ioctl,
  58 #ifdef CONFIG_COMPAT
  59         .fb_compat_ioctl        = sbusfb_compat_ioctl,
  60 #endif
  61 };
  62 
  63 /* Offset of interesting structures in the OBIO space */
  64 /*
  65  * Brooktree is the video dac and is funny to program on the cg6.
  66  * (it's even funnier on the cg3)
  67  * The FBC could be the frame buffer control
  68  * The FHC could is the frame buffer hardware control.
  69  */
  70 #define CG6_ROM_OFFSET                  0x0UL
  71 #define CG6_BROOKTREE_OFFSET            0x200000UL
  72 #define CG6_DHC_OFFSET                  0x240000UL
  73 #define CG6_ALT_OFFSET                  0x280000UL
  74 #define CG6_FHC_OFFSET                  0x300000UL
  75 #define CG6_THC_OFFSET                  0x301000UL
  76 #define CG6_FBC_OFFSET                  0x700000UL
  77 #define CG6_TEC_OFFSET                  0x701000UL
  78 #define CG6_RAM_OFFSET                  0x800000UL
  79 
  80 /* FHC definitions */
  81 #define CG6_FHC_FBID_SHIFT              24
  82 #define CG6_FHC_FBID_MASK               255
  83 #define CG6_FHC_REV_SHIFT               20
  84 #define CG6_FHC_REV_MASK                15
  85 #define CG6_FHC_FROP_DISABLE            (1 << 19)
  86 #define CG6_FHC_ROW_DISABLE             (1 << 18)
  87 #define CG6_FHC_SRC_DISABLE             (1 << 17)
  88 #define CG6_FHC_DST_DISABLE             (1 << 16)
  89 #define CG6_FHC_RESET                   (1 << 15)
  90 #define CG6_FHC_LITTLE_ENDIAN           (1 << 13)
  91 #define CG6_FHC_RES_MASK                (3 << 11)
  92 #define CG6_FHC_1024                    (0 << 11)
  93 #define CG6_FHC_1152                    (1 << 11)
  94 #define CG6_FHC_1280                    (2 << 11)
  95 #define CG6_FHC_1600                    (3 << 11)
  96 #define CG6_FHC_CPU_MASK                (3 << 9)
  97 #define CG6_FHC_CPU_SPARC               (0 << 9)
  98 #define CG6_FHC_CPU_68020               (1 << 9)
  99 #define CG6_FHC_CPU_386                 (2 << 9)
 100 #define CG6_FHC_TEST                    (1 << 8)
 101 #define CG6_FHC_TEST_X_SHIFT            4
 102 #define CG6_FHC_TEST_X_MASK             15
 103 #define CG6_FHC_TEST_Y_SHIFT            0
 104 #define CG6_FHC_TEST_Y_MASK             15
 105 
 106 /* FBC mode definitions */
 107 #define CG6_FBC_BLIT_IGNORE             0x00000000
 108 #define CG6_FBC_BLIT_NOSRC              0x00100000
 109 #define CG6_FBC_BLIT_SRC                0x00200000
 110 #define CG6_FBC_BLIT_ILLEGAL            0x00300000
 111 #define CG6_FBC_BLIT_MASK               0x00300000
 112 
 113 #define CG6_FBC_VBLANK                  0x00080000
 114 
 115 #define CG6_FBC_MODE_IGNORE             0x00000000
 116 #define CG6_FBC_MODE_COLOR8             0x00020000
 117 #define CG6_FBC_MODE_COLOR1             0x00040000
 118 #define CG6_FBC_MODE_HRMONO             0x00060000
 119 #define CG6_FBC_MODE_MASK               0x00060000
 120 
 121 #define CG6_FBC_DRAW_IGNORE             0x00000000
 122 #define CG6_FBC_DRAW_RENDER             0x00008000
 123 #define CG6_FBC_DRAW_PICK               0x00010000
 124 #define CG6_FBC_DRAW_ILLEGAL            0x00018000
 125 #define CG6_FBC_DRAW_MASK               0x00018000
 126 
 127 #define CG6_FBC_BWRITE0_IGNORE          0x00000000
 128 #define CG6_FBC_BWRITE0_ENABLE          0x00002000
 129 #define CG6_FBC_BWRITE0_DISABLE         0x00004000
 130 #define CG6_FBC_BWRITE0_ILLEGAL         0x00006000
 131 #define CG6_FBC_BWRITE0_MASK            0x00006000
 132 
 133 #define CG6_FBC_BWRITE1_IGNORE          0x00000000
 134 #define CG6_FBC_BWRITE1_ENABLE          0x00000800
 135 #define CG6_FBC_BWRITE1_DISABLE         0x00001000
 136 #define CG6_FBC_BWRITE1_ILLEGAL         0x00001800
 137 #define CG6_FBC_BWRITE1_MASK            0x00001800
 138 
 139 #define CG6_FBC_BREAD_IGNORE            0x00000000
 140 #define CG6_FBC_BREAD_0                 0x00000200
 141 #define CG6_FBC_BREAD_1                 0x00000400
 142 #define CG6_FBC_BREAD_ILLEGAL           0x00000600
 143 #define CG6_FBC_BREAD_MASK              0x00000600
 144 
 145 #define CG6_FBC_BDISP_IGNORE            0x00000000
 146 #define CG6_FBC_BDISP_0                 0x00000080
 147 #define CG6_FBC_BDISP_1                 0x00000100
 148 #define CG6_FBC_BDISP_ILLEGAL           0x00000180
 149 #define CG6_FBC_BDISP_MASK              0x00000180
 150 
 151 #define CG6_FBC_INDEX_MOD               0x00000040
 152 #define CG6_FBC_INDEX_MASK              0x00000030
 153 
 154 /* THC definitions */
 155 #define CG6_THC_MISC_REV_SHIFT          16
 156 #define CG6_THC_MISC_REV_MASK           15
 157 #define CG6_THC_MISC_RESET              (1 << 12)
 158 #define CG6_THC_MISC_VIDEO              (1 << 10)
 159 #define CG6_THC_MISC_SYNC               (1 << 9)
 160 #define CG6_THC_MISC_VSYNC              (1 << 8)
 161 #define CG6_THC_MISC_SYNC_ENAB          (1 << 7)
 162 #define CG6_THC_MISC_CURS_RES           (1 << 6)
 163 #define CG6_THC_MISC_INT_ENAB           (1 << 5)
 164 #define CG6_THC_MISC_INT                (1 << 4)
 165 #define CG6_THC_MISC_INIT               0x9f
 166 #define CG6_THC_CURSOFF                 ((65536-32) | ((65536-32) << 16))
 167 
 168 /* The contents are unknown */
 169 struct cg6_tec {
 170         int tec_matrix;
 171         int tec_clip;
 172         int tec_vdc;
 173 };
 174 
 175 struct cg6_thc {
 176         u32     thc_pad0[512];
 177         u32     thc_hs;         /* hsync timing */
 178         u32     thc_hsdvs;
 179         u32     thc_hd;
 180         u32     thc_vs;         /* vsync timing */
 181         u32     thc_vd;
 182         u32     thc_refresh;
 183         u32     thc_misc;
 184         u32     thc_pad1[56];
 185         u32     thc_cursxy;     /* cursor x,y position (16 bits each) */
 186         u32     thc_cursmask[32];       /* cursor mask bits */
 187         u32     thc_cursbits[32];       /* what to show where mask enabled */
 188 };
 189 
 190 struct cg6_fbc {
 191         u32     xxx0[1];
 192         u32     mode;
 193         u32     clip;
 194         u32     xxx1[1];
 195         u32     s;
 196         u32     draw;
 197         u32     blit;
 198         u32     font;
 199         u32     xxx2[24];
 200         u32     x0, y0, z0, color0;
 201         u32     x1, y1, z1, color1;
 202         u32     x2, y2, z2, color2;
 203         u32     x3, y3, z3, color3;
 204         u32     offx, offy;
 205         u32     xxx3[2];
 206         u32     incx, incy;
 207         u32     xxx4[2];
 208         u32     clipminx, clipminy;
 209         u32     xxx5[2];
 210         u32     clipmaxx, clipmaxy;
 211         u32     xxx6[2];
 212         u32     fg;
 213         u32     bg;
 214         u32     alu;
 215         u32     pm;
 216         u32     pixelm;
 217         u32     xxx7[2];
 218         u32     patalign;
 219         u32     pattern[8];
 220         u32     xxx8[432];
 221         u32     apointx, apointy, apointz;
 222         u32     xxx9[1];
 223         u32     rpointx, rpointy, rpointz;
 224         u32     xxx10[5];
 225         u32     pointr, pointg, pointb, pointa;
 226         u32     alinex, aliney, alinez;
 227         u32     xxx11[1];
 228         u32     rlinex, rliney, rlinez;
 229         u32     xxx12[5];
 230         u32     liner, lineg, lineb, linea;
 231         u32     atrix, atriy, atriz;
 232         u32     xxx13[1];
 233         u32     rtrix, rtriy, rtriz;
 234         u32     xxx14[5];
 235         u32     trir, trig, trib, tria;
 236         u32     aquadx, aquady, aquadz;
 237         u32     xxx15[1];
 238         u32     rquadx, rquady, rquadz;
 239         u32     xxx16[5];
 240         u32     quadr, quadg, quadb, quada;
 241         u32     arectx, arecty, arectz;
 242         u32     xxx17[1];
 243         u32     rrectx, rrecty, rrectz;
 244         u32     xxx18[5];
 245         u32     rectr, rectg, rectb, recta;
 246 };
 247 
 248 struct bt_regs {
 249         u32     addr;
 250         u32     color_map;
 251         u32     control;
 252         u32     cursor;
 253 };
 254 
 255 struct cg6_par {
 256         spinlock_t              lock;
 257         struct bt_regs          __iomem *bt;
 258         struct cg6_fbc          __iomem *fbc;
 259         struct cg6_thc          __iomem *thc;
 260         struct cg6_tec          __iomem *tec;
 261         u32                     __iomem *fhc;
 262 
 263         u32                     flags;
 264 #define CG6_FLAG_BLANKED        0x00000001
 265 
 266         unsigned long           which_io;
 267 };
 268 
 269 static int cg6_sync(struct fb_info *info)
 270 {
 271         struct cg6_par *par = (struct cg6_par *)info->par;
 272         struct cg6_fbc __iomem *fbc = par->fbc;
 273         int limit = 10000;
 274 
 275         do {
 276                 if (!(sbus_readl(&fbc->s) & 0x10000000))
 277                         break;
 278                 udelay(10);
 279         } while (--limit > 0);
 280 
 281         return 0;
 282 }
 283 
 284 static void cg6_switch_from_graph(struct cg6_par *par)
 285 {
 286         struct cg6_thc __iomem *thc = par->thc;
 287         unsigned long flags;
 288 
 289         spin_lock_irqsave(&par->lock, flags);
 290 
 291         /* Hide the cursor. */
 292         sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
 293 
 294         spin_unlock_irqrestore(&par->lock, flags);
 295 }
 296 
 297 static int cg6_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 298 {
 299         struct cg6_par *par = (struct cg6_par *)info->par;
 300 
 301         /* We just use this to catch switches out of
 302          * graphics mode.
 303          */
 304         cg6_switch_from_graph(par);
 305 
 306         if (var->xoffset || var->yoffset || var->vmode)
 307                 return -EINVAL;
 308         return 0;
 309 }
 310 
 311 /**
 312  *      cg6_fillrect -  Draws a rectangle on the screen.
 313  *
 314  *      @info: frame buffer structure that represents a single frame buffer
 315  *      @rect: structure defining the rectagle and operation.
 316  */
 317 static void cg6_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 318 {
 319         struct cg6_par *par = (struct cg6_par *)info->par;
 320         struct cg6_fbc __iomem *fbc = par->fbc;
 321         unsigned long flags;
 322         s32 val;
 323 
 324         /* CG6 doesn't handle ROP_XOR */
 325 
 326         spin_lock_irqsave(&par->lock, flags);
 327 
 328         cg6_sync(info);
 329 
 330         sbus_writel(rect->color, &fbc->fg);
 331         sbus_writel(~(u32)0, &fbc->pixelm);
 332         sbus_writel(0xea80ff00, &fbc->alu);
 333         sbus_writel(0, &fbc->s);
 334         sbus_writel(0, &fbc->clip);
 335         sbus_writel(~(u32)0, &fbc->pm);
 336         sbus_writel(rect->dy, &fbc->arecty);
 337         sbus_writel(rect->dx, &fbc->arectx);
 338         sbus_writel(rect->dy + rect->height, &fbc->arecty);
 339         sbus_writel(rect->dx + rect->width, &fbc->arectx);
 340         do {
 341                 val = sbus_readl(&fbc->draw);
 342         } while (val < 0 && (val & 0x20000000));
 343         spin_unlock_irqrestore(&par->lock, flags);
 344 }
 345 
 346 /**
 347  *      cg6_copyarea - Copies one area of the screen to another area.
 348  *
 349  *      @info: frame buffer structure that represents a single frame buffer
 350  *      @area: Structure providing the data to copy the framebuffer contents
 351  *              from one region to another.
 352  *
 353  *      This drawing operation copies a rectangular area from one area of the
 354  *      screen to another area.
 355  */
 356 static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 357 {
 358         struct cg6_par *par = (struct cg6_par *)info->par;
 359         struct cg6_fbc __iomem *fbc = par->fbc;
 360         unsigned long flags;
 361         int i;
 362 
 363         spin_lock_irqsave(&par->lock, flags);
 364 
 365         cg6_sync(info);
 366 
 367         sbus_writel(0xff, &fbc->fg);
 368         sbus_writel(0x00, &fbc->bg);
 369         sbus_writel(~0, &fbc->pixelm);
 370         sbus_writel(0xe880cccc, &fbc->alu);
 371         sbus_writel(0, &fbc->s);
 372         sbus_writel(0, &fbc->clip);
 373 
 374         sbus_writel(area->sy, &fbc->y0);
 375         sbus_writel(area->sx, &fbc->x0);
 376         sbus_writel(area->sy + area->height - 1, &fbc->y1);
 377         sbus_writel(area->sx + area->width - 1, &fbc->x1);
 378         sbus_writel(area->dy, &fbc->y2);
 379         sbus_writel(area->dx, &fbc->x2);
 380         sbus_writel(area->dy + area->height - 1, &fbc->y3);
 381         sbus_writel(area->dx + area->width - 1, &fbc->x3);
 382         do {
 383                 i = sbus_readl(&fbc->blit);
 384         } while (i < 0 && (i & 0x20000000));
 385         spin_unlock_irqrestore(&par->lock, flags);
 386 }
 387 
 388 /**
 389  *      cg6_imageblit - Copies a image from system memory to the screen.
 390  *
 391  *      @info: frame buffer structure that represents a single frame buffer
 392  *      @image: structure defining the image.
 393  */
 394 static void cg6_imageblit(struct fb_info *info, const struct fb_image *image)
 395 {
 396         struct cg6_par *par = (struct cg6_par *)info->par;
 397         struct cg6_fbc __iomem *fbc = par->fbc;
 398         const u8 *data = image->data;
 399         unsigned long flags;
 400         u32 x, y;
 401         int i, width;
 402 
 403         if (image->depth > 1) {
 404                 cfb_imageblit(info, image);
 405                 return;
 406         }
 407 
 408         spin_lock_irqsave(&par->lock, flags);
 409 
 410         cg6_sync(info);
 411 
 412         sbus_writel(image->fg_color, &fbc->fg);
 413         sbus_writel(image->bg_color, &fbc->bg);
 414         sbus_writel(0x140000, &fbc->mode);
 415         sbus_writel(0xe880fc30, &fbc->alu);
 416         sbus_writel(~(u32)0, &fbc->pixelm);
 417         sbus_writel(0, &fbc->s);
 418         sbus_writel(0, &fbc->clip);
 419         sbus_writel(0xff, &fbc->pm);
 420         sbus_writel(32, &fbc->incx);
 421         sbus_writel(0, &fbc->incy);
 422 
 423         x = image->dx;
 424         y = image->dy;
 425         for (i = 0; i < image->height; i++) {
 426                 width = image->width;
 427 
 428                 while (width >= 32) {
 429                         u32 val;
 430 
 431                         sbus_writel(y, &fbc->y0);
 432                         sbus_writel(x, &fbc->x0);
 433                         sbus_writel(x + 32 - 1, &fbc->x1);
 434 
 435                         val = ((u32)data[0] << 24) |
 436                               ((u32)data[1] << 16) |
 437                               ((u32)data[2] <<  8) |
 438                               ((u32)data[3] <<  0);
 439                         sbus_writel(val, &fbc->font);
 440 
 441                         data += 4;
 442                         x += 32;
 443                         width -= 32;
 444                 }
 445                 if (width) {
 446                         u32 val;
 447 
 448                         sbus_writel(y, &fbc->y0);
 449                         sbus_writel(x, &fbc->x0);
 450                         sbus_writel(x + width - 1, &fbc->x1);
 451                         if (width <= 8) {
 452                                 val = (u32) data[0] << 24;
 453                                 data += 1;
 454                         } else if (width <= 16) {
 455                                 val = ((u32) data[0] << 24) |
 456                                       ((u32) data[1] << 16);
 457                                 data += 2;
 458                         } else {
 459                                 val = ((u32) data[0] << 24) |
 460                                       ((u32) data[1] << 16) |
 461                                       ((u32) data[2] <<  8);
 462                                 data += 3;
 463                         }
 464                         sbus_writel(val, &fbc->font);
 465                 }
 466 
 467                 y += 1;
 468                 x = image->dx;
 469         }
 470 
 471         spin_unlock_irqrestore(&par->lock, flags);
 472 }
 473 
 474 /**
 475  *      cg6_setcolreg - Sets a color register.
 476  *
 477  *      @regno: boolean, 0 copy local, 1 get_user() function
 478  *      @red: frame buffer colormap structure
 479  *      @green: The green value which can be up to 16 bits wide
 480  *      @blue:  The blue value which can be up to 16 bits wide.
 481  *      @transp: If supported the alpha value which can be up to 16 bits wide.
 482  *      @info: frame buffer info structure
 483  */
 484 static int cg6_setcolreg(unsigned regno,
 485                          unsigned red, unsigned green, unsigned blue,
 486                          unsigned transp, struct fb_info *info)
 487 {
 488         struct cg6_par *par = (struct cg6_par *)info->par;
 489         struct bt_regs __iomem *bt = par->bt;
 490         unsigned long flags;
 491 
 492         if (regno >= 256)
 493                 return 1;
 494 
 495         red >>= 8;
 496         green >>= 8;
 497         blue >>= 8;
 498 
 499         spin_lock_irqsave(&par->lock, flags);
 500 
 501         sbus_writel((u32)regno << 24, &bt->addr);
 502         sbus_writel((u32)red << 24, &bt->color_map);
 503         sbus_writel((u32)green << 24, &bt->color_map);
 504         sbus_writel((u32)blue << 24, &bt->color_map);
 505 
 506         spin_unlock_irqrestore(&par->lock, flags);
 507 
 508         return 0;
 509 }
 510 
 511 /**
 512  *      cg6_blank - Blanks the display.
 513  *
 514  *      @blank_mode: the blank mode we want.
 515  *      @info: frame buffer structure that represents a single frame buffer
 516  */
 517 static int cg6_blank(int blank, struct fb_info *info)
 518 {
 519         struct cg6_par *par = (struct cg6_par *)info->par;
 520         struct cg6_thc __iomem *thc = par->thc;
 521         unsigned long flags;
 522         u32 val;
 523 
 524         spin_lock_irqsave(&par->lock, flags);
 525         val = sbus_readl(&thc->thc_misc);
 526 
 527         switch (blank) {
 528         case FB_BLANK_UNBLANK: /* Unblanking */
 529                 val |= CG6_THC_MISC_VIDEO;
 530                 par->flags &= ~CG6_FLAG_BLANKED;
 531                 break;
 532 
 533         case FB_BLANK_NORMAL: /* Normal blanking */
 534         case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
 535         case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
 536         case FB_BLANK_POWERDOWN: /* Poweroff */
 537                 val &= ~CG6_THC_MISC_VIDEO;
 538                 par->flags |= CG6_FLAG_BLANKED;
 539                 break;
 540         }
 541 
 542         sbus_writel(val, &thc->thc_misc);
 543         spin_unlock_irqrestore(&par->lock, flags);
 544 
 545         return 0;
 546 }
 547 
 548 static struct sbus_mmap_map cg6_mmap_map[] = {
 549         {
 550                 .voff   = CG6_FBC,
 551                 .poff   = CG6_FBC_OFFSET,
 552                 .size   = PAGE_SIZE
 553         },
 554         {
 555                 .voff   = CG6_TEC,
 556                 .poff   = CG6_TEC_OFFSET,
 557                 .size   = PAGE_SIZE
 558         },
 559         {
 560                 .voff   = CG6_BTREGS,
 561                 .poff   = CG6_BROOKTREE_OFFSET,
 562                 .size   = PAGE_SIZE
 563         },
 564         {
 565                 .voff   = CG6_FHC,
 566                 .poff   = CG6_FHC_OFFSET,
 567                 .size   = PAGE_SIZE
 568         },
 569         {
 570                 .voff   = CG6_THC,
 571                 .poff   = CG6_THC_OFFSET,
 572                 .size   = PAGE_SIZE
 573         },
 574         {
 575                 .voff   = CG6_ROM,
 576                 .poff   = CG6_ROM_OFFSET,
 577                 .size   = 0x10000
 578         },
 579         {
 580                 .voff   = CG6_RAM,
 581                 .poff   = CG6_RAM_OFFSET,
 582                 .size   = SBUS_MMAP_FBSIZE(1)
 583         },
 584         {
 585                 .voff   = CG6_DHC,
 586                 .poff   = CG6_DHC_OFFSET,
 587                 .size   = 0x40000
 588         },
 589         { .size = 0 }
 590 };
 591 
 592 static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
 593 {
 594         struct cg6_par *par = (struct cg6_par *)info->par;
 595 
 596         return sbusfb_mmap_helper(cg6_mmap_map,
 597                                   info->fix.smem_start, info->fix.smem_len,
 598                                   par->which_io, vma);
 599 }
 600 
 601 static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 602 {
 603         return sbusfb_ioctl_helper(cmd, arg, info,
 604                                    FBTYPE_SUNFAST_COLOR, 8, info->fix.smem_len);
 605 }
 606 
 607 /*
 608  *  Initialisation
 609  */
 610 
 611 static void cg6_init_fix(struct fb_info *info, int linebytes)
 612 {
 613         struct cg6_par *par = (struct cg6_par *)info->par;
 614         const char *cg6_cpu_name, *cg6_card_name;
 615         u32 conf;
 616 
 617         conf = sbus_readl(par->fhc);
 618         switch (conf & CG6_FHC_CPU_MASK) {
 619         case CG6_FHC_CPU_SPARC:
 620                 cg6_cpu_name = "sparc";
 621                 break;
 622         case CG6_FHC_CPU_68020:
 623                 cg6_cpu_name = "68020";
 624                 break;
 625         default:
 626                 cg6_cpu_name = "i386";
 627                 break;
 628         }
 629         if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
 630                 if (info->fix.smem_len <= 0x100000)
 631                         cg6_card_name = "TGX";
 632                 else
 633                         cg6_card_name = "TGX+";
 634         } else {
 635                 if (info->fix.smem_len <= 0x100000)
 636                         cg6_card_name = "GX";
 637                 else
 638                         cg6_card_name = "GX+";
 639         }
 640 
 641         sprintf(info->fix.id, "%s %s", cg6_card_name, cg6_cpu_name);
 642         info->fix.id[sizeof(info->fix.id) - 1] = 0;
 643 
 644         info->fix.type = FB_TYPE_PACKED_PIXELS;
 645         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 646 
 647         info->fix.line_length = linebytes;
 648 
 649         info->fix.accel = FB_ACCEL_SUN_CGSIX;
 650 }
 651 
 652 /* Initialize Brooktree DAC */
 653 static void cg6_bt_init(struct cg6_par *par)
 654 {
 655         struct bt_regs __iomem *bt = par->bt;
 656 
 657         sbus_writel(0x04 << 24, &bt->addr);      /* color planes */
 658         sbus_writel(0xff << 24, &bt->control);
 659         sbus_writel(0x05 << 24, &bt->addr);
 660         sbus_writel(0x00 << 24, &bt->control);
 661         sbus_writel(0x06 << 24, &bt->addr);      /* overlay plane */
 662         sbus_writel(0x73 << 24, &bt->control);
 663         sbus_writel(0x07 << 24, &bt->addr);
 664         sbus_writel(0x00 << 24, &bt->control);
 665 }
 666 
 667 static void cg6_chip_init(struct fb_info *info)
 668 {
 669         struct cg6_par *par = (struct cg6_par *)info->par;
 670         struct cg6_tec __iomem *tec = par->tec;
 671         struct cg6_fbc __iomem *fbc = par->fbc;
 672         struct cg6_thc __iomem *thc = par->thc;
 673         u32 rev, conf, mode;
 674         int i;
 675 
 676         /* Hide the cursor. */
 677         sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
 678 
 679         /* Turn off stuff in the Transform Engine. */
 680         sbus_writel(0, &tec->tec_matrix);
 681         sbus_writel(0, &tec->tec_clip);
 682         sbus_writel(0, &tec->tec_vdc);
 683 
 684         /* Take care of bugs in old revisions. */
 685         rev = (sbus_readl(par->fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
 686         if (rev < 5) {
 687                 conf = (sbus_readl(par->fhc) & CG6_FHC_RES_MASK) |
 688                         CG6_FHC_CPU_68020 | CG6_FHC_TEST |
 689                         (11 << CG6_FHC_TEST_X_SHIFT) |
 690                         (11 << CG6_FHC_TEST_Y_SHIFT);
 691                 if (rev < 2)
 692                         conf |= CG6_FHC_DST_DISABLE;
 693                 sbus_writel(conf, par->fhc);
 694         }
 695 
 696         /* Set things in the FBC. Bad things appear to happen if we do
 697          * back to back store/loads on the mode register, so copy it
 698          * out instead. */
 699         mode = sbus_readl(&fbc->mode);
 700         do {
 701                 i = sbus_readl(&fbc->s);
 702         } while (i & 0x10000000);
 703         mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
 704                   CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
 705                   CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
 706                   CG6_FBC_BDISP_MASK);
 707         mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
 708                  CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
 709                  CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
 710                  CG6_FBC_BDISP_0);
 711         sbus_writel(mode, &fbc->mode);
 712 
 713         sbus_writel(0, &fbc->clip);
 714         sbus_writel(0, &fbc->offx);
 715         sbus_writel(0, &fbc->offy);
 716         sbus_writel(0, &fbc->clipminx);
 717         sbus_writel(0, &fbc->clipminy);
 718         sbus_writel(info->var.xres - 1, &fbc->clipmaxx);
 719         sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
 720 }
 721 
 722 static void cg6_unmap_regs(struct platform_device *op, struct fb_info *info,
 723                            struct cg6_par *par)
 724 {
 725         if (par->fbc)
 726                 of_iounmap(&op->resource[0], par->fbc, 4096);
 727         if (par->tec)
 728                 of_iounmap(&op->resource[0], par->tec, sizeof(struct cg6_tec));
 729         if (par->thc)
 730                 of_iounmap(&op->resource[0], par->thc, sizeof(struct cg6_thc));
 731         if (par->bt)
 732                 of_iounmap(&op->resource[0], par->bt, sizeof(struct bt_regs));
 733         if (par->fhc)
 734                 of_iounmap(&op->resource[0], par->fhc, sizeof(u32));
 735 
 736         if (info->screen_base)
 737                 of_iounmap(&op->resource[0], info->screen_base,
 738                            info->fix.smem_len);
 739 }
 740 
 741 static int cg6_probe(struct platform_device *op)
 742 {
 743         struct device_node *dp = op->dev.of_node;
 744         struct fb_info *info;
 745         struct cg6_par *par;
 746         int linebytes, err;
 747         int dblbuf;
 748 
 749         info = framebuffer_alloc(sizeof(struct cg6_par), &op->dev);
 750 
 751         err = -ENOMEM;
 752         if (!info)
 753                 goto out_err;
 754         par = info->par;
 755 
 756         spin_lock_init(&par->lock);
 757 
 758         info->fix.smem_start = op->resource[0].start;
 759         par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 760 
 761         sbusfb_fill_var(&info->var, dp, 8);
 762         info->var.red.length = 8;
 763         info->var.green.length = 8;
 764         info->var.blue.length = 8;
 765 
 766         linebytes = of_getintprop_default(dp, "linebytes",
 767                                           info->var.xres);
 768         info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 769 
 770         dblbuf = of_getintprop_default(dp, "dblbuf", 0);
 771         if (dblbuf)
 772                 info->fix.smem_len *= 4;
 773 
 774         par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
 775                                 4096, "cgsix fbc");
 776         par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
 777                                 sizeof(struct cg6_tec), "cgsix tec");
 778         par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
 779                                 sizeof(struct cg6_thc), "cgsix thc");
 780         par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
 781                                 sizeof(struct bt_regs), "cgsix dac");
 782         par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
 783                                 sizeof(u32), "cgsix fhc");
 784 
 785         info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
 786                         FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
 787                         FBINFO_READS_FAST;
 788         info->fbops = &cg6_ops;
 789 
 790         info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
 791                                         info->fix.smem_len, "cgsix ram");
 792         if (!par->fbc || !par->tec || !par->thc ||
 793             !par->bt || !par->fhc || !info->screen_base)
 794                 goto out_unmap_regs;
 795 
 796         info->var.accel_flags = FB_ACCELF_TEXT;
 797 
 798         cg6_bt_init(par);
 799         cg6_chip_init(info);
 800         cg6_blank(FB_BLANK_UNBLANK, info);
 801 
 802         if (fb_alloc_cmap(&info->cmap, 256, 0))
 803                 goto out_unmap_regs;
 804 
 805         fb_set_cmap(&info->cmap, info);
 806         cg6_init_fix(info, linebytes);
 807 
 808         err = register_framebuffer(info);
 809         if (err < 0)
 810                 goto out_dealloc_cmap;
 811 
 812         dev_set_drvdata(&op->dev, info);
 813 
 814         printk(KERN_INFO "%pOF: CGsix [%s] at %lx:%lx\n",
 815                dp, info->fix.id,
 816                par->which_io, info->fix.smem_start);
 817 
 818         return 0;
 819 
 820 out_dealloc_cmap:
 821         fb_dealloc_cmap(&info->cmap);
 822 
 823 out_unmap_regs:
 824         cg6_unmap_regs(op, info, par);
 825         framebuffer_release(info);
 826 
 827 out_err:
 828         return err;
 829 }
 830 
 831 static int cg6_remove(struct platform_device *op)
 832 {
 833         struct fb_info *info = dev_get_drvdata(&op->dev);
 834         struct cg6_par *par = info->par;
 835 
 836         unregister_framebuffer(info);
 837         fb_dealloc_cmap(&info->cmap);
 838 
 839         cg6_unmap_regs(op, info, par);
 840 
 841         framebuffer_release(info);
 842 
 843         return 0;
 844 }
 845 
 846 static const struct of_device_id cg6_match[] = {
 847         {
 848                 .name = "cgsix",
 849         },
 850         {
 851                 .name = "cgthree+",
 852         },
 853         {},
 854 };
 855 MODULE_DEVICE_TABLE(of, cg6_match);
 856 
 857 static struct platform_driver cg6_driver = {
 858         .driver = {
 859                 .name = "cg6",
 860                 .of_match_table = cg6_match,
 861         },
 862         .probe          = cg6_probe,
 863         .remove         = cg6_remove,
 864 };
 865 
 866 static int __init cg6_init(void)
 867 {
 868         if (fb_get_options("cg6fb", NULL))
 869                 return -ENODEV;
 870 
 871         return platform_driver_register(&cg6_driver);
 872 }
 873 
 874 static void __exit cg6_exit(void)
 875 {
 876         platform_driver_unregister(&cg6_driver);
 877 }
 878 
 879 module_init(cg6_init);
 880 module_exit(cg6_exit);
 881 
 882 MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets");
 883 MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
 884 MODULE_VERSION("2.0");
 885 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */