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 // 192 // This was necessary for GBE--we had to wait through two 193 // vertical retrace periods before the pixel DMA was 194 // turned off for sure. I've left this in for now, in 195 // case dbe needs it. 196 197 for (i = 0; i < 10000; i++) { 198 DBE_GETREG(frm_inhwctrl, readVal); 199 if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) == 200 0) 201 udelay(10); 202 else { 203 DBE_GETREG(ovr_inhwctrl, readVal); 204 if (GET_DBE_FIELD 205 (OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0) 206 udelay(10); 207 else { 208 DBE_GETREG(did_inhwctrl, readVal); 209 if (GET_DBE_FIELD 210 (DID_INHWCTRL, DID_DMA_ENABLE, 211 readVal) == 0) 212 udelay(10); 213 else 214 break; 215 } 216 } 217 } 218} 219 220/* 221 * Set the User Defined Part of the Display. Again if par use it to get 222 * real video mode. 223 */ 224static int sgivwfb_check_var(struct fb_var_screeninfo *var, 225 struct fb_info *info) 226{ 227 struct sgivw_par *par = (struct sgivw_par *)info->par; 228 struct dbe_timing_info *timing; 229 u_long line_length; 230 u_long min_mode; 231 int req_dot; 232 int test_mode; 233 234 /* 235 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! 236 * as FB_VMODE_SMOOTH_XPAN is only used internally 237 */ 238 239 if (var->vmode & FB_VMODE_CONUPDATE) { 240 var->vmode |= FB_VMODE_YWRAP; 241 var->xoffset = info->var.xoffset; 242 var->yoffset = info->var.yoffset; 243 } 244 245 var->xoffset = 0; 246 var->yoffset = 0; 247 248 /* Limit bpp to 8, 16, and 32 */ 249 if (var->bits_per_pixel <= 8) 250 var->bits_per_pixel = 8; 251 else if (var->bits_per_pixel <= 16) 252 var->bits_per_pixel = 16; 253 else if (var->bits_per_pixel <= 32) 254 var->bits_per_pixel = 32; 255 else 256 return -EINVAL; 257 258 var->grayscale = 0; /* No grayscale for now */ 259 260 /* determine valid resolution and timing */ 261 for (min_mode = 0; min_mode < ARRAY_SIZE(dbeVTimings); min_mode++) { 262 if (dbeVTimings[min_mode].width >= var->xres && 263 dbeVTimings[min_mode].height >= var->yres) 264 break; 265 } 266 267 if (min_mode == ARRAY_SIZE(dbeVTimings)) 268 return -EINVAL; /* Resolution to high */ 269 270 /* for now, pick closest dot-clock within 3MHz */ 271 req_dot = PICOS2KHZ(var->pixclock); 272 printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n", 273 var->pixclock, req_dot); 274 test_mode = min_mode; 275 while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) { 276 if (dbeVTimings[test_mode].cfreq + 3000 > req_dot) 277 break; 278 test_mode++; 279 } 280 if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width) 281 test_mode--; 282 min_mode = test_mode; 283 timing = &dbeVTimings[min_mode]; 284 printk(KERN_INFO "sgivwfb: granted dot-clock=%d KHz\n", timing->cfreq); 285 286 /* Adjust virtual resolution, if necessary */ 287 if (var->xres > var->xres_virtual || (!ywrap && !ypan)) 288 var->xres_virtual = var->xres; 289 if (var->yres > var->yres_virtual || (!ywrap && !ypan)) 290 var->yres_virtual = var->yres; 291 292 /* 293 * Memory limit 294 */ 295 line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); 296 if (line_length * var->yres_virtual > sgivwfb_mem_size) 297 return -ENOMEM; /* Virtual resolution to high */ 298 299 info->fix.line_length = line_length; 300 301 switch (var->bits_per_pixel) { 302 case 8: 303 var->red.offset = 0; 304 var->red.length = 8; 305 var->green.offset = 0; 306 var->green.length = 8; 307 var->blue.offset = 0; 308 var->blue.length = 8; 309 var->transp.offset = 0; 310 var->transp.length = 0; 311 break; 312 case 16: /* RGBA 5551 */ 313 var->red.offset = 11; 314 var->red.length = 5; 315 var->green.offset = 6; 316 var->green.length = 5; 317 var->blue.offset = 1; 318 var->blue.length = 5; 319 var->transp.offset = 0; 320 var->transp.length = 0; 321 break; 322 case 32: /* RGB 8888 */ 323 var->red.offset = 0; 324 var->red.length = 8; 325 var->green.offset = 8; 326 var->green.length = 8; 327 var->blue.offset = 16; 328 var->blue.length = 8; 329 var->transp.offset = 24; 330 var->transp.length = 8; 331 break; 332 } 333 var->red.msb_right = 0; 334 var->green.msb_right = 0; 335 var->blue.msb_right = 0; 336 var->transp.msb_right = 0; 337 338 /* set video timing information */ 339 var->pixclock = KHZ2PICOS(timing->cfreq); 340 var->left_margin = timing->htotal - timing->hsync_end; 341 var->right_margin = timing->hsync_start - timing->width; 342 var->upper_margin = timing->vtotal - timing->vsync_end; 343 var->lower_margin = timing->vsync_start - timing->height; 344 var->hsync_len = timing->hsync_end - timing->hsync_start; 345 var->vsync_len = timing->vsync_end - timing->vsync_start; 346 347 /* Ouch. This breaks the rules but timing_num is only important if you 348 * change a video mode */ 349 par->timing_num = min_mode; 350 351 printk(KERN_INFO "sgivwfb: new video mode xres=%d yres=%d bpp=%d\n", 352 var->xres, var->yres, var->bits_per_pixel); 353 printk(KERN_INFO " vxres=%d vyres=%d\n", var->xres_virtual, 354 var->yres_virtual); 355 return 0; 356} 357 358/* 359 * Setup flatpanel related registers. 360 */ 361static void sgivwfb_setup_flatpanel(struct sgivw_par *par, struct dbe_timing_info *currentTiming) 362{ 363 int fp_wid, fp_hgt, fp_vbs, fp_vbe; 364 u32 outputVal = 0; 365 366 SET_DBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal, 367 (currentTiming->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1); 368 SET_DBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal, 369 (currentTiming->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1); 370 DBE_SETREG(vt_flags, outputVal); 371 372 /* Turn on the flat panel */ 373 switch (flatpanel_id) { 374 case FLATPANEL_SGI_1600SW: 375 fp_wid = 1600; 376 fp_hgt = 1024; 377 fp_vbs = 0; 378 fp_vbe = 1600; 379 currentTiming->pll_m = 4; 380 currentTiming->pll_n = 1; 381 currentTiming->pll_p = 0; 382 break; 383 default: 384 fp_wid = fp_hgt = fp_vbs = fp_vbe = 0xfff; 385 } 386 387 outputVal = 0; 388 SET_DBE_FIELD(FP_DE, FP_DE_ON, outputVal, fp_vbs); 389 SET_DBE_FIELD(FP_DE, FP_DE_OFF, outputVal, fp_vbe); 390 DBE_SETREG(fp_de, outputVal); 391 outputVal = 0; 392 SET_DBE_FIELD(FP_HDRV, FP_HDRV_OFF, outputVal, fp_wid); 393 DBE_SETREG(fp_hdrv, outputVal); 394 outputVal = 0; 395 SET_DBE_FIELD(FP_VDRV, FP_VDRV_ON, outputVal, 1); 396 SET_DBE_FIELD(FP_VDRV, FP_VDRV_OFF, outputVal, fp_hgt + 1); 397 DBE_SETREG(fp_vdrv, outputVal); 398} 399 400/* 401 * Set the hardware according to 'par'. 402 */ 403static int sgivwfb_set_par(struct fb_info *info) 404{ 405 struct sgivw_par *par = info->par; 406 int i, j, htmp, temp; 407 u32 readVal, outputVal; 408 int wholeTilesX, maxPixelsPerTileX; 409 int frmWrite1, frmWrite2, frmWrite3b; 410 struct dbe_timing_info *currentTiming; /* Current Video Timing */ 411 int xpmax, ypmax; // Monitor resolution 412 int bytesPerPixel; // Bytes per pixel 413 414 currentTiming = &dbeVTimings[par->timing_num]; 415 bytesPerPixel = bytes_per_pixel(info->var.bits_per_pixel); 416 xpmax = currentTiming->width; 417 ypmax = currentTiming->height; 418 419 /* dbe_InitGraphicsBase(); */ 420 /* Turn on dotclock PLL */ 421 DBE_SETREG(ctrlstat, 0x20000000); 422 423 dbe_TurnOffDma(par); 424 425 /* dbe_CalculateScreenParams(); */ 426 maxPixelsPerTileX = 512 / bytesPerPixel; 427 wholeTilesX = xpmax / maxPixelsPerTileX; 428 if (wholeTilesX * maxPixelsPerTileX < xpmax) 429 wholeTilesX++; 430 431 printk(KERN_DEBUG "sgivwfb: pixPerTile=%d wholeTilesX=%d\n", 432 maxPixelsPerTileX, wholeTilesX); 433 434 /* dbe_InitGammaMap(); */ 435 udelay(10); 436 437 for (i = 0; i < 256; i++) { 438 DBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8)); 439 } 440 441 /* dbe_TurnOn(); */ 442 DBE_GETREG(vt_xy, readVal); 443 if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) { 444 DBE_SETREG(vt_xy, 0x00000000); 445 udelay(1); 446 } else 447 dbe_TurnOffDma(par); 448 449 /* dbe_Initdbe(); */ 450 for (i = 0; i < 256; i++) { 451 for (j = 0; j < 100; j++) { 452 DBE_GETREG(cm_fifo, readVal); 453 if (readVal != 0x00000000) 454 break; 455 else 456 udelay(10); 457 } 458 459 // DBE_ISETREG(cmap, i, 0x00000000); 460 DBE_ISETREG(cmap, i, (i << 8) | (i << 16) | (i << 24)); 461 } 462 463 /* dbe_InitFramebuffer(); */ 464 frmWrite1 = 0; 465 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1, 466 wholeTilesX); 467 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, 0); 468 469 switch (bytesPerPixel) { 470 case 1: 471 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, 472 DBE_FRM_DEPTH_8); 473 break; 474 case 2: 475 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, 476 DBE_FRM_DEPTH_16); 477 break; 478 case 4: 479 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, 480 DBE_FRM_DEPTH_32); 481 break; 482 } 483 484 frmWrite2 = 0; 485 SET_DBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax); 486 487 // Tell dbe about the framebuffer location and type 488 frmWrite3b = 0; 489 SET_DBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b, 490 sgivwfb_mem_phys >> 9); 491 SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1); 492 SET_DBE_FIELD(FRM_CONTROL, FRM_LINEAR, frmWrite3b, 1); 493 494 /* Initialize DIDs */ 495 496 outputVal = 0; 497 switch (bytesPerPixel) { 498 case 1: 499 SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_I8); 500 break; 501 case 2: 502 SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGBA5); 503 break; 504 case 4: 505 SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGB8); 506 break; 507 } 508 SET_DBE_FIELD(WID, BUF, outputVal, DBE_BMODE_BOTH); 509 510 for (i = 0; i < 32; i++) { 511 DBE_ISETREG(mode_regs, i, outputVal); 512 } 513 514 /* dbe_InitTiming(); */ 515 DBE_SETREG(vt_intr01, 0xffffffff); 516 DBE_SETREG(vt_intr23, 0xffffffff); 517 518 DBE_GETREG(dotclock, readVal); 519 DBE_SETREG(dotclock, readVal & 0xffff); 520 521 DBE_SETREG(vt_xymax, 0x00000000); 522 outputVal = 0; 523 SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal, 524 currentTiming->vsync_start); 525 SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal, 526 currentTiming->vsync_end); 527 DBE_SETREG(vt_vsync, outputVal); 528 outputVal = 0; 529 SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal, 530 currentTiming->hsync_start); 531 SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal, 532 currentTiming->hsync_end); 533 DBE_SETREG(vt_hsync, outputVal); 534 outputVal = 0; 535 SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal, 536 currentTiming->vblank_start); 537 SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal, 538 currentTiming->vblank_end); 539 DBE_SETREG(vt_vblank, outputVal); 540 outputVal = 0; 541 SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal, 542 currentTiming->hblank_start); 543 SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal, 544 currentTiming->hblank_end - 3); 545 DBE_SETREG(vt_hblank, outputVal); 546 outputVal = 0; 547 SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal, 548 currentTiming->vblank_start); 549 SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal, 550 currentTiming->vblank_end); 551 DBE_SETREG(vt_vcmap, outputVal); 552 outputVal = 0; 553 SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal, 554 currentTiming->hblank_start); 555 SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal, 556 currentTiming->hblank_end - 3); 557 DBE_SETREG(vt_hcmap, outputVal); 558 559 if (flatpanel_id != -1) 560 sgivwfb_setup_flatpanel(par, currentTiming); 561 562 outputVal = 0; 563 temp = currentTiming->vblank_start - currentTiming->vblank_end - 1; 564 if (temp > 0) 565 temp = -temp; 566 567 SET_DBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32) temp); 568 if (currentTiming->hblank_end >= 20) 569 SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal, 570 currentTiming->hblank_end - 20); 571 else 572 SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal, 573 currentTiming->htotal - (20 - 574 currentTiming-> 575 hblank_end)); 576 DBE_SETREG(did_start_xy, outputVal); 577 578 outputVal = 0; 579 SET_DBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal, 580 (u32) (temp + 1)); 581 if (currentTiming->hblank_end >= DBE_CRS_MAGIC) 582 SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, 583 currentTiming->hblank_end - DBE_CRS_MAGIC); 584 else 585 SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, 586 currentTiming->htotal - (DBE_CRS_MAGIC - 587 currentTiming-> 588 hblank_end)); 589 DBE_SETREG(crs_start_xy, outputVal); 590 591 outputVal = 0; 592 SET_DBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32) temp); 593 SET_DBE_FIELD(VC_START_XY, VC_STARTX, outputVal, 594 currentTiming->hblank_end - 4); 595 DBE_SETREG(vc_start_xy, outputVal); 596 597 DBE_SETREG(frm_size_tile, frmWrite1); 598 DBE_SETREG(frm_size_pixel, frmWrite2); 599 600 outputVal = 0; 601 SET_DBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m - 1); 602 SET_DBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n - 1); 603 SET_DBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p); 604 SET_DBE_FIELD(DOTCLK, RUN, outputVal, 1); 605 DBE_SETREG(dotclock, outputVal); 606 607 udelay(11 * 1000); 608 609 DBE_SETREG(vt_vpixen, 0xffffff); 610 DBE_SETREG(vt_hpixen, 0xffffff); 611 612 outputVal = 0; 613 SET_DBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal); 614 SET_DBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal); 615 DBE_SETREG(vt_xymax, outputVal); 616 617 outputVal = frmWrite1; 618 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1); 619 DBE_SETREG(frm_size_tile, outputVal); 620 DBE_SETREG(frm_size_tile, frmWrite1); 621 622 outputVal = 0; 623 SET_DBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1); 624 DBE_SETREG(ovr_width_tile, outputVal); 625 DBE_SETREG(ovr_width_tile, 0); 626 627 DBE_SETREG(frm_control, frmWrite3b); 628 DBE_SETREG(did_control, 0); 629 630 // Wait for dbe to take frame settings 631 for (i = 0; i < 100000; i++) { 632 DBE_GETREG(frm_inhwctrl, readVal); 633 if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) != 634 0) 635 break; 636 else 637 udelay(1); 638 } 639 640 if (i == 100000) 641 printk(KERN_INFO 642 "sgivwfb: timeout waiting for frame DMA enable.\n"); 643 644 outputVal = 0; 645 htmp = currentTiming->hblank_end - 19; 646 if (htmp < 0) 647 htmp += currentTiming->htotal; /* allow blank to wrap around */ 648 SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp); 649 SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal, 650 ((htmp + currentTiming->width - 651 2) % currentTiming->htotal)); 652 DBE_SETREG(vt_hpixen, outputVal); 653 654 outputVal = 0; 655 SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal, 656 currentTiming->vblank_start); 657 SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal, 658 currentTiming->vblank_end); 659 DBE_SETREG(vt_vpixen, outputVal); 660 661 // Turn off mouse cursor 662 par->regs->crs_ctl = 0; 663 664 DBE_GETREG(ctrlstat, readVal); 665 readVal &= 0x02000000; 666 667 if (readVal != 0) { 668 DBE_SETREG(ctrlstat, 0x30000000); 669 } 670 return 0; 671} 672 673/* 674 * Set a single color register. The values supplied are already 675 * rounded down to the hardware's capabilities (according to the 676 * entries in the var structure). Return != 0 for invalid regno. 677 */ 678 679static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, 680 u_int blue, u_int transp, 681 struct fb_info *info) 682{ 683 struct sgivw_par *par = (struct sgivw_par *) info->par; 684 685 if (regno > 255) 686 return 1; 687 red >>= 8; 688 green >>= 8; 689 blue >>= 8; 690 691 /* wait for the color map FIFO to have a free entry */ 692 while (par->cmap_fifo == 0) 693 par->cmap_fifo = par->regs->cm_fifo; 694 695 par->regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); 696 par->cmap_fifo--; /* assume FIFO is filling up */ 697 return 0; 698} 699 700static int sgivwfb_mmap(struct fb_info *info, 701 struct vm_area_struct *vma) 702{ 703 unsigned long size = vma->vm_end - vma->vm_start; 704 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 705 706 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) 707 return -EINVAL; 708 if (offset + size > sgivwfb_mem_size) 709 return -EINVAL; 710 offset += sgivwfb_mem_phys; 711 pgprot_val(vma->vm_page_prot) = 712 pgprot_val(vma->vm_page_prot) | _PAGE_PCD; 713 vma->vm_flags |= VM_IO; 714 if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT, 715 size, vma->vm_page_prot)) 716 return -EAGAIN; 717 printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n", 718 offset, vma->vm_start); 719 return 0; 720} 721 722int __init sgivwfb_setup(char *options) 723{ 724 char *this_opt; 725 726 if (!options || !*options) 727 return 0; 728 729 while ((this_opt = strsep(&options, ",")) != NULL) { 730 if (!strncmp(this_opt, "monitor:", 8)) { 731 if (!strncmp(this_opt + 8, "crt", 3)) 732 flatpanel_id = -1; 733 else if (!strncmp(this_opt + 8, "1600sw", 6)) 734 flatpanel_id = FLATPANEL_SGI_1600SW; 735 } 736 } 737 return 0; 738} 739 740/* 741 * Initialisation 742 */ 743static int __devinit sgivwfb_probe(struct platform_device *dev) 744{ 745 struct sgivw_par *par; 746 struct fb_info *info; 747 char *monitor; 748 749 info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 16, &dev->dev); 750 if (!info) 751 return -ENOMEM; 752 par = info->par; 753 754 if (!request_mem_region(DBE_REG_PHYS, DBE_REG_SIZE, "sgivwfb")) { 755 printk(KERN_ERR "sgivwfb: couldn't reserve mmio region\n"); 756 framebuffer_release(info); 757 return -EBUSY; 758 } 759 760 par->regs = (struct asregs *) ioremap_nocache(DBE_REG_PHYS, DBE_REG_SIZE); 761 if (!par->regs) { 762 printk(KERN_ERR "sgivwfb: couldn't ioremap registers\n"); 763 goto fail_ioremap_regs; 764 } 765 766 mtrr_add(sgivwfb_mem_phys, sgivwfb_mem_size, MTRR_TYPE_WRCOMB, 1); 767 768 sgivwfb_fix.smem_start = sgivwfb_mem_phys; 769 sgivwfb_fix.smem_len = sgivwfb_mem_size; 770 sgivwfb_fix.ywrapstep = ywrap; 771 sgivwfb_fix.ypanstep = ypan; 772 773 info->fix = sgivwfb_fix; 774 775 switch (flatpanel_id) { 776 case FLATPANEL_SGI_1600SW: 777 info->var = sgivwfb_var1600sw; 778 monitor = "SGI 1600SW flatpanel"; 779 break; 780 default: 781 info->var = sgivwfb_var; 782 monitor = "CRT"; 783 } 784 785 printk(KERN_INFO "sgivwfb: %s monitor selected\n", monitor); 786 787 info->fbops = &sgivwfb_ops; 788 info->pseudo_palette = (void *) (par + 1); 789 info->flags = FBINFO_DEFAULT; 790 791 info->screen_base = ioremap_nocache((unsigned long) sgivwfb_mem_phys, sgivwfb_mem_size); 792 if (!info->screen_base) { 793 printk(KERN_ERR "sgivwfb: couldn't ioremap screen_base\n"); 794 goto fail_ioremap_fbmem; 795 } 796 797 if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) 798 goto fail_color_map; 799 800 if (register_framebuffer(info) < 0) { 801 printk(KERN_ERR "sgivwfb: couldn't register framebuffer\n"); 802 goto fail_register_framebuffer; 803 } 804 805 platform_set_drvdata(dev, info); 806 807 printk(KERN_INFO "fb%d: SGI DBE frame buffer device, using %ldK of video memory at %#lx\n", 808 info->node, sgivwfb_mem_size >> 10, sgivwfb_mem_phys); 809 return 0; 810 811fail_register_framebuffer: 812 fb_dealloc_cmap(&info->cmap); 813fail_color_map: 814 iounmap((char *) info->screen_base); 815fail_ioremap_fbmem: 816 iounmap(par->regs); 817fail_ioremap_regs: 818 release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE); 819 framebuffer_release(info); 820 return -ENXIO; 821} 822 823static int __devexit sgivwfb_remove(struct platform_device *dev) 824{ 825 struct fb_info *info = platform_get_drvdata(dev); 826 827 if (info) { 828 struct sgivw_par *par = info->par; 829 830 unregister_framebuffer(info); 831 dbe_TurnOffDma(par); 832 iounmap(par->regs); 833 iounmap(info->screen_base); 834 release_mem_region(DBE_REG_PHYS, DBE_REG_SIZE); 835 fb_dealloc_cmap(&info->cmap); 836 framebuffer_release(info); 837 } 838 return 0; 839} 840 841static struct platform_driver sgivwfb_driver = { 842 .probe = sgivwfb_probe, 843 .remove = __devexit_p(sgivwfb_remove), 844 .driver = { 845 .name = "sgivwfb", 846 }, 847}; 848 849static struct platform_device *sgivwfb_device; 850 851int __init sgivwfb_init(void) 852{ 853 int ret; 854 855#ifndef MODULE 856 char *option = NULL; 857 858 if (fb_get_options("sgivwfb", &option)) 859 return -ENODEV; 860 sgivwfb_setup(option); 861#endif 862 ret = platform_driver_register(&sgivwfb_driver); 863 if (!ret) { 864 sgivwfb_device = platform_device_alloc("sgivwfb", 0); 865 if (sgivwfb_device) { 866 ret = platform_device_add(sgivwfb_device); 867 } else 868 ret = -ENOMEM; 869 if (ret) { 870 platform_driver_unregister(&sgivwfb_driver); 871 platform_device_put(sgivwfb_device); 872 } 873 } 874 return ret; 875} 876 877module_init(sgivwfb_init); 878 879#ifdef MODULE 880MODULE_LICENSE("GPL"); 881 882static void __exit sgivwfb_exit(void) 883{ 884 platform_device_unregister(sgivwfb_device); 885 platform_driver_unregister(&sgivwfb_driver); 886} 887 888module_exit(sgivwfb_exit); 889 890#endif /* MODULE */ 891