linux-old/drivers/video/cgsixfb.c
<<
>>
Prefs
   1/* $Id: cgsixfb.c,v 1.26 2001/10/16 05:44:44 davem Exp $
   2 * cgsixfb.c: CGsix (GX,GXplus) frame buffer driver
   3 *
   4 * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
   5 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
   6 * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/sched.h>
  11#include <linux/kernel.h>
  12#include <linux/errno.h>
  13#include <linux/string.h>
  14#include <linux/mm.h>
  15#include <linux/tty.h>
  16#include <linux/slab.h>
  17#include <linux/vmalloc.h>
  18#include <linux/delay.h>
  19#include <linux/interrupt.h>
  20#include <linux/fb.h>
  21#include <linux/init.h>
  22#include <linux/selection.h>
  23
  24#include <video/sbusfb.h>
  25#include <asm/io.h>
  26
  27/* Offset of interesting structures in the OBIO space */
  28/*
  29 * Brooktree is the video dac and is funny to program on the cg6.
  30 * (it's even funnier on the cg3)
  31 * The FBC could be the frame buffer control
  32 * The FHC could is the frame buffer hardware control.
  33 */
  34#define CG6_ROM_OFFSET       0x0UL
  35#define CG6_BROOKTREE_OFFSET 0x200000UL
  36#define CG6_DHC_OFFSET       0x240000UL
  37#define CG6_ALT_OFFSET       0x280000UL
  38#define CG6_FHC_OFFSET       0x300000UL
  39#define CG6_THC_OFFSET       0x301000UL
  40#define CG6_FBC_OFFSET       0x700000UL
  41#define CG6_TEC_OFFSET       0x701000UL
  42#define CG6_RAM_OFFSET       0x800000UL
  43
  44/* FHC definitions */
  45#define CG6_FHC_FBID_SHIFT           24
  46#define CG6_FHC_FBID_MASK            255
  47#define CG6_FHC_REV_SHIFT            20
  48#define CG6_FHC_REV_MASK             15
  49#define CG6_FHC_FROP_DISABLE         (1 << 19)
  50#define CG6_FHC_ROW_DISABLE          (1 << 18)
  51#define CG6_FHC_SRC_DISABLE          (1 << 17)
  52#define CG6_FHC_DST_DISABLE          (1 << 16)
  53#define CG6_FHC_RESET                (1 << 15)
  54#define CG6_FHC_LITTLE_ENDIAN        (1 << 13)
  55#define CG6_FHC_RES_MASK             (3 << 11)
  56#define CG6_FHC_1024                 (0 << 11)
  57#define CG6_FHC_1152                 (1 << 11)
  58#define CG6_FHC_1280                 (2 << 11)
  59#define CG6_FHC_1600                 (3 << 11)
  60#define CG6_FHC_CPU_MASK             (3 << 9)
  61#define CG6_FHC_CPU_SPARC            (0 << 9)
  62#define CG6_FHC_CPU_68020            (1 << 9)
  63#define CG6_FHC_CPU_386              (2 << 9)
  64#define CG6_FHC_TEST                 (1 << 8)
  65#define CG6_FHC_TEST_X_SHIFT         4
  66#define CG6_FHC_TEST_X_MASK          15
  67#define CG6_FHC_TEST_Y_SHIFT         0
  68#define CG6_FHC_TEST_Y_MASK          15
  69
  70/* FBC mode definitions */
  71#define CG6_FBC_BLIT_IGNORE             0x00000000
  72#define CG6_FBC_BLIT_NOSRC              0x00100000
  73#define CG6_FBC_BLIT_SRC                0x00200000
  74#define CG6_FBC_BLIT_ILLEGAL            0x00300000
  75#define CG6_FBC_BLIT_MASK               0x00300000
  76
  77#define CG6_FBC_VBLANK                  0x00080000
  78
  79#define CG6_FBC_MODE_IGNORE             0x00000000
  80#define CG6_FBC_MODE_COLOR8             0x00020000
  81#define CG6_FBC_MODE_COLOR1             0x00040000
  82#define CG6_FBC_MODE_HRMONO             0x00060000
  83#define CG6_FBC_MODE_MASK               0x00060000
  84
  85#define CG6_FBC_DRAW_IGNORE             0x00000000
  86#define CG6_FBC_DRAW_RENDER             0x00008000
  87#define CG6_FBC_DRAW_PICK               0x00010000
  88#define CG6_FBC_DRAW_ILLEGAL            0x00018000
  89#define CG6_FBC_DRAW_MASK               0x00018000
  90
  91#define CG6_FBC_BWRITE0_IGNORE          0x00000000
  92#define CG6_FBC_BWRITE0_ENABLE          0x00002000
  93#define CG6_FBC_BWRITE0_DISABLE         0x00004000
  94#define CG6_FBC_BWRITE0_ILLEGAL         0x00006000
  95#define CG6_FBC_BWRITE0_MASK            0x00006000
  96
  97#define CG6_FBC_BWRITE1_IGNORE          0x00000000
  98#define CG6_FBC_BWRITE1_ENABLE          0x00000800
  99#define CG6_FBC_BWRITE1_DISABLE         0x00001000
 100#define CG6_FBC_BWRITE1_ILLEGAL         0x00001800
 101#define CG6_FBC_BWRITE1_MASK            0x00001800
 102
 103#define CG6_FBC_BREAD_IGNORE            0x00000000
 104#define CG6_FBC_BREAD_0                 0x00000200
 105#define CG6_FBC_BREAD_1                 0x00000400
 106#define CG6_FBC_BREAD_ILLEGAL           0x00000600
 107#define CG6_FBC_BREAD_MASK              0x00000600
 108
 109#define CG6_FBC_BDISP_IGNORE            0x00000000
 110#define CG6_FBC_BDISP_0                 0x00000080
 111#define CG6_FBC_BDISP_1                 0x00000100
 112#define CG6_FBC_BDISP_ILLEGAL           0x00000180
 113#define CG6_FBC_BDISP_MASK              0x00000180
 114
 115#define CG6_FBC_INDEX_MOD               0x00000040
 116#define CG6_FBC_INDEX_MASK              0x00000030
 117
 118/* THC definitions */
 119#define CG6_THC_MISC_REV_SHIFT       16
 120#define CG6_THC_MISC_REV_MASK        15
 121#define CG6_THC_MISC_RESET           (1 << 12)
 122#define CG6_THC_MISC_VIDEO           (1 << 10)
 123#define CG6_THC_MISC_SYNC            (1 << 9)
 124#define CG6_THC_MISC_VSYNC           (1 << 8)
 125#define CG6_THC_MISC_SYNC_ENAB       (1 << 7)
 126#define CG6_THC_MISC_CURS_RES        (1 << 6)
 127#define CG6_THC_MISC_INT_ENAB        (1 << 5)
 128#define CG6_THC_MISC_INT             (1 << 4)
 129#define CG6_THC_MISC_INIT            0x9f
 130
 131MODULE_LICENSE("GPL");
 132
 133/* The contents are unknown */
 134struct cg6_tec {
 135        volatile int tec_matrix;
 136        volatile int tec_clip;
 137        volatile int tec_vdc;
 138};
 139
 140struct cg6_thc {
 141        uint thc_pad0[512];
 142        volatile uint thc_hs;           /* hsync timing */
 143        volatile uint thc_hsdvs;
 144        volatile uint thc_hd;
 145        volatile uint thc_vs;           /* vsync timing */
 146        volatile uint thc_vd;
 147        volatile uint thc_refresh;
 148        volatile uint thc_misc;
 149        uint thc_pad1[56];
 150        volatile uint thc_cursxy;       /* cursor x,y position (16 bits each) */
 151        volatile uint thc_cursmask[32]; /* cursor mask bits */
 152        volatile uint thc_cursbits[32]; /* what to show where mask enabled */
 153};
 154
 155struct cg6_fbc {
 156        u32             xxx0[1];
 157        volatile u32    mode;
 158        volatile u32    clip;
 159        u32             xxx1[1];            
 160        volatile u32    s;
 161        volatile u32    draw;
 162        volatile u32    blit;
 163        volatile u32    font;
 164        u32             xxx2[24];
 165        volatile u32    x0, y0, z0, color0;
 166        volatile u32    x1, y1, z1, color1;
 167        volatile u32    x2, y2, z2, color2;
 168        volatile u32    x3, y3, z3, color3;
 169        volatile u32    offx, offy;
 170        u32             xxx3[2];
 171        volatile u32    incx, incy;
 172        u32             xxx4[2];
 173        volatile u32    clipminx, clipminy;
 174        u32             xxx5[2];
 175        volatile u32    clipmaxx, clipmaxy;
 176        u32             xxx6[2];
 177        volatile u32    fg;
 178        volatile u32    bg;
 179        volatile u32    alu;
 180        volatile u32    pm;
 181        volatile u32    pixelm;
 182        u32             xxx7[2];
 183        volatile u32    patalign;
 184        volatile u32    pattern[8];
 185        u32             xxx8[432];
 186        volatile u32    apointx, apointy, apointz;
 187        u32             xxx9[1];
 188        volatile u32    rpointx, rpointy, rpointz;
 189        u32             xxx10[5];
 190        volatile u32    pointr, pointg, pointb, pointa;
 191        volatile u32    alinex, aliney, alinez;
 192        u32             xxx11[1];
 193        volatile u32    rlinex, rliney, rlinez;
 194        u32             xxx12[5];
 195        volatile u32    liner, lineg, lineb, linea;
 196        volatile u32    atrix, atriy, atriz;
 197        u32             xxx13[1];
 198        volatile u32    rtrix, rtriy, rtriz;
 199        u32             xxx14[5];
 200        volatile u32    trir, trig, trib, tria;
 201        volatile u32    aquadx, aquady, aquadz;
 202        u32             xxx15[1];
 203        volatile u32    rquadx, rquady, rquadz;
 204        u32             xxx16[5];
 205        volatile u32    quadr, quadg, quadb, quada;
 206        volatile u32    arectx, arecty, arectz;
 207        u32             xxx17[1];
 208        volatile u32    rrectx, rrecty, rrectz;
 209        u32             xxx18[5];
 210        volatile u32    rectr, rectg, rectb, recta;
 211};
 212
 213static struct sbus_mmap_map cg6_mmap_map[] = {
 214        { CG6_FBC,              CG6_FBC_OFFSET,         PAGE_SIZE               },
 215        { CG6_TEC,              CG6_TEC_OFFSET,         PAGE_SIZE               },
 216        { CG6_BTREGS,           CG6_BROOKTREE_OFFSET,   PAGE_SIZE               },
 217        { CG6_FHC,              CG6_FHC_OFFSET,         PAGE_SIZE               },
 218        { CG6_THC,              CG6_THC_OFFSET,         PAGE_SIZE               },
 219        { CG6_ROM,              CG6_ROM_OFFSET,         0x10000                 },
 220        { CG6_RAM,              CG6_RAM_OFFSET,         SBUS_MMAP_FBSIZE(1)     },
 221        { CG6_DHC,              CG6_DHC_OFFSET,         0x40000                 },
 222        { 0,                    0,                      0                       }
 223};
 224
 225static void cg6_setup(struct display *p)
 226{
 227        p->next_line = sbusfbinfo(p->fb_info)->var.xres_virtual;
 228        p->next_plane = 0;
 229}
 230
 231static void cg6_clear(struct vc_data *conp, struct display *p, int sy, int sx,
 232                      int height, int width)
 233{
 234        struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
 235        register struct cg6_fbc *fbc = fb->s.cg6.fbc;
 236        unsigned long flags;
 237        int x, y, w, h;
 238        int i;
 239        
 240        spin_lock_irqsave(&fb->lock, flags);
 241        do {
 242                i = sbus_readl(&fbc->s);
 243        } while (i & 0x10000000);
 244        sbus_writel(attr_bgcol_ec(p,conp), &fbc->fg);
 245        sbus_writel(attr_bgcol_ec(p,conp), &fbc->bg);
 246        sbus_writel(~0, &fbc->pixelm);
 247        sbus_writel(0xea80ff00, &fbc->alu);
 248        sbus_writel(0, &fbc->s);
 249        sbus_writel(0, &fbc->clip);
 250        sbus_writel(~0, &fbc->pm);
 251
 252        if (fontheightlog(p)) {
 253                y = sy << fontheightlog(p); h = height << fontheightlog(p);
 254        } else {
 255                y = sy * fontheight(p); h = height * fontheight(p);
 256        }
 257        if (fontwidthlog(p)) {
 258                x = sx << fontwidthlog(p); w = width << fontwidthlog(p);
 259        } else {
 260                x = sx * fontwidth(p); w = width * fontwidth(p);
 261        }
 262        sbus_writel(y + fb->y_margin, &fbc->arecty);
 263        sbus_writel(x + fb->x_margin, &fbc->arectx);
 264        sbus_writel(y + fb->y_margin + h, &fbc->arecty);
 265        sbus_writel(x + fb->x_margin + w, &fbc->arectx);
 266        do {
 267                i = sbus_readl(&fbc->draw);
 268        } while (i < 0 && (i & 0x20000000));
 269        spin_unlock_irqrestore(&fb->lock, flags);
 270}
 271
 272static void cg6_fill(struct fb_info_sbusfb *fb, struct display *p, int s,
 273                     int count, unsigned short *boxes)
 274{
 275        int i;
 276        register struct cg6_fbc *fbc = fb->s.cg6.fbc;
 277        unsigned long flags;
 278        
 279        spin_lock_irqsave(&fb->lock, flags);
 280        do {
 281                i = sbus_readl(&fbc->s);
 282        } while (i & 0x10000000);
 283        sbus_writel(attr_bgcol(p,s), &fbc->fg);
 284        sbus_writel(attr_bgcol(p,s), &fbc->bg);
 285        sbus_writel(~0, &fbc->pixelm);
 286        sbus_writel(0xea80ff00, &fbc->alu);
 287        sbus_writel(0, &fbc->s);
 288        sbus_writel(0, &fbc->clip);
 289        sbus_writel(~0, &fbc->pm);
 290        while (count-- > 0) {
 291                sbus_writel(boxes[1], &fbc->arecty);
 292                sbus_writel(boxes[0], &fbc->arectx);
 293                sbus_writel(boxes[3], &fbc->arecty);
 294                sbus_writel(boxes[2], &fbc->arectx);
 295                boxes += 4;
 296                do {
 297                        i = sbus_readl(&fbc->draw);
 298                } while (i < 0 && (i & 0x20000000));
 299        }
 300        spin_unlock_irqrestore(&fb->lock, flags);
 301}
 302
 303static void cg6_putc(struct vc_data *conp, struct display *p, int c, int yy, int xx)
 304{
 305        struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
 306        register struct cg6_fbc *fbc = fb->s.cg6.fbc;
 307        unsigned long flags;
 308        int i, x, y;
 309        u8 *fd;
 310
 311        spin_lock_irqsave(&fb->lock, flags);
 312        if (fontheightlog(p)) {
 313                y = fb->y_margin + (yy << fontheightlog(p));
 314                i = ((c & p->charmask) << fontheightlog(p));
 315        } else {
 316                y = fb->y_margin + (yy * fontheight(p));
 317                i = (c & p->charmask) * fontheight(p);
 318        }
 319        if (fontwidth(p) <= 8)
 320                fd = p->fontdata + i;
 321        else
 322                fd = p->fontdata + (i << 1);
 323        if (fontwidthlog(p))
 324                x = fb->x_margin + (xx << fontwidthlog(p));
 325        else
 326                x = fb->x_margin + (xx * fontwidth(p));
 327        do {
 328                i = sbus_readl(&fbc->s);
 329        } while (i & 0x10000000);
 330        sbus_writel(attr_fgcol(p,c), &fbc->fg);
 331        sbus_writel(attr_bgcol(p,c), &fbc->bg);
 332        sbus_writel(0x140000, &fbc->mode);
 333        sbus_writel(0xe880fc30, &fbc->alu);
 334        sbus_writel(~0, &fbc->pixelm);
 335        sbus_writel(0, &fbc->s);
 336        sbus_writel(0, &fbc->clip);
 337        sbus_writel(0xff, &fbc->pm);
 338        sbus_writel(0, &fbc->incx);
 339        sbus_writel(1, &fbc->incy);
 340        sbus_writel(x, &fbc->x0);
 341        sbus_writel(x + fontwidth(p) - 1, &fbc->x1);
 342        sbus_writel(y, &fbc->y0);
 343        if (fontwidth(p) <= 8) {
 344                for (i = 0; i < fontheight(p); i++) {
 345                        u32 val = *fd++ << 24;
 346                        sbus_writel(val, &fbc->font);
 347                }
 348        } else {
 349                for (i = 0; i < fontheight(p); i++) {
 350                        u32 val = *(u16 *)fd << 16;
 351
 352                        sbus_writel(val, &fbc->font);
 353                        fd += 2;
 354                }
 355        }
 356        spin_unlock_irqrestore(&fb->lock, flags);
 357}
 358
 359static void cg6_putcs(struct vc_data *conp, struct display *p, const unsigned short *s,
 360                      int count, int yy, int xx)
 361{
 362        struct fb_info_sbusfb *fb = (struct fb_info_sbusfb *)p->fb_info;
 363        register struct cg6_fbc *fbc = fb->s.cg6.fbc;
 364        unsigned long flags;
 365        int i, x, y;
 366        u8 *fd1, *fd2, *fd3, *fd4;
 367        u16 c;
 368
 369        spin_lock_irqsave(&fb->lock, flags);
 370        do {
 371                i = sbus_readl(&fbc->s);
 372        } while (i & 0x10000000);
 373        c = scr_readw(s);
 374        sbus_writel(attr_fgcol(p, c), &fbc->fg);
 375        sbus_writel(attr_bgcol(p, c), &fbc->bg);
 376        sbus_writel(0x140000, &fbc->mode);
 377        sbus_writel(0xe880fc30, &fbc->alu);
 378        sbus_writel(~0, &fbc->pixelm);
 379        sbus_writel(0, &fbc->s);
 380        sbus_writel(0, &fbc->clip);
 381        sbus_writel(0xff, &fbc->pm);
 382        x = fb->x_margin;
 383        y = fb->y_margin;
 384        if (fontwidthlog(p))
 385                x += (xx << fontwidthlog(p));
 386        else
 387                x += xx * fontwidth(p);
 388        if (fontheightlog(p))
 389                y += (yy << fontheightlog(p));
 390        else
 391                y += (yy * fontheight(p));
 392        if (fontwidth(p) <= 8) {
 393                while (count >= 4) {
 394                        count -= 4;
 395                        sbus_writel(0, &fbc->incx);
 396                        sbus_writel(1, &fbc->incy);
 397                        sbus_writel(x, &fbc->x0);
 398                        sbus_writel((x += 4 * fontwidth(p)) - 1, &fbc->x1);
 399                        sbus_writel(y, &fbc->y0);
 400                        if (fontheightlog(p)) {
 401                                fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
 402                                fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
 403                                fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
 404                                fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) << fontheightlog(p));
 405                        } else {
 406                                fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
 407                                fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
 408                                fd3 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
 409                                fd4 = p->fontdata + ((scr_readw(s++) & p->charmask) * fontheight(p));
 410                        }
 411                        if (fontwidth(p) == 8) {
 412                                for (i = 0; i < fontheight(p); i++) {
 413                                        u32 val = ((u32)*fd4++) |
 414                                                ((((u32)*fd3++) |
 415                                                  ((((u32)*fd2++) |
 416                                                    (((u32)*fd1++)
 417                                                     << 8)) << 8)) << 8);
 418                                        sbus_writel(val, &fbc->font);
 419                                }
 420                        } else {
 421                                for (i = 0; i < fontheight(p); i++) {
 422                                        u32 val = (((u32)*fd4++) |
 423                                                   ((((u32)*fd3++) |
 424                                                     ((((u32)*fd2++) |
 425                                                       (((u32)*fd1++) 
 426                                                        << fontwidth(p))) <<
 427                                                      fontwidth(p))) <<
 428                                                    fontwidth(p))) <<
 429                                                (24 - 3 * fontwidth(p));
 430                                        sbus_writel(val, &fbc->font);
 431                                }
 432                        }
 433                }
 434        } else {
 435                while (count >= 2) {
 436                        count -= 2;
 437                        sbus_writel(0, &fbc->incx);
 438                        sbus_writel(1, &fbc->incy);
 439                        sbus_writel(x, &fbc->x0);
 440                        sbus_writel((x += 2 * fontwidth(p)) - 1, &fbc->x1);
 441                        sbus_writel(y, &fbc->y0);
 442                        if (fontheightlog(p)) {
 443                                fd1 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
 444                                fd2 = p->fontdata + ((scr_readw(s++) & p->charmask) << (fontheightlog(p) + 1));
 445                        } else {
 446                                fd1 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
 447                                fd2 = p->fontdata + (((scr_readw(s++) & p->charmask) * fontheight(p)) << 1);
 448                        }
 449                        for (i = 0; i < fontheight(p); i++) {
 450                                u32 val = ((((u32)*(u16 *)fd1) << fontwidth(p)) |
 451                                           ((u32)*(u16 *)fd2)) << (16 - fontwidth(p));
 452                                sbus_writel(val, &fbc->font);
 453                                fd1 += 2; fd2 += 2;
 454                        }
 455                }
 456        }
 457        while (count) {
 458                count--;
 459                sbus_writel(0, &fbc->incx);
 460                sbus_writel(1, &fbc->incy);
 461                sbus_writel(x, &fbc->x0);
 462                sbus_writel((x += fontwidth(p)) - 1, &fbc->x1);
 463                sbus_writel(y, &fbc->y0);
 464                if (fontheightlog(p))
 465                        i = ((scr_readw(s++) & p->charmask) << fontheightlog(p));
 466                else
 467                        i = ((scr_readw(s++) & p->charmask) * fontheight(p));
 468                if (fontwidth(p) <= 8) {
 469                        fd1 = p->fontdata + i;
 470                        for (i = 0; i < fontheight(p); i++) {
 471                                u32 val = *fd1++ << 24;
 472                                sbus_writel(val, &fbc->font);
 473                        }
 474                } else {
 475                        fd1 = p->fontdata + (i << 1);
 476                        for (i = 0; i < fontheight(p); i++) {
 477                                u32 val = *(u16 *)fd1 << 16;
 478                                sbus_writel(val, &fbc->font);
 479                                fd1 += 2;
 480                        }
 481                }
 482        }
 483        spin_unlock_irqrestore(&fb->lock, flags);
 484}
 485
 486static void cg6_revc(struct display *p, int xx, int yy)
 487{
 488        /* Not used if hw cursor */
 489}
 490
 491static void cg6_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
 492{
 493        struct bt_regs *bt = fb->s.cg6.bt;
 494        unsigned long flags;
 495        int i;
 496                
 497        spin_lock_irqsave(&fb->lock, flags);
 498        sbus_writel(index << 24, &bt->addr);
 499        for (i = index; count--; i++){
 500                sbus_writel(fb->color_map CM(i,0) << 24,
 501                            &bt->color_map);
 502                sbus_writel(fb->color_map CM(i,1) << 24,
 503                            &bt->color_map);
 504                sbus_writel(fb->color_map CM(i,2) << 24,
 505                            &bt->color_map);
 506        }
 507        spin_unlock_irqrestore(&fb->lock, flags);
 508}
 509
 510static void cg6_restore_palette (struct fb_info_sbusfb *fb)
 511{
 512        struct bt_regs *bt = fb->s.cg6.bt;
 513        unsigned long flags;
 514                
 515        spin_lock_irqsave(&fb->lock, flags);
 516        sbus_writel(0, &bt->addr);
 517        sbus_writel(0xffffffff, &bt->color_map);
 518        sbus_writel(0xffffffff, &bt->color_map);
 519        sbus_writel(0xffffffff, &bt->color_map);
 520        spin_unlock_irqrestore(&fb->lock, flags);
 521}
 522
 523static struct display_switch cg6_dispsw __initdata = {
 524        setup:          cg6_setup,
 525        bmove:          fbcon_redraw_bmove,
 526        clear:          cg6_clear,
 527        putc:           cg6_putc,
 528        putcs:          cg6_putcs,
 529        revc:           cg6_revc, 
 530        fontwidthmask:  FONTWIDTHRANGE(1,16) /* Allow fontwidths up to 16 */
 531};
 532
 533static void cg6_setcursormap (struct fb_info_sbusfb *fb, u8 *red, u8 *green, u8 *blue)
 534{
 535        struct bt_regs *bt = fb->s.cg6.bt;
 536        unsigned long flags;
 537        
 538        spin_lock_irqsave(&fb->lock, flags);
 539        sbus_writel(1 << 24, &bt->addr);
 540        sbus_writel(red[0] << 24, &bt->cursor);
 541        sbus_writel(green[0] << 24, &bt->cursor);
 542        sbus_writel(blue[0] << 24, &bt->cursor);
 543        sbus_writel(3 << 24, &bt->addr);
 544        sbus_writel(red[1] << 24, &bt->cursor);
 545        sbus_writel(green[1] << 24, &bt->cursor);
 546        sbus_writel(blue[1] << 24, &bt->cursor);
 547        spin_unlock_irqrestore(&fb->lock, flags);
 548}
 549
 550/* Set cursor shape */
 551static void cg6_setcurshape (struct fb_info_sbusfb *fb)
 552{
 553        struct cg6_thc *thc = fb->s.cg6.thc;
 554        unsigned long flags;
 555        int i;
 556
 557        spin_lock_irqsave(&fb->lock, flags);
 558        for (i = 0; i < 32; i++) {
 559                sbus_writel(fb->cursor.bits[0][i],
 560                            &thc->thc_cursmask [i]);
 561                sbus_writel(fb->cursor.bits[1][i],
 562                            &thc->thc_cursbits [i]);
 563        }
 564        spin_unlock_irqrestore(&fb->lock, flags);
 565}
 566
 567/* Load cursor information */
 568static void cg6_setcursor (struct fb_info_sbusfb *fb)
 569{
 570        unsigned int v;
 571        unsigned long flags;
 572        struct cg_cursor *c = &fb->cursor;
 573
 574        spin_lock_irqsave(&fb->lock, flags);
 575        if (c->enable)
 576                v = ((c->cpos.fbx - c->chot.fbx) << 16)
 577                    |((c->cpos.fby - c->chot.fby) & 0xffff);
 578        else
 579                /* Magic constant to turn off the cursor */
 580                v = ((65536-32) << 16) | (65536-32);
 581        sbus_writel(v, &fb->s.cg6.thc->thc_cursxy);
 582        spin_unlock_irqrestore(&fb->lock, flags);
 583}
 584
 585static void cg6_blank (struct fb_info_sbusfb *fb)
 586{
 587        unsigned long flags;
 588        u32 tmp;
 589
 590        spin_lock_irqsave(&fb->lock, flags);
 591        tmp = sbus_readl(&fb->s.cg6.thc->thc_misc);
 592        tmp &= ~CG6_THC_MISC_VIDEO;
 593        sbus_writel(tmp, &fb->s.cg6.thc->thc_misc);
 594        spin_unlock_irqrestore(&fb->lock, flags);
 595}
 596
 597static void cg6_unblank (struct fb_info_sbusfb *fb)
 598{
 599        unsigned long flags;
 600        u32 tmp;
 601
 602        spin_lock_irqsave(&fb->lock, flags);
 603        tmp = sbus_readl(&fb->s.cg6.thc->thc_misc);
 604        tmp |= CG6_THC_MISC_VIDEO;
 605        sbus_writel(tmp, &fb->s.cg6.thc->thc_misc);
 606        spin_unlock_irqrestore(&fb->lock, flags);
 607}
 608
 609static void cg6_reset (struct fb_info_sbusfb *fb)
 610{
 611        unsigned int rev, conf;
 612        struct cg6_tec *tec = fb->s.cg6.tec;
 613        struct cg6_fbc *fbc = fb->s.cg6.fbc;
 614        unsigned long flags;
 615        u32 mode, tmp;
 616        int i;
 617        
 618        spin_lock_irqsave(&fb->lock, flags);
 619
 620        /* Turn off stuff in the Transform Engine. */
 621        sbus_writel(0, &tec->tec_matrix);
 622        sbus_writel(0, &tec->tec_clip);
 623        sbus_writel(0, &tec->tec_vdc);
 624
 625        /* Take care of bugs in old revisions. */
 626        rev = (sbus_readl(fb->s.cg6.fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
 627        if (rev < 5) {
 628                conf = (sbus_readl(fb->s.cg6.fhc) & CG6_FHC_RES_MASK) |
 629                        CG6_FHC_CPU_68020 | CG6_FHC_TEST |
 630                        (11 << CG6_FHC_TEST_X_SHIFT) |
 631                        (11 << CG6_FHC_TEST_Y_SHIFT);
 632                if (rev < 2)
 633                        conf |= CG6_FHC_DST_DISABLE;
 634                sbus_writel(conf, fb->s.cg6.fhc);
 635        }
 636
 637        /* Set things in the FBC. Bad things appear to happen if we do
 638         * back to back store/loads on the mode register, so copy it
 639         * out instead. */
 640        mode = sbus_readl(&fbc->mode);
 641        do {
 642                i = sbus_readl(&fbc->s);
 643        } while (i & 0x10000000);
 644        mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
 645                       CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
 646                       CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
 647                       CG6_FBC_BDISP_MASK);
 648        mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
 649                      CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
 650                      CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
 651                      CG6_FBC_BDISP_0);
 652        sbus_writel(mode, &fbc->mode);
 653
 654        sbus_writel(0, &fbc->clip);
 655        sbus_writel(0, &fbc->offx);
 656        sbus_writel(0, &fbc->offy);
 657        sbus_writel(0, &fbc->clipminx);
 658        sbus_writel(0, &fbc->clipminy);
 659        sbus_writel(fb->type.fb_width - 1, &fbc->clipmaxx);
 660        sbus_writel(fb->type.fb_height - 1, &fbc->clipmaxy);
 661
 662        /* Enable cursor in Brooktree DAC. */
 663        sbus_writel(0x06 << 24, &fb->s.cg6.bt->addr);
 664        tmp = sbus_readl(&fb->s.cg6.bt->control);
 665        tmp |= 0x03 << 24;
 666        sbus_writel(tmp, &fb->s.cg6.bt->control);
 667
 668        spin_unlock_irqrestore(&fb->lock, flags);
 669}
 670
 671static void cg6_margins (struct fb_info_sbusfb *fb, struct display *p, int x_margin, int y_margin)
 672{
 673        p->screen_base += (y_margin - fb->y_margin) *
 674                p->line_length + (x_margin - fb->x_margin);
 675}
 676
 677static int __init cg6_rasterimg (struct fb_info *info, int start)
 678{
 679        struct fb_info_sbusfb *fb = sbusfbinfo(info);
 680        register struct cg6_fbc *fbc = fb->s.cg6.fbc;
 681        int i;
 682        
 683        do {
 684                i = sbus_readl(&fbc->s);
 685        } while (i & 0x10000000);
 686        return 0;
 687}
 688
 689static char idstring[70] __initdata = { 0 };
 690
 691char __init *cgsixfb_init(struct fb_info_sbusfb *fb)
 692{
 693        struct fb_fix_screeninfo *fix = &fb->fix;
 694        struct fb_var_screeninfo *var = &fb->var;
 695        struct display *disp = &fb->disp;
 696        struct fbtype *type = &fb->type;
 697        struct sbus_dev *sdev = fb->sbdp;
 698        unsigned long phys = sdev->reg_addrs[0].phys_addr;
 699        u32 conf;
 700        char *p;
 701        char *cardtype;
 702        struct bt_regs *bt;
 703        struct fb_ops *fbops;
 704
 705        fbops = kmalloc(sizeof(*fbops), GFP_KERNEL);
 706        if (fbops == NULL)
 707                return NULL;
 708        
 709        *fbops = *fb->info.fbops;
 710        fbops->fb_rasterimg = cg6_rasterimg;
 711        fb->info.fbops = fbops;
 712        
 713        if (prom_getbool (fb->prom_node, "dblbuf")) {
 714                type->fb_size *= 4;
 715                fix->smem_len *= 4;
 716        }
 717
 718        fix->line_length = fb->var.xres_virtual;
 719        fix->accel = FB_ACCEL_SUN_CGSIX;
 720        
 721        var->accel_flags = FB_ACCELF_TEXT;
 722        
 723        disp->scrollmode = SCROLL_YREDRAW;
 724        if (!disp->screen_base) {
 725                disp->screen_base = (char *)
 726                        sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET,
 727                                     type->fb_size, "cgsix ram");
 728        }
 729        disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
 730        fb->s.cg6.fbc = (struct cg6_fbc *)
 731                sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET,
 732                             4096, "cgsix fbc");
 733        fb->s.cg6.tec = (struct cg6_tec *)
 734                sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET,
 735                             sizeof(struct cg6_tec), "cgsix tec");
 736        fb->s.cg6.thc = (struct cg6_thc *)
 737                sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET,
 738                             sizeof(struct cg6_thc), "cgsix thc");
 739        fb->s.cg6.bt = bt = (struct bt_regs *)
 740                sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET,
 741                             sizeof(struct bt_regs), "cgsix dac");
 742        fb->s.cg6.fhc = (u32 *)
 743                sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET,
 744                             sizeof(u32), "cgsix fhc");
 745#if 0
 746        prom_printf("CG6: RES[%016lx:%016lx:%016lx]\n",
 747                    sdev->resource[0].start,
 748                    sdev->resource[0].end,
 749                    sdev->resource[0].flags);
 750        prom_printf("CG6: fbc(%p) tec(%p) thc(%p) bt(%p) fhc(%p)\n",
 751                    fb->s.cg6.fbc,
 752                    fb->s.cg6.tec,
 753                    fb->s.cg6.thc,
 754                    fb->s.cg6.bt,
 755                    fb->s.cg6.fhc);
 756        prom_halt();
 757#endif
 758        fb->dispsw = cg6_dispsw;
 759
 760        fb->margins = cg6_margins;
 761        fb->loadcmap = cg6_loadcmap;
 762        fb->setcursor = cg6_setcursor;
 763        fb->setcursormap = cg6_setcursormap;
 764        fb->setcurshape = cg6_setcurshape;
 765        fb->restore_palette = cg6_restore_palette;
 766        fb->fill = cg6_fill;
 767        fb->blank = cg6_blank;
 768        fb->unblank = cg6_unblank;
 769        fb->reset = cg6_reset;
 770        
 771        fb->physbase = phys;
 772        fb->mmap_map = cg6_mmap_map;
 773        
 774        /* Initialize Brooktree DAC */
 775        sbus_writel(0x04 << 24, &bt->addr);         /* color planes */
 776        sbus_writel(0xff << 24, &bt->control);
 777        sbus_writel(0x05 << 24, &bt->addr);
 778        sbus_writel(0x00 << 24, &bt->control);
 779        sbus_writel(0x06 << 24, &bt->addr);         /* overlay plane */
 780        sbus_writel(0x73 << 24, &bt->control);
 781        sbus_writel(0x07 << 24, &bt->addr);
 782        sbus_writel(0x00 << 24, &bt->control);
 783        
 784        conf = sbus_readl(fb->s.cg6.fhc);
 785        switch(conf & CG6_FHC_CPU_MASK) {
 786        case CG6_FHC_CPU_SPARC: p = "sparc"; break;
 787        case CG6_FHC_CPU_68020: p = "68020"; break;
 788        default: p = "i386"; break;
 789        }
 790
 791        if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
 792                if (fix->smem_len <= 0x100000) {
 793                        cardtype = "TGX";
 794                } else {
 795                        cardtype = "TGX+";
 796                }
 797        } else {
 798                if (fix->smem_len <= 0x100000) {
 799                        cardtype = "GX";
 800                } else {
 801                        cardtype = "GX+";
 802                }
 803        }
 804                                                                                
 805        sprintf(idstring, 
 806#ifdef __sparc_v9__
 807                    "cgsix at %016lx TEC Rev %x CPU %s Rev %x [%s]", phys,
 808#else   
 809                    "cgsix at %x.%08lx TEC Rev %x CPU %s Rev %x [%s]",
 810                    fb->iospace, phys, 
 811#endif
 812                    ((sbus_readl(&fb->s.cg6.thc->thc_misc) >> CG6_THC_MISC_REV_SHIFT) &
 813                     CG6_THC_MISC_REV_MASK),
 814                    p, (conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK, cardtype);
 815
 816        sprintf(fb->info.modename, "CGsix [%s]", cardtype);
 817        sprintf(fix->id, "CGsix [%s]", cardtype);
 818                    
 819        cg6_reset(fb);
 820                    
 821        return idstring;
 822}
 823
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.