linux/drivers/video/ffb.c
<<
>>
Prefs
   1/* ffb.c: Creator/Elite3D frame buffer driver
   2 *
   3 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
   4 * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
   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/delay.h>
  14#include <linux/init.h>
  15#include <linux/fb.h>
  16#include <linux/mm.h>
  17#include <linux/timer.h>
  18#include <linux/of_device.h>
  19
  20#include <asm/io.h>
  21#include <asm/upa.h>
  22#include <asm/fbio.h>
  23
  24#include "sbuslib.h"
  25
  26/*
  27 * Local functions.
  28 */
  29
  30static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned,
  31                         unsigned, struct fb_info *);
  32static int ffb_blank(int, struct fb_info *);
  33
  34static void ffb_imageblit(struct fb_info *, const struct fb_image *);
  35static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *);
  36static void ffb_copyarea(struct fb_info *, const struct fb_copyarea *);
  37static int ffb_sync(struct fb_info *);
  38static int ffb_mmap(struct fb_info *, struct vm_area_struct *);
  39static int ffb_ioctl(struct fb_info *, unsigned int, unsigned long);
  40static int ffb_pan_display(struct fb_var_screeninfo *, struct fb_info *);
  41
  42/*
  43 *  Frame buffer operations
  44 */
  45
  46static struct fb_ops ffb_ops = {
  47        .owner                  = THIS_MODULE,
  48        .fb_setcolreg           = ffb_setcolreg,
  49        .fb_blank               = ffb_blank,
  50        .fb_pan_display         = ffb_pan_display,
  51        .fb_fillrect            = ffb_fillrect,
  52        .fb_copyarea            = ffb_copyarea,
  53        .fb_imageblit           = ffb_imageblit,
  54        .fb_sync                = ffb_sync,
  55        .fb_mmap                = ffb_mmap,
  56        .fb_ioctl               = ffb_ioctl,
  57#ifdef CONFIG_COMPAT
  58        .fb_compat_ioctl        = sbusfb_compat_ioctl,
  59#endif
  60};
  61
  62/* Register layout and definitions */
  63#define FFB_SFB8R_VOFF          0x00000000
  64#define FFB_SFB8G_VOFF          0x00400000
  65#define FFB_SFB8B_VOFF          0x00800000
  66#define FFB_SFB8X_VOFF          0x00c00000
  67#define FFB_SFB32_VOFF          0x01000000
  68#define FFB_SFB64_VOFF          0x02000000
  69#define FFB_FBC_REGS_VOFF       0x04000000
  70#define FFB_BM_FBC_REGS_VOFF    0x04002000
  71#define FFB_DFB8R_VOFF          0x04004000
  72#define FFB_DFB8G_VOFF          0x04404000
  73#define FFB_DFB8B_VOFF          0x04804000
  74#define FFB_DFB8X_VOFF          0x04c04000
  75#define FFB_DFB24_VOFF          0x05004000
  76#define FFB_DFB32_VOFF          0x06004000
  77#define FFB_DFB422A_VOFF        0x07004000      /* DFB 422 mode write to A */
  78#define FFB_DFB422AD_VOFF       0x07804000      /* DFB 422 mode with line doubling */
  79#define FFB_DFB24B_VOFF         0x08004000      /* DFB 24bit mode write to B */
  80#define FFB_DFB422B_VOFF        0x09004000      /* DFB 422 mode write to B */
  81#define FFB_DFB422BD_VOFF       0x09804000      /* DFB 422 mode with line doubling */
  82#define FFB_SFB16Z_VOFF         0x0a004000      /* 16bit mode Z planes */
  83#define FFB_SFB8Z_VOFF          0x0a404000      /* 8bit mode Z planes */
  84#define FFB_SFB422_VOFF         0x0ac04000      /* SFB 422 mode write to A/B */
  85#define FFB_SFB422D_VOFF        0x0b404000      /* SFB 422 mode with line doubling */
  86#define FFB_FBC_KREGS_VOFF      0x0bc04000
  87#define FFB_DAC_VOFF            0x0bc06000
  88#define FFB_PROM_VOFF           0x0bc08000
  89#define FFB_EXP_VOFF            0x0bc18000
  90
  91#define FFB_SFB8R_POFF          0x04000000UL
  92#define FFB_SFB8G_POFF          0x04400000UL
  93#define FFB_SFB8B_POFF          0x04800000UL
  94#define FFB_SFB8X_POFF          0x04c00000UL
  95#define FFB_SFB32_POFF          0x05000000UL
  96#define FFB_SFB64_POFF          0x06000000UL
  97#define FFB_FBC_REGS_POFF       0x00600000UL
  98#define FFB_BM_FBC_REGS_POFF    0x00600000UL
  99#define FFB_DFB8R_POFF          0x01000000UL
 100#define FFB_DFB8G_POFF          0x01400000UL
 101#define FFB_DFB8B_POFF          0x01800000UL
 102#define FFB_DFB8X_POFF          0x01c00000UL
 103#define FFB_DFB24_POFF          0x02000000UL
 104#define FFB_DFB32_POFF          0x03000000UL
 105#define FFB_FBC_KREGS_POFF      0x00610000UL
 106#define FFB_DAC_POFF            0x00400000UL
 107#define FFB_PROM_POFF           0x00000000UL
 108#define FFB_EXP_POFF            0x00200000UL
 109#define FFB_DFB422A_POFF        0x09000000UL
 110#define FFB_DFB422AD_POFF       0x09800000UL
 111#define FFB_DFB24B_POFF         0x0a000000UL
 112#define FFB_DFB422B_POFF        0x0b000000UL
 113#define FFB_DFB422BD_POFF       0x0b800000UL
 114#define FFB_SFB16Z_POFF         0x0c800000UL
 115#define FFB_SFB8Z_POFF          0x0c000000UL
 116#define FFB_SFB422_POFF         0x0d000000UL
 117#define FFB_SFB422D_POFF        0x0d800000UL
 118
 119/* Draw operations */
 120#define FFB_DRAWOP_DOT          0x00
 121#define FFB_DRAWOP_AADOT        0x01
 122#define FFB_DRAWOP_BRLINECAP    0x02
 123#define FFB_DRAWOP_BRLINEOPEN   0x03
 124#define FFB_DRAWOP_DDLINE       0x04
 125#define FFB_DRAWOP_AALINE       0x05
 126#define FFB_DRAWOP_TRIANGLE     0x06
 127#define FFB_DRAWOP_POLYGON      0x07
 128#define FFB_DRAWOP_RECTANGLE    0x08
 129#define FFB_DRAWOP_FASTFILL     0x09
 130#define FFB_DRAWOP_BCOPY        0x0a
 131#define FFB_DRAWOP_VSCROLL      0x0b
 132
 133/* Pixel processor control */
 134/* Force WID */
 135#define FFB_PPC_FW_DISABLE      0x800000
 136#define FFB_PPC_FW_ENABLE       0xc00000
 137/* Auxiliary clip */
 138#define FFB_PPC_ACE_DISABLE     0x040000
 139#define FFB_PPC_ACE_AUX_SUB     0x080000
 140#define FFB_PPC_ACE_AUX_ADD     0x0c0000
 141/* Depth cue */
 142#define FFB_PPC_DCE_DISABLE     0x020000
 143#define FFB_PPC_DCE_ENABLE      0x030000
 144/* Alpha blend */
 145#define FFB_PPC_ABE_DISABLE     0x008000
 146#define FFB_PPC_ABE_ENABLE      0x00c000
 147/* View clip */
 148#define FFB_PPC_VCE_DISABLE     0x001000
 149#define FFB_PPC_VCE_2D          0x002000
 150#define FFB_PPC_VCE_3D          0x003000
 151/* Area pattern */
 152#define FFB_PPC_APE_DISABLE     0x000800
 153#define FFB_PPC_APE_ENABLE      0x000c00
 154/* Transparent background */
 155#define FFB_PPC_TBE_OPAQUE      0x000200
 156#define FFB_PPC_TBE_TRANSPARENT 0x000300
 157/* Z source */
 158#define FFB_PPC_ZS_VAR          0x000080
 159#define FFB_PPC_ZS_CONST        0x0000c0
 160/* Y source */
 161#define FFB_PPC_YS_VAR          0x000020
 162#define FFB_PPC_YS_CONST        0x000030
 163/* X source */
 164#define FFB_PPC_XS_WID          0x000004
 165#define FFB_PPC_XS_VAR          0x000008
 166#define FFB_PPC_XS_CONST        0x00000c
 167/* Color (BGR) source */
 168#define FFB_PPC_CS_VAR          0x000002
 169#define FFB_PPC_CS_CONST        0x000003
 170
 171#define FFB_ROP_NEW             0x83
 172#define FFB_ROP_OLD             0x85
 173#define FFB_ROP_NEW_XOR_OLD     0x86
 174
 175#define FFB_UCSR_FIFO_MASK      0x00000fff
 176#define FFB_UCSR_FB_BUSY        0x01000000
 177#define FFB_UCSR_RP_BUSY        0x02000000
 178#define FFB_UCSR_ALL_BUSY       (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
 179#define FFB_UCSR_READ_ERR       0x40000000
 180#define FFB_UCSR_FIFO_OVFL      0x80000000
 181#define FFB_UCSR_ALL_ERRORS     (FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
 182
 183struct ffb_fbc {
 184        /* Next vertex registers */
 185        u32     xxx1[3];
 186        u32     alpha;
 187        u32     red;
 188        u32     green;
 189        u32     blue;
 190        u32     depth;
 191        u32     y;
 192        u32     x;
 193        u32     xxx2[2];
 194        u32     ryf;
 195        u32     rxf;
 196        u32     xxx3[2];
 197
 198        u32     dmyf;
 199        u32     dmxf;
 200        u32     xxx4[2];
 201        u32     ebyi;
 202        u32     ebxi;
 203        u32     xxx5[2];
 204        u32     by;
 205        u32     bx;
 206        u32     dy;
 207        u32     dx;
 208        u32     bh;
 209        u32     bw;
 210        u32     xxx6[2];
 211
 212        u32     xxx7[32];
 213
 214        /* Setup unit vertex state register */
 215        u32     suvtx;
 216        u32     xxx8[63];
 217
 218        /* Control registers */
 219        u32     ppc;
 220        u32     wid;
 221        u32     fg;
 222        u32     bg;
 223        u32     consty;
 224        u32     constz;
 225        u32     xclip;
 226        u32     dcss;
 227        u32     vclipmin;
 228        u32     vclipmax;
 229        u32     vclipzmin;
 230        u32     vclipzmax;
 231        u32     dcsf;
 232        u32     dcsb;
 233        u32     dczf;
 234        u32     dczb;
 235
 236        u32     xxx9;
 237        u32     blendc;
 238        u32     blendc1;
 239        u32     blendc2;
 240        u32     fbramitc;
 241        u32     fbc;
 242        u32     rop;
 243        u32     cmp;
 244        u32     matchab;
 245        u32     matchc;
 246        u32     magnab;
 247        u32     magnc;
 248        u32     fbcfg0;
 249        u32     fbcfg1;
 250        u32     fbcfg2;
 251        u32     fbcfg3;
 252
 253        u32     ppcfg;
 254        u32     pick;
 255        u32     fillmode;
 256        u32     fbramwac;
 257        u32     pmask;
 258        u32     xpmask;
 259        u32     ypmask;
 260        u32     zpmask;
 261        u32     clip0min;
 262        u32     clip0max;
 263        u32     clip1min;
 264        u32     clip1max;
 265        u32     clip2min;
 266        u32     clip2max;
 267        u32     clip3min;
 268        u32     clip3max;
 269
 270        /* New 3dRAM III support regs */
 271        u32     rawblend2;
 272        u32     rawpreblend;
 273        u32     rawstencil;
 274        u32     rawstencilctl;
 275        u32     threedram1;
 276        u32     threedram2;
 277        u32     passin;
 278        u32     rawclrdepth;
 279        u32     rawpmask;
 280        u32     rawcsrc;
 281        u32     rawmatch;
 282        u32     rawmagn;
 283        u32     rawropblend;
 284        u32     rawcmp;
 285        u32     rawwac;
 286        u32     fbramid;
 287
 288        u32     drawop;
 289        u32     xxx10[2];
 290        u32     fontlpat;
 291        u32     xxx11;
 292        u32     fontxy;
 293        u32     fontw;
 294        u32     fontinc;
 295        u32     font;
 296        u32     xxx12[3];
 297        u32     blend2;
 298        u32     preblend;
 299        u32     stencil;
 300        u32     stencilctl;
 301
 302        u32     xxx13[4];
 303        u32     dcss1;
 304        u32     dcss2;
 305        u32     dcss3;
 306        u32     widpmask;
 307        u32     dcs2;
 308        u32     dcs3;
 309        u32     dcs4;
 310        u32     xxx14;
 311        u32     dcd2;
 312        u32     dcd3;
 313        u32     dcd4;
 314        u32     xxx15;
 315
 316        u32     pattern[32];
 317
 318        u32     xxx16[256];
 319
 320        u32     devid;
 321        u32     xxx17[63];
 322
 323        u32     ucsr;
 324        u32     xxx18[31];
 325
 326        u32     mer;
 327};
 328
 329struct ffb_dac {
 330        u32     type;
 331        u32     value;
 332        u32     type2;
 333        u32     value2;
 334};
 335
 336#define FFB_DAC_UCTRL           0x1001 /* User Control */
 337#define FFB_DAC_UCTRL_MANREV    0x00000f00 /* 4-bit Manufacturing Revision */
 338#define FFB_DAC_UCTRL_MANREV_SHIFT 8
 339#define FFB_DAC_TGEN            0x6000 /* Timing Generator */
 340#define FFB_DAC_TGEN_VIDE       0x00000001 /* Video Enable */
 341#define FFB_DAC_DID             0x8000 /* Device Identification */
 342#define FFB_DAC_DID_PNUM        0x0ffff000 /* Device Part Number */
 343#define FFB_DAC_DID_PNUM_SHIFT  12
 344#define FFB_DAC_DID_REV         0xf0000000 /* Device Revision */
 345#define FFB_DAC_DID_REV_SHIFT   28
 346
 347#define FFB_DAC_CUR_CTRL        0x100
 348#define FFB_DAC_CUR_CTRL_P0     0x00000001
 349#define FFB_DAC_CUR_CTRL_P1     0x00000002
 350
 351struct ffb_par {
 352        spinlock_t              lock;
 353        struct ffb_fbc __iomem  *fbc;
 354        struct ffb_dac __iomem  *dac;
 355
 356        u32                     flags;
 357#define FFB_FLAG_AFB            0x00000001 /* AFB m3 or m6 */
 358#define FFB_FLAG_BLANKED        0x00000002 /* screen is blanked */
 359#define FFB_FLAG_INVCURSOR      0x00000004 /* DAC has inverted cursor logic */
 360
 361        u32                     fg_cache __attribute__((aligned (8)));
 362        u32                     bg_cache;
 363        u32                     rop_cache;
 364
 365        int                     fifo_cache;
 366
 367        unsigned long           physbase;
 368        unsigned long           fbsize;
 369
 370        int                     board_type;
 371
 372        u32                     pseudo_palette[16];
 373};
 374
 375static void FFBFifo(struct ffb_par *par, int n)
 376{
 377        struct ffb_fbc __iomem *fbc;
 378        int cache = par->fifo_cache;
 379
 380        if (cache - n < 0) {
 381                fbc = par->fbc;
 382                do {
 383                        cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK);
 384                        cache -= 8;
 385                } while (cache - n < 0);
 386        }
 387        par->fifo_cache = cache - n;
 388}
 389
 390static void FFBWait(struct ffb_par *par)
 391{
 392        struct ffb_fbc __iomem *fbc;
 393        int limit = 10000;
 394
 395        fbc = par->fbc;
 396        do {
 397                if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_BUSY) == 0)
 398                        break;
 399                if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) {
 400                        upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
 401                }
 402                udelay(10);
 403        } while (--limit > 0);
 404}
 405
 406static int ffb_sync(struct fb_info *p)
 407{
 408        struct ffb_par *par = (struct ffb_par *)p->par;
 409
 410        FFBWait(par);
 411        return 0;
 412}
 413
 414static __inline__ void ffb_rop(struct ffb_par *par, u32 rop)
 415{
 416        if (par->rop_cache != rop) {
 417                FFBFifo(par, 1);
 418                upa_writel(rop, &par->fbc->rop);
 419                par->rop_cache = rop;
 420        }
 421}
 422
 423static void ffb_switch_from_graph(struct ffb_par *par)
 424{
 425        struct ffb_fbc __iomem *fbc = par->fbc;
 426        struct ffb_dac __iomem *dac = par->dac;
 427        unsigned long flags;
 428
 429        spin_lock_irqsave(&par->lock, flags);
 430        FFBWait(par);
 431        par->fifo_cache = 0;
 432        FFBFifo(par, 7);
 433        upa_writel(FFB_PPC_VCE_DISABLE | FFB_PPC_TBE_OPAQUE |
 434                   FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,
 435                   &fbc->ppc);
 436        upa_writel(0x2000707f, &fbc->fbc);
 437        upa_writel(par->rop_cache, &fbc->rop);
 438        upa_writel(0xffffffff, &fbc->pmask);
 439        upa_writel((1 << 16) | (0 << 0), &fbc->fontinc);
 440        upa_writel(par->fg_cache, &fbc->fg);
 441        upa_writel(par->bg_cache, &fbc->bg);
 442        FFBWait(par);
 443
 444        /* Disable cursor.  */
 445        upa_writel(FFB_DAC_CUR_CTRL, &dac->type2);
 446        if (par->flags & FFB_FLAG_INVCURSOR)
 447                upa_writel(0, &dac->value2);
 448        else
 449                upa_writel((FFB_DAC_CUR_CTRL_P0 |
 450                            FFB_DAC_CUR_CTRL_P1), &dac->value2);
 451
 452        spin_unlock_irqrestore(&par->lock, flags);
 453}
 454
 455static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 456{
 457        struct ffb_par *par = (struct ffb_par *)info->par;
 458
 459        /* We just use this to catch switches out of
 460         * graphics mode.
 461         */
 462        ffb_switch_from_graph(par);
 463
 464        if (var->xoffset || var->yoffset || var->vmode)
 465                return -EINVAL;
 466        return 0;
 467}
 468
 469/**
 470 *      ffb_fillrect - Draws a rectangle on the screen.
 471 *
 472 *      @info: frame buffer structure that represents a single frame buffer
 473 *      @rect: structure defining the rectagle and operation.
 474 */
 475static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 476{
 477        struct ffb_par *par = (struct ffb_par *)info->par;
 478        struct ffb_fbc __iomem *fbc = par->fbc;
 479        unsigned long flags;
 480        u32 fg;
 481
 482        BUG_ON(rect->rop != ROP_COPY && rect->rop != ROP_XOR);
 483
 484        fg = ((u32 *)info->pseudo_palette)[rect->color];
 485
 486        spin_lock_irqsave(&par->lock, flags);
 487
 488        if (fg != par->fg_cache) {
 489                FFBFifo(par, 1);
 490                upa_writel(fg, &fbc->fg);
 491                par->fg_cache = fg;
 492        }
 493
 494        ffb_rop(par, rect->rop == ROP_COPY ?
 495                     FFB_ROP_NEW :
 496                     FFB_ROP_NEW_XOR_OLD);
 497
 498        FFBFifo(par, 5);
 499        upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
 500        upa_writel(rect->dy, &fbc->by);
 501        upa_writel(rect->dx, &fbc->bx);
 502        upa_writel(rect->height, &fbc->bh);
 503        upa_writel(rect->width, &fbc->bw);
 504
 505        spin_unlock_irqrestore(&par->lock, flags);
 506}
 507
 508/**
 509 *      ffb_copyarea - Copies on area of the screen to another area.
 510 *
 511 *      @info: frame buffer structure that represents a single frame buffer
 512 *      @area: structure defining the source and destination.
 513 */
 514
 515static void ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 516{
 517        struct ffb_par *par = (struct ffb_par *)info->par;
 518        struct ffb_fbc __iomem *fbc = par->fbc;
 519        unsigned long flags;
 520
 521        if (area->dx != area->sx ||
 522            area->dy == area->sy) {
 523                cfb_copyarea(info, area);
 524                return;
 525        }
 526
 527        spin_lock_irqsave(&par->lock, flags);
 528
 529        ffb_rop(par, FFB_ROP_OLD);
 530
 531        FFBFifo(par, 7);
 532        upa_writel(FFB_DRAWOP_VSCROLL, &fbc->drawop);
 533        upa_writel(area->sy, &fbc->by);
 534        upa_writel(area->sx, &fbc->bx);
 535        upa_writel(area->dy, &fbc->dy);
 536        upa_writel(area->dx, &fbc->dx);
 537        upa_writel(area->height, &fbc->bh);
 538        upa_writel(area->width, &fbc->bw);
 539
 540        spin_unlock_irqrestore(&par->lock, flags);
 541}
 542
 543/**
 544 *      ffb_imageblit - Copies a image from system memory to the screen.
 545 *
 546 *      @info: frame buffer structure that represents a single frame buffer
 547 *      @image: structure defining the image.
 548 */
 549static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)
 550{
 551        struct ffb_par *par = (struct ffb_par *)info->par;
 552        struct ffb_fbc __iomem *fbc = par->fbc;
 553        const u8 *data = image->data;
 554        unsigned long flags;
 555        u32 fg, bg, xy;
 556        u64 fgbg;
 557        int i, width, stride;
 558
 559        if (image->depth > 1) {
 560                cfb_imageblit(info, image);
 561                return;
 562        }
 563
 564        fg = ((u32 *)info->pseudo_palette)[image->fg_color];
 565        bg = ((u32 *)info->pseudo_palette)[image->bg_color];
 566        fgbg = ((u64) fg << 32) | (u64) bg;
 567        xy = (image->dy << 16) | image->dx;
 568        width = image->width;
 569        stride = ((width + 7) >> 3);
 570
 571        spin_lock_irqsave(&par->lock, flags);
 572
 573        if (fgbg != *(u64 *)&par->fg_cache) {
 574                FFBFifo(par, 2);
 575                upa_writeq(fgbg, &fbc->fg);
 576                *(u64 *)&par->fg_cache = fgbg;
 577        }
 578
 579        if (width >= 32) {
 580                FFBFifo(par, 1);
 581                upa_writel(32, &fbc->fontw);
 582        }
 583
 584        while (width >= 32) {
 585                const u8 *next_data = data + 4;
 586
 587                FFBFifo(par, 1);
 588                upa_writel(xy, &fbc->fontxy);
 589                xy += (32 << 0);
 590
 591                for (i = 0; i < image->height; i++) {
 592                        u32 val = (((u32)data[0] << 24) |
 593                                   ((u32)data[1] << 16) |
 594                                   ((u32)data[2] <<  8) |
 595                                   ((u32)data[3] <<  0));
 596                        FFBFifo(par, 1);
 597                        upa_writel(val, &fbc->font);
 598
 599                        data += stride;
 600                }
 601
 602                data = next_data;
 603                width -= 32;
 604        }
 605
 606        if (width) {
 607                FFBFifo(par, 2);
 608                upa_writel(width, &fbc->fontw);
 609                upa_writel(xy, &fbc->fontxy);
 610
 611                for (i = 0; i < image->height; i++) {
 612                        u32 val = (((u32)data[0] << 24) |
 613                                   ((u32)data[1] << 16) |
 614                                   ((u32)data[2] <<  8) |
 615                                   ((u32)data[3] <<  0));
 616                        FFBFifo(par, 1);
 617                        upa_writel(val, &fbc->font);
 618
 619                        data += stride;
 620                }
 621        }
 622
 623        spin_unlock_irqrestore(&par->lock, flags);
 624}
 625
 626static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var)
 627{
 628        var->red.offset = 0;
 629        var->red.length = 8;
 630        var->green.offset = 8;
 631        var->green.length = 8;
 632        var->blue.offset = 16;
 633        var->blue.length = 8;
 634        var->transp.offset = 0;
 635        var->transp.length = 0;
 636}
 637
 638/**
 639 *      ffb_setcolreg - Sets a color register.
 640 *
 641 *      @regno: boolean, 0 copy local, 1 get_user() function
 642 *      @red: frame buffer colormap structure
 643 *      @green: The green value which can be up to 16 bits wide
 644 *      @blue:  The blue value which can be up to 16 bits wide.
 645 *      @transp: If supported the alpha value which can be up to 16 bits wide.
 646 *      @info: frame buffer info structure
 647 */
 648static int ffb_setcolreg(unsigned regno,
 649                         unsigned red, unsigned green, unsigned blue,
 650                         unsigned transp, struct fb_info *info)
 651{
 652        u32 value;
 653
 654        if (regno >= 16)
 655                return 1;
 656
 657        red >>= 8;
 658        green >>= 8;
 659        blue >>= 8;
 660
 661        value = (blue << 16) | (green << 8) | red;
 662        ((u32 *)info->pseudo_palette)[regno] = value;
 663
 664        return 0;
 665}
 666
 667/**
 668 *      ffb_blank - Optional function.  Blanks the display.
 669 *      @blank_mode: the blank mode we want.
 670 *      @info: frame buffer structure that represents a single frame buffer
 671 */
 672static int ffb_blank(int blank, struct fb_info *info)
 673{
 674        struct ffb_par *par = (struct ffb_par *)info->par;
 675        struct ffb_dac __iomem *dac = par->dac;
 676        unsigned long flags;
 677        u32 val;
 678        int i;
 679
 680        spin_lock_irqsave(&par->lock, flags);
 681
 682        FFBWait(par);
 683
 684        upa_writel(FFB_DAC_TGEN, &dac->type);
 685        val = upa_readl(&dac->value);
 686        switch (blank) {
 687        case FB_BLANK_UNBLANK: /* Unblanking */
 688                val |= FFB_DAC_TGEN_VIDE;
 689                par->flags &= ~FFB_FLAG_BLANKED;
 690                break;
 691
 692        case FB_BLANK_NORMAL: /* Normal blanking */
 693        case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
 694        case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
 695        case FB_BLANK_POWERDOWN: /* Poweroff */
 696                val &= ~FFB_DAC_TGEN_VIDE;
 697                par->flags |= FFB_FLAG_BLANKED;
 698                break;
 699        }
 700        upa_writel(FFB_DAC_TGEN, &dac->type);
 701        upa_writel(val, &dac->value);
 702        for (i = 0; i < 10; i++) {
 703                upa_writel(FFB_DAC_TGEN, &dac->type);
 704                upa_readl(&dac->value);
 705        }
 706
 707        spin_unlock_irqrestore(&par->lock, flags);
 708
 709        return 0;
 710}
 711
 712static struct sbus_mmap_map ffb_mmap_map[] = {
 713        {
 714                .voff   = FFB_SFB8R_VOFF,
 715                .poff   = FFB_SFB8R_POFF,
 716                .size   = 0x0400000
 717        },
 718        {
 719                .voff   = FFB_SFB8G_VOFF,
 720                .poff   = FFB_SFB8G_POFF,
 721                .size   = 0x0400000
 722        },
 723        {
 724                .voff   = FFB_SFB8B_VOFF,
 725                .poff   = FFB_SFB8B_POFF,
 726                .size   = 0x0400000
 727        },
 728        {
 729                .voff   = FFB_SFB8X_VOFF,
 730                .poff   = FFB_SFB8X_POFF,
 731                .size   = 0x0400000
 732        },
 733        {
 734                .voff   = FFB_SFB32_VOFF,
 735                .poff   = FFB_SFB32_POFF,
 736                .size   = 0x1000000
 737        },
 738        {
 739                .voff   = FFB_SFB64_VOFF,
 740                .poff   = FFB_SFB64_POFF,
 741                .size   = 0x2000000
 742        },
 743        {
 744                .voff   = FFB_FBC_REGS_VOFF,
 745                .poff   = FFB_FBC_REGS_POFF,
 746                .size   = 0x0002000
 747        },
 748        {
 749                .voff   = FFB_BM_FBC_REGS_VOFF,
 750                .poff   = FFB_BM_FBC_REGS_POFF,
 751                .size   = 0x0002000
 752        },
 753        {
 754                .voff   = FFB_DFB8R_VOFF,
 755                .poff   = FFB_DFB8R_POFF,
 756                .size   = 0x0400000
 757        },
 758        {
 759                .voff   = FFB_DFB8G_VOFF,
 760                .poff   = FFB_DFB8G_POFF,
 761                .size   = 0x0400000
 762        },
 763        {
 764                .voff   = FFB_DFB8B_VOFF,
 765                .poff   = FFB_DFB8B_POFF,
 766                .size   = 0x0400000
 767        },
 768        {
 769                .voff   = FFB_DFB8X_VOFF,
 770                .poff   = FFB_DFB8X_POFF,
 771                .size   = 0x0400000
 772        },
 773        {
 774                .voff   = FFB_DFB24_VOFF,
 775                .poff   = FFB_DFB24_POFF,
 776                .size   = 0x1000000
 777        },
 778        {
 779                .voff   = FFB_DFB32_VOFF,
 780                .poff   = FFB_DFB32_POFF,
 781                .size   = 0x1000000
 782        },
 783        {
 784                .voff   = FFB_FBC_KREGS_VOFF,
 785                .poff   = FFB_FBC_KREGS_POFF,
 786                .size   = 0x0002000
 787        },
 788        {
 789                .voff   = FFB_DAC_VOFF,
 790                .poff   = FFB_DAC_POFF,
 791                .size   = 0x0002000
 792        },
 793        {
 794                .voff   = FFB_PROM_VOFF,
 795                .poff   = FFB_PROM_POFF,
 796                .size   = 0x0010000
 797        },
 798        {
 799                .voff   = FFB_EXP_VOFF,
 800                .poff   = FFB_EXP_POFF,
 801                .size   = 0x0002000
 802        },
 803        {
 804                .voff   = FFB_DFB422A_VOFF,
 805                .poff   = FFB_DFB422A_POFF,
 806                .size   = 0x0800000
 807        },
 808        {
 809                .voff   = FFB_DFB422AD_VOFF,
 810                .poff   = FFB_DFB422AD_POFF,
 811                .size   = 0x0800000
 812        },
 813        {
 814                .voff   = FFB_DFB24B_VOFF,
 815                .poff   = FFB_DFB24B_POFF,
 816                .size   = 0x1000000
 817        },
 818        {
 819                .voff   = FFB_DFB422B_VOFF,
 820                .poff   = FFB_DFB422B_POFF,
 821                .size   = 0x0800000
 822        },
 823        {
 824                .voff   = FFB_DFB422BD_VOFF,
 825                .poff   = FFB_DFB422BD_POFF,
 826                .size   = 0x0800000
 827        },
 828        {
 829                .voff   = FFB_SFB16Z_VOFF,
 830                .poff   = FFB_SFB16Z_POFF,
 831                .size   = 0x0800000
 832        },
 833        {
 834                .voff   = FFB_SFB8Z_VOFF,
 835                .poff   = FFB_SFB8Z_POFF,
 836                .size   = 0x0800000
 837        },
 838        {
 839                .voff   = FFB_SFB422_VOFF,
 840                .poff   = FFB_SFB422_POFF,
 841                .size   = 0x0800000
 842        },
 843        {
 844                .voff   = FFB_SFB422D_VOFF,
 845                .poff   = FFB_SFB422D_POFF,
 846                .size   = 0x0800000
 847        },
 848        { .size = 0 }
 849};
 850
 851static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 852{
 853        struct ffb_par *par = (struct ffb_par *)info->par;
 854
 855        return sbusfb_mmap_helper(ffb_mmap_map,
 856                                  par->physbase, par->fbsize,
 857                                  0, vma);
 858}
 859
 860static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 861{
 862        struct ffb_par *par = (struct ffb_par *)info->par;
 863
 864        return sbusfb_ioctl_helper(cmd, arg, info,
 865                                   FBTYPE_CREATOR, 24, par->fbsize);
 866}
 867
 868/*
 869 *  Initialisation
 870 */
 871
 872static void ffb_init_fix(struct fb_info *info)
 873{
 874        struct ffb_par *par = (struct ffb_par *)info->par;
 875        const char *ffb_type_name;
 876
 877        if (!(par->flags & FFB_FLAG_AFB)) {
 878                if ((par->board_type & 0x7) == 0x3)
 879                        ffb_type_name = "Creator 3D";
 880                else
 881                        ffb_type_name = "Creator";
 882        } else
 883                ffb_type_name = "Elite 3D";
 884
 885        strlcpy(info->fix.id, ffb_type_name, sizeof(info->fix.id));
 886
 887        info->fix.type = FB_TYPE_PACKED_PIXELS;
 888        info->fix.visual = FB_VISUAL_TRUECOLOR;
 889
 890        /* Framebuffer length is the same regardless of resolution. */
 891        info->fix.line_length = 8192;
 892
 893        info->fix.accel = FB_ACCEL_SUN_CREATOR;
 894}
 895
 896static int __devinit ffb_probe(struct platform_device *op)
 897{
 898        struct device_node *dp = op->dev.of_node;
 899        struct ffb_fbc __iomem *fbc;
 900        struct ffb_dac __iomem *dac;
 901        struct fb_info *info;
 902        struct ffb_par *par;
 903        u32 dac_pnum, dac_rev, dac_mrev;
 904        int err;
 905
 906        info = framebuffer_alloc(sizeof(struct ffb_par), &op->dev);
 907
 908        err = -ENOMEM;
 909        if (!info)
 910                goto out_err;
 911
 912        par = info->par;
 913
 914        spin_lock_init(&par->lock);
 915        par->fbc = of_ioremap(&op->resource[2], 0,
 916                              sizeof(struct ffb_fbc), "ffb fbc");
 917        if (!par->fbc)
 918                goto out_release_fb;
 919
 920        par->dac = of_ioremap(&op->resource[1], 0,
 921                              sizeof(struct ffb_dac), "ffb dac");
 922        if (!par->dac)
 923                goto out_unmap_fbc;
 924
 925        par->rop_cache = FFB_ROP_NEW;
 926        par->physbase = op->resource[0].start;
 927
 928        /* Don't mention copyarea, so SCROLL_REDRAW is always
 929         * used.  It is the fastest on this chip.
 930         */
 931        info->flags = (FBINFO_DEFAULT |
 932                       /* FBINFO_HWACCEL_COPYAREA | */
 933                       FBINFO_HWACCEL_FILLRECT |
 934                       FBINFO_HWACCEL_IMAGEBLIT);
 935
 936        info->fbops = &ffb_ops;
 937
 938        info->screen_base = (char *) par->physbase + FFB_DFB24_POFF;
 939        info->pseudo_palette = par->pseudo_palette;
 940
 941        sbusfb_fill_var(&info->var, dp, 32);
 942        par->fbsize = PAGE_ALIGN(info->var.xres * info->var.yres * 4);
 943        ffb_fixup_var_rgb(&info->var);
 944
 945        info->var.accel_flags = FB_ACCELF_TEXT;
 946
 947        if (!strcmp(dp->name, "SUNW,afb"))
 948                par->flags |= FFB_FLAG_AFB;
 949
 950        par->board_type = of_getintprop_default(dp, "board_type", 0);
 951
 952        fbc = par->fbc;
 953        if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
 954                upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
 955
 956        dac = par->dac;
 957        upa_writel(FFB_DAC_DID, &dac->type);
 958        dac_pnum = upa_readl(&dac->value);
 959        dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT;
 960        dac_pnum = (dac_pnum & FFB_DAC_DID_PNUM) >> FFB_DAC_DID_PNUM_SHIFT;
 961
 962        upa_writel(FFB_DAC_UCTRL, &dac->type);
 963        dac_mrev = upa_readl(&dac->value);
 964        dac_mrev = (dac_mrev & FFB_DAC_UCTRL_MANREV) >>
 965                FFB_DAC_UCTRL_MANREV_SHIFT;
 966
 967        /* Elite3D has different DAC revision numbering, and no DAC revisions
 968         * have the reversed meaning of cursor enable.  Otherwise, Pacifica 1
 969         * ramdacs with manufacturing revision less than 3 have inverted
 970         * cursor logic.  We identify Pacifica 1 as not Pacifica 2, the
 971         * latter having a part number value of 0x236e.
 972         */
 973        if ((par->flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {
 974                par->flags &= ~FFB_FLAG_INVCURSOR;
 975        } else {
 976                if (dac_mrev < 3)
 977                        par->flags |= FFB_FLAG_INVCURSOR;
 978        }
 979
 980        ffb_switch_from_graph(par);
 981
 982        /* Unblank it just to be sure.  When there are multiple
 983         * FFB/AFB cards in the system, or it is not the OBP
 984         * chosen console, it will have video outputs off in
 985         * the DAC.
 986         */
 987        ffb_blank(FB_BLANK_UNBLANK, info);
 988
 989        if (fb_alloc_cmap(&info->cmap, 256, 0))
 990                goto out_unmap_dac;
 991
 992        ffb_init_fix(info);
 993
 994        err = register_framebuffer(info);
 995        if (err < 0)
 996                goto out_dealloc_cmap;
 997
 998        dev_set_drvdata(&op->dev, info);
 999
1000        printk(KERN_INFO "%s: %s at %016lx, type %d, "
1001               "DAC pnum[%x] rev[%d] manuf_rev[%d]\n",
1002               dp->full_name,
1003               ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
1004               par->physbase, par->board_type,
1005               dac_pnum, dac_rev, dac_mrev);
1006
1007        return 0;
1008
1009out_dealloc_cmap:
1010        fb_dealloc_cmap(&info->cmap);
1011
1012out_unmap_dac:
1013        of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));
1014
1015out_unmap_fbc:
1016        of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
1017
1018out_release_fb:
1019        framebuffer_release(info);
1020
1021out_err:
1022        return err;
1023}
1024
1025static int __devexit ffb_remove(struct platform_device *op)
1026{
1027        struct fb_info *info = dev_get_drvdata(&op->dev);
1028        struct ffb_par *par = info->par;
1029
1030        unregister_framebuffer(info);
1031        fb_dealloc_cmap(&info->cmap);
1032
1033        of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
1034        of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));
1035
1036        framebuffer_release(info);
1037
1038        dev_set_drvdata(&op->dev, NULL);
1039
1040        return 0;
1041}
1042
1043static const struct of_device_id ffb_match[] = {
1044        {
1045                .name = "SUNW,ffb",
1046        },
1047        {
1048                .name = "SUNW,afb",
1049        },
1050        {},
1051};
1052MODULE_DEVICE_TABLE(of, ffb_match);
1053
1054static struct platform_driver ffb_driver = {
1055        .driver = {
1056                .name = "ffb",
1057                .owner = THIS_MODULE,
1058                .of_match_table = ffb_match,
1059        },
1060        .probe          = ffb_probe,
1061        .remove         = __devexit_p(ffb_remove),
1062};
1063
1064static int __init ffb_init(void)
1065{
1066        if (fb_get_options("ffb", NULL))
1067                return -ENODEV;
1068
1069        return platform_driver_register(&ffb_driver);
1070}
1071
1072static void __exit ffb_exit(void)
1073{
1074        platform_driver_unregister(&ffb_driver);
1075}
1076
1077module_init(ffb_init);
1078module_exit(ffb_exit);
1079
1080MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets");
1081MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
1082MODULE_VERSION("2.0");
1083MODULE_LICENSE("GPL");
1084