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/config.h> 13#include <linux/module.h> 14#include <linux/kernel.h> 15#include <linux/errno.h> 16#include <linux/string.h> 17#include <linux/mm.h> 18#include <linux/tty.h> 19#include <linux/slab.h> 20#include <linux/vmalloc.h> 21#include <linux/delay.h> 22#include <linux/interrupt.h> 23#include <asm/uaccess.h> 24#include <linux/fb.h> 25#include <linux/init.h> 26#include <asm/io.h> 27#include <asm/mtrr.h> 28 29#include <video/fbcon.h> 30#include <video/fbcon-cfb8.h> 31#include <video/fbcon-cfb16.h> 32#include <video/fbcon-cfb32.h> 33 34#define INCLUDE_TIMING_TABLE_DATA 35#define DBE_REG_BASE regs 36#include "sgivwfb.h" 37 38struct sgivwfb_par { 39 struct fb_var_screeninfo var; 40 u_long timing_num; 41 int valid; 42}; 43 44/* 45 * RAM we reserve for the frame buffer. This defines the maximum screen 46 * size 47 * 48 * The default can be overridden if the driver is compiled as a module 49 */ 50 51/* set by arch/i386/kernel/setup.c */ 52u_long sgivwfb_mem_phys; 53u_long sgivwfb_mem_size; 54 55static volatile char *fbmem; 56static asregs *regs; 57static struct fb_info fb_info; 58static struct { u_char red, green, blue, pad; } palette[256]; 59static char sgivwfb_name[16] = "SGI Vis WS FB"; 60static u32 cmap_fifo; 61static int ypan = 0; 62static int ywrap = 0; 63 64/* console related variables */ 65static int currcon = 0; 66static struct display disp; 67 68static union { 69#ifdef FBCON_HAS_CFB16 70 u16 cfb16[16]; 71#endif 72#ifdef FBCON_HAS_CFB32 73 u32 cfb32[16]; 74#endif 75} fbcon_cmap; 76 77static struct sgivwfb_par par_current = { 78 { /* var (screeninfo) */ 79 /* 640x480, 8 bpp */ 80 640, 480, 640, 480, 0, 0, 8, 0, 81 {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 82 0, 0, -1, -1, 0, 20000, 64, 64, 32, 32, 64, 2, 83 0, FB_VMODE_NONINTERLACED 84 }, 85 0, /* timing_num */ 86 0 /* par not activated */ 87}; 88 89/* 90 * Interface used by the world 91 */ 92int sgivwfb_setup(char*); 93 94static int sgivwfb_get_fix(struct fb_fix_screeninfo *fix, int con, 95 struct fb_info *info); 96static int sgivwfb_get_var(struct fb_var_screeninfo *var, int con, 97 struct fb_info *info); 98static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con, 99 struct fb_info *info); 100static int sgivwfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, 101 struct fb_info *info); 102static int sgivwfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, 103 struct fb_info *info); 104static int sgivwfb_mmap(struct fb_info *info, struct file *file, 105 struct vm_area_struct *vma); 106 107static struct fb_ops sgivwfb_ops = { 108 owner: THIS_MODULE, 109 fb_get_fix: sgivwfb_get_fix, 110 fb_get_var: sgivwfb_get_var, 111 fb_set_var: sgivwfb_set_var, 112 fb_get_cmap: sgivwfb_get_cmap, 113 fb_set_cmap: sgivwfb_set_cmap, 114 fb_mmap: sgivwfb_mmap, 115}; 116 117/* 118 * Interface to the low level console driver 119 */ 120int sgivwfb_init(void); 121static int sgivwfbcon_switch(int con, struct fb_info *info); 122static int sgivwfbcon_updatevar(int con, struct fb_info *info); 123static void sgivwfbcon_blank(int blank, struct fb_info *info); 124 125/* 126 * Internal routines 127 */ 128static u_long get_line_length(int xres_virtual, int bpp); 129static unsigned long bytes_per_pixel(int bpp); 130static void activate_par(struct sgivwfb_par *par); 131static void sgivwfb_encode_fix(struct fb_fix_screeninfo *fix, 132 struct fb_var_screeninfo *var); 133static int sgivwfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, 134 u_int *transp, struct fb_info *info); 135static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 136 u_int transp, struct fb_info *info); 137static void do_install_cmap(int con, struct fb_info *info); 138 139static unsigned long get_line_length(int xres_virtual, int bpp) 140{ 141 return(xres_virtual * bytes_per_pixel(bpp)); 142} 143 144static unsigned long bytes_per_pixel(int bpp) 145{ 146 unsigned long length; 147 148 switch (bpp) { 149 case 8: 150 length = 1; 151 break; 152 case 16: 153 length = 2; 154 break; 155 case 32: 156 length = 4; 157 break; 158 default: 159 printk(KERN_INFO "sgivwfb: unsupported bpp=%d\n", bpp); 160 length = 0; 161 break; 162 } 163 return(length); 164} 165 166/* 167 * Function: dbe_TurnOffDma 168 * Parameters: (None) 169 * Description: This should turn off the monitor and dbe. This is used 170 * when switching between the serial console and the graphics 171 * console. 172 */ 173 174static void dbe_TurnOffDma(void) 175{ 176 int i; 177 unsigned int readVal; 178 179 // Check to see if things are already turned off: 180 // 1) Check to see if dbe is not using the internal dotclock. 181 // 2) Check to see if the xy counter in dbe is already off. 182 183 DBE_GETREG(ctrlstat, readVal); 184 if (GET_DBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2) 185 return; 186 187 DBE_GETREG(vt_xy, readVal); 188 if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) 189 return; 190 191 // Otherwise, turn off dbe 192 193 DBE_GETREG(ovr_control, readVal); 194 SET_DBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0); 195 DBE_SETREG(ovr_control, readVal); 196 udelay(1000); 197 DBE_GETREG(frm_control, readVal); 198 SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0); 199 DBE_SETREG(frm_control, readVal); 200 udelay(1000); 201 DBE_GETREG(did_control, readVal); 202 SET_DBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0); 203 DBE_SETREG(did_control, readVal); 204 udelay(1000); 205 206 // XXX HACK: 207 // 208 // This was necessary for GBE--we had to wait through two 209 // vertical retrace periods before the pixel DMA was 210 // turned off for sure. I've left this in for now, in 211 // case dbe needs it. 212 213 for (i = 0; i < 10000; i++) 214 { 215 DBE_GETREG(frm_inhwctrl, readVal); 216 if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) == 0) 217 udelay(10); 218 else 219 { 220 DBE_GETREG(ovr_inhwctrl, readVal); 221 if (GET_DBE_FIELD(OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0) 222 udelay(10); 223 else 224 { 225 DBE_GETREG(did_inhwctrl, readVal); 226 if (GET_DBE_FIELD(DID_INHWCTRL, DID_DMA_ENABLE, readVal) == 0) 227 udelay(10); 228 else 229 break; 230 } 231 } 232 } 233} 234 235/* 236 * Set the hardware according to 'par'. 237 */ 238static void activate_par(struct sgivwfb_par *par) 239{ 240 int i,j, htmp, temp; 241 u32 readVal, outputVal; 242 int wholeTilesX, maxPixelsPerTileX; 243 int frmWrite1, frmWrite2, frmWrite3b; 244 dbe_timing_info_t *currentTiming; /* Current Video Timing */ 245 int xpmax, ypmax; // Monitor resolution 246 int bytesPerPixel; // Bytes per pixel 247 248 currentTiming = &dbeVTimings[par->timing_num]; 249 bytesPerPixel = bytes_per_pixel(par->var.bits_per_pixel); 250 xpmax = currentTiming->width; 251 ypmax = currentTiming->height; 252 253 /* dbe_InitGraphicsBase(); */ 254 /* Turn on dotclock PLL */ 255 DBE_SETREG(ctrlstat, 0x20000000); 256 257 dbe_TurnOffDma(); 258 259 /* dbe_CalculateScreenParams(); */ 260 maxPixelsPerTileX = 512/bytesPerPixel; 261 wholeTilesX = xpmax/maxPixelsPerTileX; 262 if (wholeTilesX*maxPixelsPerTileX < xpmax) 263 wholeTilesX++; 264 265 printk(KERN_DEBUG "sgivwfb: pixPerTile=%d wholeTilesX=%d\n", 266 maxPixelsPerTileX, wholeTilesX); 267 268 /* dbe_InitGammaMap(); */ 269 udelay(10); 270 271 for (i = 0; i < 256; i++) 272 { 273 DBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8)); 274 } 275 276 /* dbe_TurnOn(); */ 277 DBE_GETREG(vt_xy, readVal); 278 if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) 279 { 280 DBE_SETREG(vt_xy, 0x00000000); 281 udelay(1); 282 } 283 else 284 dbe_TurnOffDma(); 285 286 /* dbe_Initdbe(); */ 287 for (i = 0; i < 256; i++) 288 { 289 for (j = 0; j < 100; j++) 290 { 291 DBE_GETREG(cm_fifo, readVal); 292 if (readVal != 0x00000000) 293 break; 294 else 295 udelay(10); 296 } 297 298 // DBE_ISETREG(cmap, i, 0x00000000); 299 DBE_ISETREG(cmap, i, (i<<8)|(i<<16)|(i<<24)); 300 } 301 302 /* dbe_InitFramebuffer(); */ 303 frmWrite1 = 0; 304 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_WIDTH_TILE, frmWrite1, wholeTilesX); 305 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_RHS, frmWrite1, 0); 306 307 switch(bytesPerPixel) 308 { 309 case 1: 310 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, DBE_FRM_DEPTH_8); 311 break; 312 case 2: 313 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, DBE_FRM_DEPTH_16); 314 break; 315 case 4: 316 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_DEPTH, frmWrite1, DBE_FRM_DEPTH_32); 317 break; 318 } 319 320 frmWrite2 = 0; 321 SET_DBE_FIELD(FRM_SIZE_PIXEL, FB_HEIGHT_PIX, frmWrite2, ypmax); 322 323 // Tell dbe about the framebuffer location and type 324 // XXX What format is the FRM_TILE_PTR?? 64K aligned address? 325 frmWrite3b = 0; 326 SET_DBE_FIELD(FRM_CONTROL, FRM_TILE_PTR, frmWrite3b, sgivwfb_mem_phys>>9); 327 SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, frmWrite3b, 1); 328 SET_DBE_FIELD(FRM_CONTROL, FRM_LINEAR, frmWrite3b, 1); 329 330 /* Initialize DIDs */ 331 332 outputVal = 0; 333 switch(bytesPerPixel) 334 { 335 case 1: 336 SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_I8); 337 break; 338 case 2: 339 SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGBA5); 340 break; 341 case 4: 342 SET_DBE_FIELD(WID, TYP, outputVal, DBE_CMODE_RGB8); 343 break; 344 } 345 SET_DBE_FIELD(WID, BUF, outputVal, DBE_BMODE_BOTH); 346 347 for (i = 0; i < 32; i++) 348 { 349 DBE_ISETREG(mode_regs, i, outputVal); 350 } 351 352 /* dbe_InitTiming(); */ 353 DBE_SETREG(vt_intr01, 0xffffffff); 354 DBE_SETREG(vt_intr23, 0xffffffff); 355 356 DBE_GETREG(dotclock, readVal); 357 DBE_SETREG(dotclock, readVal & 0xffff); 358 359 DBE_SETREG(vt_xymax, 0x00000000); 360 outputVal = 0; 361 SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_ON, outputVal, currentTiming->vsync_start); 362 SET_DBE_FIELD(VT_VSYNC, VT_VSYNC_OFF, outputVal, currentTiming->vsync_end); 363 DBE_SETREG(vt_vsync, outputVal); 364 outputVal = 0; 365 SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_ON, outputVal, currentTiming->hsync_start); 366 SET_DBE_FIELD(VT_HSYNC, VT_HSYNC_OFF, outputVal, currentTiming->hsync_end); 367 DBE_SETREG(vt_hsync, outputVal); 368 outputVal = 0; 369 SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_ON, outputVal, currentTiming->vblank_start); 370 SET_DBE_FIELD(VT_VBLANK, VT_VBLANK_OFF, outputVal, currentTiming->vblank_end); 371 DBE_SETREG(vt_vblank, outputVal); 372 outputVal = 0; 373 SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_ON, outputVal, currentTiming->hblank_start); 374 SET_DBE_FIELD(VT_HBLANK, VT_HBLANK_OFF, outputVal, currentTiming->hblank_end-3); 375 DBE_SETREG(vt_hblank, outputVal); 376 outputVal = 0; 377 SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_ON, outputVal, currentTiming->vblank_start); 378 SET_DBE_FIELD(VT_VCMAP, VT_VCMAP_OFF, outputVal, currentTiming->vblank_end); 379 DBE_SETREG(vt_vcmap, outputVal); 380 outputVal = 0; 381 SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_ON, outputVal, currentTiming->hblank_start); 382 SET_DBE_FIELD(VT_HCMAP, VT_HCMAP_OFF, outputVal, currentTiming->hblank_end-3); 383 DBE_SETREG(vt_hcmap, outputVal); 384 385 outputVal = 0; 386 temp = currentTiming->vblank_start - currentTiming->vblank_end - 1; 387 if (temp > 0) 388 temp = -temp; 389 390 SET_DBE_FIELD(DID_START_XY, DID_STARTY, outputVal, (u32)temp); 391 if (currentTiming->hblank_end >= 20) 392 SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal, 393 currentTiming->hblank_end - 20); 394 else 395 SET_DBE_FIELD(DID_START_XY, DID_STARTX, outputVal, 396 currentTiming->htotal - (20 - currentTiming->hblank_end)); 397 DBE_SETREG(did_start_xy, outputVal); 398 399 outputVal = 0; 400 SET_DBE_FIELD(CRS_START_XY, CRS_STARTY, outputVal, (u32)(temp+1)); 401 if (currentTiming->hblank_end >= DBE_CRS_MAGIC) 402 SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, 403 currentTiming->hblank_end - DBE_CRS_MAGIC); 404 else 405 SET_DBE_FIELD(CRS_START_XY, CRS_STARTX, outputVal, 406 currentTiming->htotal - (DBE_CRS_MAGIC - currentTiming->hblank_end)); 407 DBE_SETREG(crs_start_xy, outputVal); 408 409 outputVal = 0; 410 SET_DBE_FIELD(VC_START_XY, VC_STARTY, outputVal, (u32)temp); 411 SET_DBE_FIELD(VC_START_XY, VC_STARTX, outputVal, 412 currentTiming->hblank_end - 4); 413 DBE_SETREG(vc_start_xy, outputVal); 414 415 DBE_SETREG(frm_size_tile, frmWrite1); 416 DBE_SETREG(frm_size_pixel, frmWrite2); 417 418 outputVal = 0; 419 SET_DBE_FIELD(DOTCLK, M, outputVal, currentTiming->pll_m-1); 420 SET_DBE_FIELD(DOTCLK, N, outputVal, currentTiming->pll_n-1); 421 SET_DBE_FIELD(DOTCLK, P, outputVal, currentTiming->pll_p); 422 SET_DBE_FIELD(DOTCLK, RUN, outputVal, 1); 423 DBE_SETREG(dotclock, outputVal); 424 425 udelay(11*1000); 426 427 DBE_SETREG(vt_vpixen, 0xffffff); 428 DBE_SETREG(vt_hpixen, 0xffffff); 429 430 outputVal = 0; 431 SET_DBE_FIELD(VT_XYMAX, VT_MAXX, outputVal, currentTiming->htotal); 432 SET_DBE_FIELD(VT_XYMAX, VT_MAXY, outputVal, currentTiming->vtotal); 433 DBE_SETREG(vt_xymax, outputVal); 434 435 outputVal = frmWrite1; 436 SET_DBE_FIELD(FRM_SIZE_TILE, FRM_FIFO_RESET, outputVal, 1); 437 DBE_SETREG(frm_size_tile, outputVal); 438 DBE_SETREG(frm_size_tile, frmWrite1); 439 440 outputVal = 0; 441 SET_DBE_FIELD(OVR_WIDTH_TILE, OVR_FIFO_RESET, outputVal, 1); 442 DBE_SETREG(ovr_width_tile, outputVal); 443 DBE_SETREG(ovr_width_tile, 0); 444 445 DBE_SETREG(frm_control, frmWrite3b); 446 DBE_SETREG(did_control, 0); 447 448 // Wait for dbe to take frame settings 449 for (i=0; i<100000; i++) 450 { 451 DBE_GETREG(frm_inhwctrl, readVal); 452 if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) != 0) 453 break; 454 else 455 udelay(1); 456 } 457 458 if (i==100000) 459 printk(KERN_INFO "sgivwfb: timeout waiting for frame DMA enable.\n"); 460 461 outputVal = 0; 462 htmp = currentTiming->hblank_end - 19; 463 if (htmp < 0) 464 htmp += currentTiming->htotal; /* allow blank to wrap around */ 465 SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_ON, outputVal, htmp); 466 SET_DBE_FIELD(VT_HPIXEN, VT_HPIXEN_OFF, outputVal, 467 ((htmp + currentTiming->width - 2) % currentTiming->htotal)); 468 DBE_SETREG(vt_hpixen, outputVal); 469 470 outputVal = 0; 471 SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_OFF, outputVal, 472 currentTiming->vblank_start); 473 SET_DBE_FIELD(VT_VPIXEN, VT_VPIXEN_ON, outputVal, 474 currentTiming->vblank_end); 475 DBE_SETREG(vt_vpixen, outputVal); 476 477 // Turn off mouse cursor 478 regs->crs_ctl = 0; 479 480 // XXX What's this section for?? 481 DBE_GETREG(ctrlstat, readVal); 482 readVal &= 0x02000000; 483 484 if (readVal != 0) 485 { 486 DBE_SETREG(ctrlstat, 0x30000000); 487 } 488} 489 490static void sgivwfb_encode_fix(struct fb_fix_screeninfo *fix, 491 struct fb_var_screeninfo *var) 492{ 493 memset(fix, 0, sizeof(struct fb_fix_screeninfo)); 494 strcpy(fix->id, sgivwfb_name); 495 fix->smem_start = sgivwfb_mem_phys; 496 fix->smem_len = sgivwfb_mem_size; 497 fix->type = FB_TYPE_PACKED_PIXELS; 498 fix->type_aux = 0; 499 switch (var->bits_per_pixel) { 500 case 8: 501 fix->visual = FB_VISUAL_PSEUDOCOLOR; 502 break; 503 default: 504 fix->visual = FB_VISUAL_TRUECOLOR; 505 break; 506 } 507 fix->ywrapstep = ywrap; 508 fix->xpanstep = 0; 509 fix->ypanstep = ypan; 510 fix->line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); 511 fix->mmio_start = DBE_REG_PHYS; 512 fix->mmio_len = DBE_REG_SIZE; 513} 514 515/* 516 * Read a single color register and split it into 517 * colors/transparent. Return != 0 for invalid regno. 518 */ 519static int sgivwfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, 520 u_int *transp, struct fb_info *info) 521{ 522 if (regno > 255) 523 return 1; 524 525 *red = palette[regno].red << 8; 526 *green = palette[regno].green << 8; 527 *blue = palette[regno].blue << 8; 528 *transp = 0; 529 return 0; 530} 531 532/* 533 * Set a single color register. The values supplied are already 534 * rounded down to the hardware's capabilities (according to the 535 * entries in the var structure). Return != 0 for invalid regno. 536 */ 537 538static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 539 u_int transp, struct fb_info *info) 540{ 541 if (regno > 255) 542 return 1; 543 red >>= 8; 544 green >>= 8; 545 blue >>= 8; 546 palette[regno].red = red; 547 palette[regno].green = green; 548 palette[regno].blue = blue; 549 550 /* wait for the color map FIFO to have a free entry */ 551 while (cmap_fifo == 0) 552 cmap_fifo = regs->cm_fifo; 553 554 regs->cmap[regno] = (red << 24) | (green << 16) | (blue << 8); 555 cmap_fifo--; /* assume FIFO is filling up */ 556 return 0; 557} 558 559static void do_install_cmap(int con, struct fb_info *info) 560{ 561 if (con != currcon) 562 return; 563 if (fb_display[con].cmap.len) 564 fb_set_cmap(&fb_display[con].cmap, 1, sgivwfb_setcolreg, info); 565 else 566 fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1, 567 sgivwfb_setcolreg, info); 568} 569 570/* ---------------------------------------------------- */ 571 572/* 573 * Get the Fixed Part of the Display 574 */ 575static int sgivwfb_get_fix(struct fb_fix_screeninfo *fix, int con, 576 struct fb_info *info) 577{ 578 struct fb_var_screeninfo *var; 579 580 if (con == -1) 581 var = &par_current.var; 582 else 583 var = &fb_display[con].var; 584 sgivwfb_encode_fix(fix, var); 585 return 0; 586} 587 588/* 589 * Get the User Defined Part of the Display. If a real par get it form there 590 */ 591static int sgivwfb_get_var(struct fb_var_screeninfo *var, int con, 592 struct fb_info *info) 593{ 594 if (con == -1) 595 *var = par_current.var; 596 else 597 *var = fb_display[con].var; 598 return 0; 599} 600 601/* 602 * Set the User Defined Part of the Display. Again if par use it to get 603 * real video mode. 604 */ 605static int sgivwfb_set_var(struct fb_var_screeninfo *var, int con, 606 struct fb_info *info) 607{ 608 int err, activate = var->activate; 609 int oldxres, oldyres, oldvxres, oldvyres, oldbpp; 610 u_long line_length; 611 u_long min_mode; 612 int req_dot; 613 int test_mode; 614 615 struct dbe_timing_info *timing; 616 617 struct display *display; 618 619 if (con >= 0) 620 display = &fb_display[con]; 621 else 622 display = &disp; /* used during initialization */ 623 624 /* 625 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! 626 * as FB_VMODE_SMOOTH_XPAN is only used internally 627 */ 628 629 if (var->vmode & FB_VMODE_CONUPDATE) { 630 var->vmode |= FB_VMODE_YWRAP; 631 var->xoffset = display->var.xoffset; 632 var->yoffset = display->var.yoffset; 633 } 634 635 var->xoffset = 0; 636 var->yoffset = 0; 637 638 /* Limit bpp to 8, 16, and 32 */ 639 if (var->bits_per_pixel <= 8) 640 var->bits_per_pixel = 8; 641 else if (var->bits_per_pixel <= 16) 642 var->bits_per_pixel = 16; 643 else if (var->bits_per_pixel <= 32) 644 var->bits_per_pixel = 32; 645 else 646 return -EINVAL; 647 648 var->grayscale = 0; /* No grayscale for now */ 649 650 /* determine valid resolution and timing */ 651 for (min_mode=0; min_mode<DBE_VT_SIZE; min_mode++) { 652 if (dbeVTimings[min_mode].width >= var->xres && 653 dbeVTimings[min_mode].height >= var->yres) 654 break; 655 } 656 657 if (min_mode == DBE_VT_SIZE) 658 return -EINVAL; /* Resolution to high */ 659 660 /* for now, pick closest dot-clock within 3MHz*/ 661#error "Floating point not allowed in kernel" 662 req_dot = (int)((1.0e3/1.0e6) / (1.0e-12 * (float)var->pixclock)); 663 printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n", var->pixclock, 664 req_dot); 665 test_mode=min_mode; 666 while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) { 667 if (dbeVTimings[test_mode].cfreq+3000 > req_dot) 668 break; 669 test_mode++; 670 } 671 if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width) 672 test_mode--; 673 min_mode = test_mode; 674 timing = &dbeVTimings[min_mode]; 675 printk(KERN_INFO "sgivwfb: granted dot-clock=%d KHz\n", timing->cfreq); 676 677 /* Adjust virtual resolution, if necessary */ 678 if (var->xres > var->xres_virtual || (!ywrap && !ypan)) 679 var->xres_virtual = var->xres; 680 if (var->yres > var->yres_virtual || (!ywrap && !ypan)) 681 var->yres_virtual = var->yres; 682 683 /* 684 * Memory limit 685 */ 686 line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); 687 if (line_length*var->yres_virtual > sgivwfb_mem_size) 688 return -ENOMEM; /* Virtual resolution to high */ 689 690 switch (var->bits_per_pixel) 691 { 692 case 8: 693 var->red.offset = 0; 694 var->red.length = 8; 695 var->green.offset = 0; 696 var->green.length = 8; 697 var->blue.offset = 0; 698 var->blue.length = 8; 699 var->transp.offset = 0; 700 var->transp.length = 0; 701 break; 702 case 16: /* RGBA 5551 */ 703 var->red.offset = 11; 704 var->red.length = 5; 705 var->green.offset = 6; 706 var->green.length = 5; 707 var->blue.offset = 1; 708 var->blue.length = 5; 709 var->transp.offset = 0; 710 var->transp.length = 0; 711 break; 712 case 32: /* RGB 8888 */ 713 var->red.offset = 0; 714 var->red.length = 8; 715 var->green.offset = 8; 716 var->green.length = 8; 717 var->blue.offset = 16; 718 var->blue.length = 8; 719 var->transp.offset = 24; 720 var->transp.length = 8; 721 break; 722 } 723 var->red.msb_right = 0; 724 var->green.msb_right = 0; 725 var->blue.msb_right = 0; 726 var->transp.msb_right = 0; 727 728 /* set video timing information */ 729 var->pixclock = (__u32)(1.0e+9/(float)timing->cfreq); 730 var->left_margin = timing->htotal - timing->hsync_end; 731 var->right_margin = timing->hsync_start - timing->width; 732 var->upper_margin = timing->vtotal - timing->vsync_end; 733 var->lower_margin = timing->vsync_start - timing->height; 734 var->hsync_len = timing->hsync_end - timing->hsync_start; 735 var->vsync_len = timing->vsync_end - timing->vsync_start; 736 737 if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { 738 oldxres = display->var.xres; 739 oldyres = display->var.yres; 740 oldvxres = display->var.xres_virtual; 741 oldvyres = display->var.yres_virtual; 742 oldbpp = display->var.bits_per_pixel; 743 display->var = *var; 744 par_current.var = *var; 745 par_current.timing_num = min_mode; 746 if (oldxres != var->xres || oldyres != var->yres || 747 oldvxres != var->xres_virtual || oldvyres != var->yres_virtual || 748 oldbpp != var->bits_per_pixel || !par_current.valid) { 749 struct fb_fix_screeninfo fix; 750 printk(KERN_INFO "sgivwfb: new video mode xres=%d yres=%d bpp=%d\n", 751 var->xres, var->yres, var->bits_per_pixel); 752 printk(KERN_INFO " vxres=%d vyres=%d\n", 753 var->xres_virtual, var->yres_virtual); 754 activate_par(&par_current); 755 sgivwfb_encode_fix(&fix, var); 756 display->screen_base = (char *)fbmem; 757 display->visual = fix.visual; 758 display->type = fix.type; 759 display->type_aux = fix.type_aux; 760 display->ypanstep = fix.ypanstep; 761 display->ywrapstep = fix.ywrapstep; 762 display->line_length = fix.line_length; 763 display->can_soft_blank = 1; 764 display->inverse = 0; 765 if (oldbpp != var->bits_per_pixel || !par_current.valid) { 766 if ((err = fb_alloc_cmap(&display->cmap, 0, 0))) 767 return err; 768 do_install_cmap(con, info); 769 } 770 switch (var->bits_per_pixel) { 771#ifdef FBCON_HAS_CFB8 772 case 8: 773 display->dispsw = &fbcon_cfb8; 774 break; 775#endif 776#ifdef FBCON_HAS_CFB16 777 case 16: 778 display->dispsw = &fbcon_cfb16; 779 display->dispsw_data = fbcon_cmap.cfb16; 780 break; 781#endif 782#ifdef FBCON_HAS_CFB32 783 case 32: 784 display->dispsw = &fbcon_cfb32; 785 display->dispsw_data = fbcon_cmap.cfb32; 786 break; 787#endif 788 default: 789 display->dispsw = &fbcon_dummy; 790 break; 791 } 792 par_current.valid = 1; 793 if (fb_info.changevar) 794 (*fb_info.changevar)(con); 795 } 796 } 797 return 0; 798} 799 800/* 801 * Get the Colormap 802 */ 803static int sgivwfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, 804 struct fb_info *info) 805{ 806 if (con == currcon) /* current console? */ 807 return fb_get_cmap(cmap, kspc, sgivwfb_getcolreg, info); 808 else if (fb_display[con].cmap.len) /* non default colormap? */ 809 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); 810 else 811 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 812 cmap, kspc ? 0 : 2); 813 return 0; 814} 815 816/* 817 * Set the Colormap 818 */ 819static int sgivwfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, 820 struct fb_info *info) 821{ 822 int err; 823 824 if (!fb_display[con].cmap.len) { /* no colormap allocated? */ 825 int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256; 826 if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0))) 827 return err; 828 } 829 if (con == currcon) /* current console? */ 830 return fb_set_cmap(cmap, kspc, sgivwfb_setcolreg, info); 831 else 832 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); 833 return 0; 834} 835 836static int sgivwfb_mmap(struct fb_info *info, struct file *file, 837 struct vm_area_struct *vma) 838{ 839 unsigned long size = vma->vm_end - vma->vm_start; 840 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 841 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) 842 return -EINVAL; 843 if (offset+size > sgivwfb_mem_size) 844 return -EINVAL; 845 offset += sgivwfb_mem_phys; 846 pgprot_val(vma->vm_page_prot) = pgprot_val(vma->vm_page_prot) | _PAGE_PCD; 847 if (remap_page_range(vma->vm_start, offset, size, vma->vm_page_prot)) 848 return -EAGAIN; 849 vma->vm_file = file; 850 printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n", offset, vma->vm_start); 851 return 0; 852} 853 854int __init sgivwfb_setup(char *options) 855{ 856 char *this_opt; 857 858 fb_info.fontname[0] = '\0'; 859 860 if (!options || !*options) 861 return 0; 862 863 while ((this_opt = strsep(&options, ",")) != NULL) { 864 if (!strncmp(this_opt, "font:", 5)) 865 strcpy(fb_info.fontname, this_opt+5); 866 } 867 return 0; 868} 869 870/* 871 * Initialisation 872 */ 873int __init sgivwfb_init(void) 874{ 875 printk(KERN_INFO "sgivwfb: framebuffer at 0x%lx, size %ldk\n", 876 sgivwfb_mem_phys, sgivwfb_mem_size/1024); 877 878 regs = (asregs*)ioremap_nocache(DBE_REG_PHYS, DBE_REG_SIZE); 879 if (!regs) { 880 printk(KERN_ERR "sgivwfb: couldn't ioremap registers\n"); 881 goto fail_ioremap_regs; 882 } 883 884#ifdef CONFIG_MTRR 885 mtrr_add((unsigned long)sgivwfb_mem_phys, sgivwfb_mem_size, MTRR_TYPE_WRCOMB, 1); 886#endif 887 888 strcpy(fb_info.modename, sgivwfb_name); 889 fb_info.changevar = NULL; 890 fb_info.node = -1; 891 fb_info.fbops = &sgivwfb_ops; 892 fb_info.disp = &disp; 893 fb_info.switch_con = &sgivwfbcon_switch; 894 fb_info.updatevar = &sgivwfbcon_updatevar; 895 fb_info.blank = &sgivwfbcon_blank; 896 fb_info.flags = FBINFO_FLAG_DEFAULT; 897 898 fbmem = ioremap_nocache((unsigned long)sgivwfb_mem_phys, sgivwfb_mem_size); 899 if (!fbmem) { 900 printk(KERN_ERR "sgivwfb: couldn't ioremap fbmem\n"); 901 goto fail_ioremap_fbmem; 902 } 903 904 /* turn on default video mode */ 905 sgivwfb_set_var(&par_current.var, -1, &fb_info); 906 907 if (register_framebuffer(&fb_info) < 0) { 908 printk(KERN_ERR "sgivwfb: couldn't register framebuffer\n"); 909 goto fail_register_framebuffer; 910 } 911 912 printk(KERN_INFO "fb%d: Virtual frame buffer device, using %ldK of video memory\n", 913 GET_FB_IDX(fb_info.node), sgivwfb_mem_size>>10); 914 915 return 0; 916 917 fail_register_framebuffer: 918 iounmap((char*)fbmem); 919 fail_ioremap_fbmem: 920 iounmap(regs); 921 fail_ioremap_regs: 922 return -ENXIO; 923} 924 925static int sgivwfbcon_switch(int con, struct fb_info *info) 926{ 927 /* Do we have to save the colormap? */ 928 if (fb_display[currcon].cmap.len) 929 fb_get_cmap(&fb_display[currcon].cmap, 1, sgivwfb_getcolreg, info); 930 931 currcon = con; 932 /* Install new colormap */ 933 do_install_cmap(con, info); 934 return 0; 935} 936 937/* 938 * Update the `var' structure (called by fbcon.c) 939 */ 940static int sgivwfbcon_updatevar(int con, struct fb_info *info) 941{ 942 /* Nothing */ 943 return 0; 944} 945 946/* 947 * Blank the display. 948 */ 949static void sgivwfbcon_blank(int blank, struct fb_info *info) 950{ 951 /* Nothing */ 952} 953 954#ifdef MODULE 955MODULE_LICENSE("GPL"); 956 957int init_module(void) 958{ 959 return sgivwfb_init(); 960} 961 962void cleanup_module(void) 963{ 964 unregister_framebuffer(&fb_info); 965 dbe_TurnOffDma(); 966 iounmap(regs); 967 iounmap(fbmem); 968} 969 970#endif /* MODULE */ 971