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