linux/drivers/video/sgivwfb.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/video/sgivwfb.c -- SGI DBE frame buffer device
   3 *
   4 *      Copyright (C) 1999 Silicon Graphics, Inc.
   5 *      Jeffrey Newquist, newquist@engr.sgi.som
   6 *
   7 *  This file is subject to the terms and conditions of the GNU General Public
   8 *  License. See the file COPYING in the main directory of this archive for
   9 *  more details.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/kernel.h>
  14#include <linux/mm.h>
  15#include <linux/errno.h>
  16#include <linux/delay.h>
  17#include <linux/fb.h>
  18#include <linux/init.h>
  19#include <linux/ioport.h>
  20#include <linux/platform_device.h>
  21
  22#include <asm/io.h>
  23#include <asm/mtrr.h>
  24#include <asm/visws/sgivw.h>
  25
  26#define INCLUDE_TIMING_TABLE_DATA
  27#define DBE_REG_BASE par->regs
  28#include <video/sgivw.h>
  29
  30struct sgivw_par {
  31        struct asregs *regs;
  32        u32 cmap_fifo;
  33        u_long timing_num;
  34};
  35
  36#define FLATPANEL_SGI_1600SW    5
  37
  38/*
  39 *  RAM we reserve for the frame buffer. This defines the maximum screen
  40 *  size
  41 *
  42 *  The default can be overridden if the driver is compiled as a module
  43 */
  44
  45static int ypan = 0;
  46static int ywrap = 0;
  47
  48static int flatpanel_id = -1;
  49
  50static struct fb_fix_screeninfo sgivwfb_fix __devinitdata = {
  51        .id             = "SGI Vis WS FB",
  52        .type           = FB_TYPE_PACKED_PIXELS,
  53        .visual         = FB_VISUAL_PSEUDOCOLOR,
  54        .mmio_start     = DBE_REG_PHYS,
  55        .mmio_len       = DBE_REG_SIZE,
  56        .accel          = FB_ACCEL_NONE,
  57        .line_length    = 640,
  58};
  59
  60static struct fb_var_screeninfo sgivwfb_var __devinitdata = {
  61        /* 640x480, 8 bpp */
  62        .xres           = 640,
  63        .yres           = 480,
  64        .xres_virtual   = 640,
  65        .yres_virtual   = 480,
  66        .bits_per_pixel = 8,
  67        .red            = { 0, 8, 0 },
  68        .green          = { 0, 8, 0 },
  69        .blue           = { 0, 8, 0 },
  70        .height         = -1,
  71        .width          = -1,
  72        .pixclock       = 20000,
  73        .left_margin    = 64,
  74        .right_margin   = 64,
  75        .upper_margin   = 32,
  76        .lower_margin   = 32,
  77        .hsync_len      = 64,
  78        .vsync_len      = 2,
  79        .vmode          = FB_VMODE_NONINTERLACED
  80};
  81
  82static struct fb_var_screeninfo sgivwfb_var1600sw __devinitdata = {
  83        /* 1600x1024, 8 bpp */
  84        .xres           = 1600,
  85        .yres           = 1024,
  86        .xres_virtual   = 1600,
  87        .yres_virtual   = 1024,
  88        .bits_per_pixel = 8,
  89        .red            = { 0, 8, 0 },
  90        .green          = { 0, 8, 0 },
  91        .blue           = { 0, 8, 0 },
  92        .height         = -1,
  93        .width          = -1,
  94        .pixclock       = 9353,
  95        .left_margin    = 20,
  96        .right_margin   = 30,
  97        .upper_margin   = 37,
  98        .lower_margin   = 3,
  99        .hsync_len      = 20,
 100        .vsync_len      = 3,
 101        .vmode          = FB_VMODE_NONINTERLACED
 102};
 103
 104/*
 105 *  Interface used by the world
 106 */
 107int sgivwfb_init(void);
 108
 109static int sgivwfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
 110static int sgivwfb_set_par(struct fb_info *info);
 111static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
 112                             u_int blue, u_int transp,
 113                             struct fb_info *info);
 114static int sgivwfb_mmap(struct fb_info *info,
 115                        struct vm_area_struct *vma);
 116
 117static struct fb_ops sgivwfb_ops = {
 118        .owner          = THIS_MODULE,
 119        .fb_check_var   = sgivwfb_check_var,
 120        .fb_set_par     = sgivwfb_set_par,
 121        .fb_setcolreg   = sgivwfb_setcolreg,
 122        .fb_fillrect    = cfb_fillrect,
 123        .fb_copyarea    = cfb_copyarea,
 124        .fb_imageblit   = cfb_imageblit,
 125        .fb_mmap        = sgivwfb_mmap,
 126};
 127
 128/*
 129 *  Internal routines
 130 */
 131static unsigned long bytes_per_pixel(int bpp)
 132{
 133        switch (bpp) {
 134                case 8:
 135                        return 1;
 136                case 16:
 137                        return 2;
 138                case 32:
 139                        return 4;
 140                default:
 141                        printk(KERN_INFO "sgivwfb: unsupported bpp %d\n", bpp);
 142                        return 0;
 143        }
 144}
 145
 146static unsigned long get_line_length(int xres_virtual, int bpp)
 147{
 148        return (xres_virtual * bytes_per_pixel(bpp));
 149}
 150
 151/*
 152 * Function:    dbe_TurnOffDma
 153 * Parameters:  (None)
 154 * Description: This should turn off the monitor and dbe.  This is used
 155 *              when switching between the serial console and the graphics
 156 *              console.
 157 */
 158
 159static void dbe_TurnOffDma(struct sgivw_par *par)
 160{
 161        unsigned int readVal;
 162        int i;
 163
 164        // Check to see if things are already turned off:
 165        // 1) Check to see if dbe is not using the internal dotclock.
 166        // 2) Check to see if the xy counter in dbe is already off.
 167
 168        DBE_GETREG(ctrlstat, readVal);
 169        if (GET_DBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2)
 170                return;
 171
 172        DBE_GETREG(vt_xy, readVal);
 173        if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1)
 174                return;
 175
 176        // Otherwise, turn off dbe
 177
 178        DBE_GETREG(ovr_control, readVal);
 179        SET_DBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0);
 180        DBE_SETREG(ovr_control, readVal);
 181        udelay(1000);
 182        DBE_GETREG(frm_control, readVal);
 183        SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0);
 184        DBE_SETREG(frm_control, readVal);
 185        udelay(1000);
 186        DBE_GETREG(did_control, readVal);
 187        SET_DBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0);
 188        DBE_SETREG(did_control, readVal);
 189        udelay(1000);
 190
 191        // XXX HACK:
 192        //
 193        //    This was necessary for GBE--we had to wait through two
 194        //    vertical retrace periods before the pixel DMA was
 195        //    turned off for sure.  I've left this in for now, in
 196        //    case dbe needs it.
 197
 198        for (i = 0; i < 10000; i++) {
 199                DBE_GETREG(frm_inhwctrl, readVal);
 200                if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) ==
 201                    0)
 202                        udelay(10);
 203                else {
 204                        DBE_GETREG(ovr_inhwctrl, readVal);
 205                        if (GET_DBE_FIELD
 206                            (OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0)
 207                                udelay(10);
 208                        else {
 209                                DBE_GETREG(did_inhwctrl, readVal);
 210                                if (GET_DBE_FIELD
 211                                    (DID_INHWCTRL, DID_DMA_ENABLE,
 212                                     readVal) == 0)
 213                                        udelay(10);
 214                                else
 215                                        break;
 216                        }
 217                }
 218        }
 219}
 220
 221/*
 222 *  Set the User Defined Part of the Display. Again if par use it to get
 223 *  real video mode.
 224 */
 225static int sgivwfb_check_var(struct fb_var_screeninfo *var, 
 226                             struct fb_info *info)
 227{
 228        struct sgivw_par *par = (struct sgivw_par *)info->par;
 229        struct dbe_timing_info *timing;
 230        u_long line_length;
 231        u_long min_mode;
 232        int req_dot;
 233        int test_mode;
 234
 235        /*
 236         *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
 237         *  as FB_VMODE_SMOOTH_XPAN is only used internally
 238         */
 239
 240        if (var->vmode & FB_VMODE_CONUPDATE) {
 241                var->vmode |= FB_VMODE_YWRAP;
 242                var->xoffset = info->var.xoffset;
 243                var->yoffset = info->var.yoffset;
 244        }
 245
 246        /* XXX FIXME - forcing var's */
 247        var->xoffset = 0;
 248        var->yoffset = 0;
 249
 250        /* Limit bpp to 8, 16, and 32 */
 251        if (var->bits_per_pixel <= 8)
 252                var->bits_per_pixel = 8;
 253        else if (var->bits_per_pixel <= 16)
 254                var->bits_per_pixel = 16;
 255        else if (var->bits_per_pixel <= 32)
 256                var->bits_per_pixel = 32;
 257        else
 258                return -EINVAL;
 259
 260        var->grayscale = 0;     /* No grayscale for now */
 261
 262        /* determine valid resolution and timing */
 263        for (min_mode = 0; min_mode < ARRAY_SIZE(dbeVTimings); min_mode++) {
 264                if (dbeVTimings[min_mode].width >= var->xres &&
 265                    dbeVTimings[min_mode].height >= var->yres)
 266                        break;
 267        }
 268
 269        if (min_mode == ARRAY_SIZE(dbeVTimings))
 270                return -EINVAL; /* Resolution to high */
 271
 272        /* XXX FIXME - should try to pick best refresh rate */
 273        /* for now, pick closest dot-clock within 3MHz */
 274        req_dot = PICOS2KHZ(var->pixclock);
 275        printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n",
 276               var->pixclock, req_dot);
 277        test_mode = min_mode;
 278        while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) {
 279                if (dbeVTimings[test_mode].cfreq + 3000 > req_dot)
 280                        break;
 281                test_mode++;
 282        }
 283        if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width)
 284                test_mode--;
 285        min_mode = test_mode;
 286        timing = &dbeVTimings[min_mode];
 287        printk(KERN_INFO "sgivwfb: granted dot-clock=%d KHz\n", timing->cfreq);
 288
 289        /* Adjust virtual resolution, if necessary */
 290        if (var->xres > var->xres_virtual || (!ywrap && !ypan))
 291                var->xres_virtual = var->xres;
 292        if (var->yres > var->yres_virtual || (!ywrap && !ypan))
 293                var->yres_virtual = var->yres;
 294
 295        /*
 296         *  Memory limit
 297         */
 298        line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
 299        if (line_length * var->yres_virtual > sgivwfb_mem_size)
 300                return -ENOMEM; /* Virtual resolution to high */
 301
 302        info->fix.line_length = line_length;
 303
 304        switch (var->bits_per_pixel) {
 305        case 8:
 306                var->red.offset = 0;
 307                var->red.length = 8;
 308                var->green.offset = 0;
 309                var->green.length = 8;
 310                var->blue.offset = 0;
 311                var->blue.length = 8;
 312                var->transp.offset = 0;
 313                var->transp.length = 0;
 314                break;
 315        case 16:                /* RGBA 5551 */
 316                var->red.offset = 11;
 317                var->red.length = 5;
 318                var->green.offset = 6;
 319                var->green.length = 5;
 320                var->blue.offset = 1;
 321                var->blue.length = 5;
 322                var->transp.offset = 0;
 323                var->transp.length = 0;
 324                break;
 325        case 32:                /* RGB 8888 */
 326                var->red.offset = 0;
 327                var->red.length = 8;
 328                var->green.offset = 8;
 329                var->green.length = 8;
 330                var->blue.offset = 16;
 331                var->blue.length = 8;
 332                var->transp.offset = 24;
 333                var->transp.length = 8;
 334                break;
 335        }
 336        var->red.msb_right = 0;
 337        var->green.msb_right = 0;
 338        var->blue.msb_right = 0;
 339        var->transp.msb_right = 0;
 340
 341        /* set video timing information */
 342        var->pixclock = KHZ2PICOS(timing->cfreq);
 343        var->left_margin = timing->htotal - timing->hsync_end;
 344        var->right_margin = timing->hsync_start - timing->width;
 345        var->upper_margin = timing->vtotal - timing->vsync_end;
 346        var->lower_margin = timing->vsync_start - timing->height;
 347        var->hsync_len = timing->hsync_end - timing->hsync_start;
 348        var->vsync_len = timing->vsync_end - timing->vsync_start;
 349
 350        /* Ouch. This breaks the rules but timing_num is only important if you
 351        * change a video mode */
 352        par->timing_num = min_mode;
 353
 354        printk(KERN_INFO "sgivwfb: new video mode xres=%d yres=%d bpp=%d\n",
 355                var->xres, var->yres, var->bits_per_pixel);
 356        printk(KERN_INFO "         vxres=%d vyres=%d\n", var->xres_virtual,
 357                var->yres_virtual);
 358        return 0;
 359}
 360
 361/*
 362 *  Setup flatpanel related registers.
 363 */
 364static void sgivwfb_setup_flatpanel(struct sgivw_par *par, struct dbe_timing_info *currentTiming)
 365{
 366        int fp_wid, fp_hgt, fp_vbs, fp_vbe;
 367        u32 outputVal = 0;
 368
 369        SET_DBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal, 
 370                (currentTiming->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);
 371        SET_DBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal, 
 372                (currentTiming->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);
 373        DBE_SETREG(vt_flags, outputVal);
 374
 375        /* Turn on the flat panel */
 376        switch (flatpanel_id) {
 377                case FLATPANEL_SGI_1600SW:
 378                        fp_wid = 1600;
 379                        fp_hgt = 1024;
 380                        fp_vbs = 0;
 381                        fp_vbe = 1600;
 382                        currentTiming->pll_m = 4;
 383                        currentTiming->pll_n = 1;
 384                        currentTiming->pll_p = 0;
 385                        break;
 386                default:
 387                        fp_wid = fp_hgt = fp_vbs = fp_vbe = 0xfff;
 388        }
 389
 390        outputVal = 0;
 391        SET_DBE_FIELD(FP_DE, FP_DE_ON, outputVal, fp_vbs);
 392        SET_DBE_FIELD(FP_DE, FP_DE_OFF, outputVal, fp_vbe);
 393        DBE_SETREG(fp_de, outputVal);
 394        outputVal = 0;
 395        SET_DBE_FIELD(FP_HDRV, FP_HDRV_OFF, outputVal, fp_wid);
 396        DBE_SETREG(fp_hdrv, outputVal);
 397        outputVal = 0;
 398        SET_DBE_FIELD(FP_VDRV, FP_VDRV_ON, outputVal, 1);
 399        SET_DBE_FIELD(FP_VDRV, FP_VDRV_OFF, outputVal, fp_hgt + 1);
 400        DBE_SETREG(fp_vdrv, outputVal);
 401}
 402
 403/*
 404 *  Set the hardware according to 'par'.
 405 */
 406static int sgivwfb_set_par(struct fb_info *info)
 407{
 408        struct sgivw_par *par = info->par;
 409        int i, j, htmp, temp;
 410        u32 readVal, outputVal;
 411        int wholeTilesX, maxPixelsPerTileX;
 412        int frmWrite1, frmWrite2, frmWrite3b;
 413        struct dbe_timing_info *currentTiming; /* Current Video Timing */
 414        int xpmax, ypmax;       // Monitor resolution
 415        int bytesPerPixel;      // Bytes per pixel
 416
 417        currentTiming = &dbeVTimings[par->timing_num];
 418        bytesPerPixel = bytes_per_pixel(info->var.bits_per_pixel);
 419        xpmax = currentTiming->width;
 420        ypmax = currentTiming->height;
 421
 422        /* dbe_InitGraphicsBase(); */
 423        /* Turn on dotclock PLL */
 424        DBE_SETREG(ctrlstat, 0x20000000);
 425
 426        dbe_TurnOffDma(par);
 427
 428        /* dbe_CalculateScreenParams(); */
 429        maxPixelsPerTileX = 512 / bytesPerPixel;
 430        wholeTilesX = xpmax / maxPixelsPerTileX;
 431        if (wholeTilesX * maxPixelsPerTileX < xpmax)
 432                wholeTilesX++;
 433
 434        printk(KERN_DEBUG "sgivwfb: pixPerTile=%d wholeTilesX=%d\n",
 435               maxPixelsPerTileX, wholeTilesX);
 436
 437        /* dbe_InitGammaMap(); */
 438        udelay(10);
 439
 440        for (i = 0; i < 256; i++) {
 441                DBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8));
 442        }
 443
 444        /* dbe_TurnOn(); */
 445        DBE_GETREG(vt_xy, readVal);
 446        if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) {
 447                DBE_SETREG(vt_xy, 0x00000000);
 448                udelay(1);
 449        } else
 450                dbe_TurnOffDma(par);
 451
 452        /* dbe_Initdbe(); */
 453        for (i = 0; i < 256; i++) {
 454                for (j = 0; j < 100; j++) {
 455                        DBE_GETREG(cm_fifo, readVal);
 456                        if (readVal != 0x00000000)
 457                                break;
 458                        else
 459                                udelay(10);
 460                }
 461
 462                // DBE_ISETREG(cmap, i, 0x00000000);
 463                DBE_ISETREG(cmap, i, (i << 8) | (i << 16) | (i << 24));
 464        }
 465
 466        /* dbe_InitFramebuffer(); */
 467        frmWrite1 = 0;
 468        SET_DBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1,
 469                      wholeTilesX);
 470        SET_DBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, 0);
 471
 472        switch (bytesPerPixel) {
 473        case 1:
 474                SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
 475                              DBE_FRM_DEPTH_8);
 476                break;
 477        case 2:
 478                SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
 479                              DBE_FRM_DEPTH_16);
 480                break;
 481        case 4:
 482                SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1,
 483                              DBE_FRM_DEPTH_32);
 484                break;
 485        }
 486
 487        frmWrite2 = 0;
 488        SET_DBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax);
 489
 490        // Tell dbe about the framebuffer location and type
 491        // XXX What format is the FRM_TILE_PTR??  64K aligned address?
 492        frmWrite3b = 0;
 493        SET_DBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b,
 494                      sgivwfb_mem_phys >> 9);
 495        SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1);
 496        SET_DBE_FIELD(FRM_CONTROL, FRM_LINEAR, frmWrite3b, 1);
 497
 498        /* Initialize DIDs */
 499
 500        outputVal = 0;
 501        switch (bytesPerPixel) {
 502        case 1:
 503                SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_I8);
 504                break;
 505        case 2:
 506                SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGBA5);
 507                break;
 508        case 4:
 509                SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGB8);
 510                break;
 511        }
 512        SET_DBE_FIELD(WID, BUF, outputVal, DBE_BMODE_BOTH);
 513
 514        for (i = 0; i < 32; i++) {
 515                DBE_ISETREG(mode_regs, i, outputVal);
 516        }
 517
 518        /* dbe_InitTiming(); */
 519        DBE_SETREG(vt_intr01, 0xffffffff);
 520        DBE_SETREG(vt_intr23, 0xffffffff);
 521
 522        DBE_GETREG(dotclock, readVal);
 523        DBE_SETREG(dotclock, readVal & 0xffff);
 524
 525        DBE_SETREG(vt_xymax, 0x00000000);
 526        outputVal = 0;
 527        SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal,
 528                      currentTiming->vsync_start);
 529        SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal,
 530                      currentTiming->vsync_end);
 531        DBE_SETREG(vt_vsync, outputVal);
 532        outputVal = 0;
 533        SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal,
 534                      currentTiming->hsync_start);
 535        SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal,
 536                      currentTiming->hsync_end);
 537        DBE_SETREG(vt_hsync, outputVal);
 538        outputVal = 0;
 539        SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal,
 540                      currentTiming->vblank_start);
 541        SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal,
 542                      currentTiming->vblank_end);
 543        DBE_SETREG(vt_vblank, outputVal);
 544        outputVal = 0;
 545        SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal,
 546                      currentTiming->hblank_start);
 547        SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal,
 548                      currentTiming->hblank_end - 3);
 549        DBE_SETREG(vt_hblank, outputVal);
 550        outputVal = 0;
 551        SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal,
 552                      currentTiming->vblank_start);
 553        SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal,
 554                      currentTiming->vblank_end);
 555        DBE_SETREG(vt_vcmap, outputVal);
 556        outputVal = 0;
 557        SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal,
 558                      currentTiming->hblank_start);
 559        SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal,
 560                      currentTiming->hblank_end - 3);
 561        DBE_SETREG(vt_hcmap, outputVal);
 562
 563        if (flatpanel_id != -1)
 564                sgivwfb_setup_flatpanel(par, currentTiming);
 565
 566        outputVal = 0;
 567        temp = currentTiming->vblank_start - currentTiming->vblank_end - 1;
 568        if (temp > 0)
 569                temp = -temp;
 570
 571        SET_DBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32) temp);
 572        if (currentTiming->hblank_end >= 20)
 573                SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal,
 574                              currentTiming->hblank_end - 20);
 575        else
 576                SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal,
 577                              currentTiming->htotal - (20 -
 578                                                       currentTiming->
 579                                                       hblank_end));
 580        DBE_SETREG(did_start_xy, outputVal);
 581
 582        outputVal = 0;
 583        SET_DBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal,
 584                      (u32) (temp + 1));
 585        if (currentTiming->hblank_end >= DBE_CRS_MAGIC)
 586                SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal,
 587                              currentTiming->hblank_end - DBE_CRS_MAGIC);
 588        else
 589                SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal,
 590                              currentTiming->htotal - (DBE_CRS_MAGIC -
 591                                                       currentTiming->
 592                                                       hblank_end));
 593        DBE_SETREG(crs_start_xy, outputVal);
 594
 595        outputVal = 0;
 596        SET_DBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32) temp);
 597        SET_DBE_FIELD(VC_START_XY, VC_STARTX, outputVal,
 598                      currentTiming->hblank_end - 4);
 599        DBE_SETREG(vc_start_xy, outputVal);
 600
 601        DBE_SETREG(frm_size_tile, frmWrite1);
 602        DBE_SETREG(frm_size_pixel, frmWrite2);
 603
 604        outputVal = 0;
 605        SET_DBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m - 1);
 606        SET_DBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n - 1);
 607        SET_DBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p);
 608        SET_DBE_FIELD(DOTCLK, RUN, outputVal, 1);
 609        DBE_SETREG(dotclock, outputVal);
 610
 611        udelay(11 * 1000);
 612
 613        DBE_SETREG(vt_vpixen, 0xffffff);
 614        DBE_SETREG(vt_hpixen, 0xffffff);
 615
 616        outputVal = 0;
 617        SET_DBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal);
 618        SET_DBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal);
 619        DBE_SETREG(vt_xymax, outputVal);
 620
 621        outputVal = frmWrite1;
 622        SET_DBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1);
 623        DBE_SETREG(frm_size_tile, outputVal);
 624        DBE_SETREG(frm_size_tile, frmWrite1);
 625
 626        outputVal = 0;
 627        SET_DBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1);
 628        DBE_SETREG(ovr_width_tile, outputVal);
 629        DBE_SETREG(ovr_width_tile, 0);
 630
 631        DBE_SETREG(frm_control, frmWrite3b);
 632        DBE_SETREG(did_control, 0);
 633
 634        // Wait for dbe to take frame settings
 635        for (i = 0; i < 100000; i++) {
 636                DBE_GETREG(frm_inhwctrl, readVal);
 637                if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) !=
 638                    0)
 639                        break;
 640                else
 641                        udelay(1);
 642        }
 643
 644        if (i == 100000)
 645                printk(KERN_INFO
 646                       "sgivwfb: timeout waiting for frame DMA enable.\n");
 647
 648        outputVal = 0;
 649        htmp = currentTiming->hblank_end - 19;
 650        if (htmp < 0)
 651                htmp += currentTiming->htotal;  /* allow blank to wrap around */
 652        SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp);
 653        SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal,
 654                      ((htmp + currentTiming->width -
 655                        2) % currentTiming->htotal));
 656        DBE_SETREG(vt_hpixen, outputVal);
 657
 658        outputVal = 0;
 659        SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal,
 660                      currentTiming->vblank_start);
 661        SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal,
 662                      currentTiming->vblank_end);
 663        DBE_SETREG(vt_vpixen, outputVal);
 664
 665        // Turn off mouse cursor
 666        par->regs->crs_ctl = 0;
 667
 668        // XXX What's this section for??
 669        DBE_GETREG(ctrlstat, readVal);
 670        readVal &= 0x02000000;
 671
 672        if (readVal != 0) {
 673                DBE_SETREG(ctrlstat, 0x30000000);
 674        }
 675        return 0;
 676}
 677
 678/*
 679 *  Set a single color register. The values supplied are already
 680 *  rounded down to the hardware's capabilities (according to the
 681 *  entries in the var structure). Return != 0 for invalid regno.
 682 */
 683
 684static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,
 685                             u_int blue, u_int transp,
 686                             struct fb_info *info)
 687{
 688        struct sgivw_par *par = (struct sgivw_par *) info->par;
 689
 690        if (regno > 255)
 691                return 1;
 692        red >>= 8;
 693        green >>= 8;
 694        blue >>= 8;
 695
 696        /* wait for the color map FIFO to have a free entry */
 697        while (par->cmap_fifo == 0)
 698                par->cmap_fifo = par->regs->cm_fifo;
 699
 700        par->regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
 701        par->cmap_fifo--;       /* assume FIFO is filling up */
 702        return 0;
 703}
 704
 705static int sgivwfb_mmap(struct fb_info *info,
 706                        struct vm_area_struct *vma)
 707{
 708        unsigned long size = vma->vm_end - vma->vm_start;
 709        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 710
 711        if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
 712                return -EINVAL;
 713        if (offset + size > sgivwfb_mem_size)
 714                return -EINVAL;
 715        offset += sgivwfb_mem_phys;
 716        pgprot_val(vma->vm_page_prot) =
 717            pgprot_val(vma->vm_page_prot) | _PAGE_PCD;
 718        vma->vm_flags |= VM_IO;
 719        if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
 720                                                size, vma->vm_page_prot))
 721                return -EAGAIN;
 722        printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
 723               offset, vma->vm_start);
 724        return 0;
 725}
 726
 727int __init sgivwfb_setup(char *options)
 728{
 729        char *this_opt;
 730
 731        if (!options || !*options)
 732                return 0;
 733
 734        while ((this_opt = strsep(&options, ",")) != NULL) {
 735                if (!strncmp(this_opt, "monitor:", 8)) {
 736                        if (!strncmp(this_opt + 8, "crt", 3))
 737                                flatpanel_id = -1;
 738                        else if (!strncmp(this_opt + 8, "1600sw", 6))
 739                                flatpanel_id = FLATPANEL_SGI_1600SW;
 740                }
 741        }
 742        return 0;
 743}
 744
 745/*
 746 *  Initialisation
 747 */
 748static int __devinit sgivwfb_probe(struct platform_device *dev)
 749{
 750        struct sgivw_par *par;
 751        struct fb_info *info;
 752        char *monitor;
 753
 754        info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 16, &dev->dev);
 755        if (!info)
 756                return -ENOMEM;
 757        par = info->par;
 758
 759        if (!request_mem_region(DBE_REG_PHYS, DBE_REG_SIZE, "sgivwfb")) {
 760                printk(KERN_ERR "sgivwfb: couldn't reserve mmio region\n");
 761                framebuffer_release(info);
 762                return -EBUSY;
 763        }
 764
 765        par->regs = (struct asregs *) ioremap_nocache(DBE_REG_PHYS, DBE_REG_SIZE);
 766        if (!par->regs) {
 767                printk(KERN_ERR "sgivwfb: couldn't ioremap registers\n");
 768                goto fail_ioremap_regs;
 769        }
 770
 771        mtrr_add(sgivwfb_mem_phys, sgivwfb_mem_size, MTRR_TYPE_WRCOMB, 1);
 772
 773        sgivwfb_fix.smem_start = sgivwfb_mem_phys;
 774        sgivwfb_fix.smem_len = sgivwfb_mem_size;
 775        sgivwfb_fix.ywrapstep = ywrap;
 776        sgivwfb_fix.ypanstep = ypan;
 777
 778        info->fix = sgivwfb_fix;
 779
 780        switch (flatpanel_id) {
 781                case FLATPANEL_SGI_1600SW:
 782                        info->var = sgivwfb_var1600sw;
 783                        monitor = "SGI 1600SW flatpanel";
 784                        break;
 785                default:
 786                        info->var = sgivwfb_var;
 787                        monitor = "CRT";
 788        }
 789
 790        printk(KERN_INFO "sgivwfb: %s monitor selected\n", monitor);
 791
 792        info->fbops = &sgivwfb_ops;
 793        info->pseudo_palette = (void *) (par + 1);
 794        info->flags = FBINFO_DEFAULT;
 795
 796        info->screen_base = ioremap_nocache((unsigned long) sgivwfb_mem_phys, sgivwfb_mem_size);
 797        if (!info->screen_base) {
 798                printk(KERN_ERR "sgivwfb: couldn't ioremap screen_base\n");
 799                goto fail_ioremap_fbmem;
 800        }
 801
 802        if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
 803                goto fail_color_map;
 804
 805        if (register_framebuffer(info) < 0) {
 806                printk(KERN_ERR "sgivwfb: couldn't register framebuffer\n");
 807                goto fail_register_framebuffer;
 808        }
 809
 810        platform_set_drvdata(dev, info);
 811
 812        printk(KERN_INFO "fb%d: SGI DBE frame buffer device, using %ldK of video memory at %#lx\n",      
 813                info->node, sgivwfb_mem_size >> 10, sgivwfb_mem_phys);
 814        return 0;
 815
 816fail_register_framebuffer:
 817        fb_dealloc_cmap(&info->cmap);
 818fail_color_map:
 819        iounmap((char *) info->screen_base);
 820fail_ioremap_fbmem:
 821        iounmap(par->regs);
 822fail_ioremap_regs:
 823        release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE);
 824        framebuffer_release(info);
 825        return -ENXIO;
 826}
 827
 828static int __devexit sgivwfb_remove(struct platform_device *dev)
 829{
 830        struct fb_info *info = platform_get_drvdata(dev);
 831
 832        if (info) {
 833                struct sgivw_par *par = info->par;
 834
 835                unregister_framebuffer(info);
 836                dbe_TurnOffDma(par);
 837                iounmap(par->regs);
 838                iounmap(info->screen_base);
 839                release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE);
 840                fb_dealloc_cmap(&info->cmap);
 841                framebuffer_release(info);
 842        }
 843        return 0;
 844}
 845
 846static struct platform_driver sgivwfb_driver = {
 847        .probe  = sgivwfb_probe,
 848        .remove = __devexit_p(sgivwfb_remove),
 849        .driver = {
 850                .name   = "sgivwfb",
 851        },
 852};
 853
 854static struct platform_device *sgivwfb_device;
 855
 856int __init sgivwfb_init(void)
 857{
 858        int ret;
 859
 860#ifndef MODULE
 861        char *option = NULL;
 862
 863        if (fb_get_options("sgivwfb", &option))
 864                return -ENODEV;
 865        sgivwfb_setup(option);
 866#endif
 867        ret = platform_driver_register(&sgivwfb_driver);
 868        if (!ret) {
 869                sgivwfb_device = platform_device_alloc("sgivwfb", 0);
 870                if (sgivwfb_device) {
 871                        ret = platform_device_add(sgivwfb_device);
 872                } else
 873                        ret = -ENOMEM;
 874                if (ret) {
 875                        platform_driver_unregister(&sgivwfb_driver);
 876                        platform_device_put(sgivwfb_device);
 877                }
 878        }
 879        return ret;
 880}
 881
 882module_init(sgivwfb_init);
 883
 884#ifdef MODULE
 885MODULE_LICENSE("GPL");
 886
 887static void __exit sgivwfb_exit(void)
 888{
 889        platform_device_unregister(sgivwfb_device);
 890        platform_driver_unregister(&sgivwfb_driver);
 891}
 892
 893module_exit(sgivwfb_exit);
 894
 895#endif                          /* MODULE */
 896
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.