cg6_driver.c revision 5eefee25
1/* 2 * GX and Turbo GX framebuffer driver. 3 * 4 * Copyright (C) 2000 Jakub Jelinek (jakub@redhat.com) 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * JAKUB JELINEK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/suncg6/cg6_driver.c,v 1.7 2002/12/06 16:44:38 tsi Exp $ */ 24 25#ifdef HAVE_CONFIG_H 26#include "config.h" 27#endif 28 29#include <string.h> 30 31#include "xf86.h" 32#include "xf86_OSproc.h" 33#include "xf86Version.h" 34#include "mipointer.h" 35#include "mibstore.h" 36#include "micmap.h" 37 38#include "fb.h" 39#include "xf86cmap.h" 40#include "cg6.h" 41 42static const OptionInfoRec * CG6AvailableOptions(int chipid, int busid); 43static void CG6Identify(int flags); 44static Bool CG6Probe(DriverPtr drv, int flags); 45static Bool CG6PreInit(ScrnInfoPtr pScrn, int flags); 46static Bool CG6ScreenInit(int Index, ScreenPtr pScreen, int argc, 47 char **argv); 48static Bool CG6EnterVT(int scrnIndex, int flags); 49static void CG6LeaveVT(int scrnIndex, int flags); 50static Bool CG6CloseScreen(int scrnIndex, ScreenPtr pScreen); 51static Bool CG6SaveScreen(ScreenPtr pScreen, int mode); 52 53/* Required if the driver supports mode switching */ 54static Bool CG6SwitchMode(int scrnIndex, DisplayModePtr mode, int flags); 55/* Required if the driver supports moving the viewport */ 56static void CG6AdjustFrame(int scrnIndex, int x, int y, int flags); 57 58/* Optional functions */ 59static void CG6FreeScreen(int scrnIndex, int flags); 60static ModeStatus CG6ValidMode(int scrnIndex, DisplayModePtr mode, 61 Bool verbose, int flags); 62 63void CG6Sync(ScrnInfoPtr pScrn); 64 65#define CG6_VERSION 4000 66#define CG6_NAME "SUNCG6" 67#define CG6_DRIVER_NAME "suncg6" 68#define CG6_MAJOR_VERSION 1 69#define CG6_MINOR_VERSION 1 70#define CG6_PATCHLEVEL 0 71 72/* 73 * This contains the functions needed by the server after loading the driver 74 * module. It must be supplied, and gets passed back by the SetupProc 75 * function in the dynamic case. In the static case, a reference to this 76 * is compiled in, and this requires that the name of this DriverRec be 77 * an upper-case version of the driver name. 78 */ 79 80_X_EXPORT DriverRec SUNCG6 = { 81 CG6_VERSION, 82 CG6_DRIVER_NAME, 83 CG6Identify, 84 CG6Probe, 85 CG6AvailableOptions, 86 NULL, 87 0 88}; 89 90typedef enum { 91 OPTION_SW_CURSOR, 92 OPTION_HW_CURSOR, 93 OPTION_NOACCEL 94} CG6Opts; 95 96static const OptionInfoRec CG6Options[] = { 97 { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE }, 98 { OPTION_HW_CURSOR, "HWcursor", OPTV_BOOLEAN, {0}, FALSE }, 99 { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, 100 { -1, NULL, OPTV_NONE, {0}, FALSE } 101}; 102 103#ifdef XFree86LOADER 104 105static MODULESETUPPROTO(cg6Setup); 106 107static XF86ModuleVersionInfo suncg6VersRec = 108{ 109 "suncg6", 110 MODULEVENDORSTRING, 111 MODINFOSTRING1, 112 MODINFOSTRING2, 113 XORG_VERSION_CURRENT, 114 CG6_MAJOR_VERSION, CG6_MINOR_VERSION, CG6_PATCHLEVEL, 115 ABI_CLASS_VIDEODRV, 116 ABI_VIDEODRV_VERSION, 117 MOD_CLASS_VIDEODRV, 118 {0,0,0,0} 119}; 120 121_X_EXPORT XF86ModuleData suncg6ModuleData = { &suncg6VersRec, cg6Setup, NULL }; 122 123pointer 124cg6Setup(pointer module, pointer opts, int *errmaj, int *errmin) 125{ 126 static Bool setupDone = FALSE; 127 128 if (!setupDone) { 129 setupDone = TRUE; 130 xf86AddDriver(&SUNCG6, module, 0); 131 132 /* 133 * Modules that this driver always requires can be loaded here 134 * by calling LoadSubModule(). 135 */ 136 137 /* 138 * The return value must be non-NULL on success even though there 139 * is no TearDownProc. 140 */ 141 return (pointer)TRUE; 142 } else { 143 if (errmaj) *errmaj = LDR_ONCEONLY; 144 return NULL; 145 } 146} 147 148#endif /* XFree86LOADER */ 149 150static Bool 151CG6GetRec(ScrnInfoPtr pScrn) 152{ 153 /* 154 * Allocate an Cg6Rec, and hook it into pScrn->driverPrivate. 155 * pScrn->driverPrivate is initialised to NULL, so we can check if 156 * the allocation has already been done. 157 */ 158 if (pScrn->driverPrivate != NULL) 159 return TRUE; 160 161 pScrn->driverPrivate = xnfcalloc(sizeof(Cg6Rec), 1); 162 return TRUE; 163} 164 165static void 166CG6FreeRec(ScrnInfoPtr pScrn) 167{ 168 Cg6Ptr pCg6; 169 170 if (pScrn->driverPrivate == NULL) 171 return; 172 173 pCg6 = GET_CG6_FROM_SCRN(pScrn); 174 175 xfree(pScrn->driverPrivate); 176 pScrn->driverPrivate = NULL; 177 178 return; 179} 180 181static const OptionInfoRec * 182CG6AvailableOptions(int chipid, int busid) 183{ 184 return CG6Options; 185} 186 187/* Mandatory */ 188static void 189CG6Identify(int flags) 190{ 191 xf86Msg(X_INFO, "%s: driver for CGsix (GX and Turbo GX)\n", CG6_NAME); 192} 193 194 195/* Mandatory */ 196static Bool 197CG6Probe(DriverPtr drv, int flags) 198{ 199 int i; 200 GDevPtr *devSections; 201 int *usedChips; 202 int numDevSections; 203 int numUsed; 204 Bool foundScreen = FALSE; 205 EntityInfoPtr pEnt; 206 207 /* 208 * The aim here is to find all cards that this driver can handle, 209 * and for the ones not already claimed by another driver, claim the 210 * slot, and allocate a ScrnInfoRec. 211 * 212 * This should be a minimal probe, and it should under no circumstances 213 * change the state of the hardware. Because a device is found, don't 214 * assume that it will be used. Don't do any initialisations other than 215 * the required ScrnInfoRec initialisations. Don't allocate any new 216 * data structures. 217 */ 218 219 /* 220 * Next we check, if there has been a chipset override in the config file. 221 * For this we must find out if there is an active device section which 222 * is relevant, i.e., which has no driver specified or has THIS driver 223 * specified. 224 */ 225 226 if ((numDevSections = xf86MatchDevice(CG6_DRIVER_NAME, 227 &devSections)) <= 0) { 228 /* 229 * There's no matching device section in the config file, so quit 230 * now. 231 */ 232 return FALSE; 233 } 234 235 /* 236 * We need to probe the hardware first. We then need to see how this 237 * fits in with what is given in the config file, and allow the config 238 * file info to override any contradictions. 239 */ 240 241 numUsed = xf86MatchSbusInstances(CG6_NAME, SBUS_DEVICE_CG6, 242 devSections, numDevSections, 243 drv, &usedChips); 244 245 xfree(devSections); 246 if (numUsed <= 0) 247 return FALSE; 248 249 if (flags & PROBE_DETECT) 250 foundScreen = TRUE; 251 else for (i = 0; i < numUsed; i++) { 252 pEnt = xf86GetEntityInfo(usedChips[i]); 253 254 /* 255 * Check that nothing else has claimed the slots. 256 */ 257 if(pEnt->active) { 258 ScrnInfoPtr pScrn; 259 260 /* Allocate a ScrnInfoRec and claim the slot */ 261 pScrn = xf86AllocateScreen(drv, 0); 262 263 /* Fill in what we can of the ScrnInfoRec */ 264 pScrn->driverVersion = CG6_VERSION; 265 pScrn->driverName = CG6_DRIVER_NAME; 266 pScrn->name = CG6_NAME; 267 pScrn->Probe = CG6Probe; 268 pScrn->PreInit = CG6PreInit; 269 pScrn->ScreenInit = CG6ScreenInit; 270 pScrn->SwitchMode = CG6SwitchMode; 271 pScrn->AdjustFrame = CG6AdjustFrame; 272 pScrn->EnterVT = CG6EnterVT; 273 pScrn->LeaveVT = CG6LeaveVT; 274 pScrn->FreeScreen = CG6FreeScreen; 275 pScrn->ValidMode = CG6ValidMode; 276 xf86AddEntityToScreen(pScrn, pEnt->index); 277 foundScreen = TRUE; 278 } 279 xfree(pEnt); 280 } 281 xfree(usedChips); 282 return foundScreen; 283} 284 285/* Mandatory */ 286static Bool 287CG6PreInit(ScrnInfoPtr pScrn, int flags) 288{ 289 Cg6Ptr pCg6; 290 sbusDevicePtr psdp; 291 MessageType from; 292 int i; 293 294 if (flags & PROBE_DETECT) return FALSE; 295 296 /* 297 * Note: This function is only called once at server startup, and 298 * not at the start of each server generation. This means that 299 * only things that are persistent across server generations can 300 * be initialised here. xf86Screens[] is (pScrn is a pointer to one 301 * of these). Privates allocated using xf86AllocateScrnInfoPrivateIndex() 302 * are too, and should be used for data that must persist across 303 * server generations. 304 * 305 * Per-generation data should be allocated with 306 * AllocateScreenPrivateIndex() from the ScreenInit() function. 307 */ 308 309 /* Allocate the Cg6Rec driverPrivate */ 310 if (!CG6GetRec(pScrn)) { 311 return FALSE; 312 } 313 pCg6 = GET_CG6_FROM_SCRN(pScrn); 314 315 /* Set pScrn->monitor */ 316 pScrn->monitor = pScrn->confScreen->monitor; 317 318 /* This driver doesn't expect more than one entity per screen */ 319 if (pScrn->numEntities > 1) 320 return FALSE; 321 /* This is the general case */ 322 for (i = 0; i < pScrn->numEntities; i++) { 323 EntityInfoPtr pEnt = xf86GetEntityInfo(pScrn->entityList[i]); 324 325 /* CG6 is purely SBUS */ 326 if (pEnt->location.type == BUS_SBUS) { 327 psdp = xf86GetSbusInfoForEntity(pEnt->index); 328 pCg6->psdp = psdp; 329 } else 330 return FALSE; 331 } 332 333 /********************* 334 deal with depth 335 *********************/ 336 337 if (!xf86SetDepthBpp(pScrn, 0, 0, 0, NoDepth24Support)) { 338 return FALSE; 339 } else { 340 /* Check that the returned depth is one we support */ 341 switch (pScrn->depth) { 342 case 8: 343 /* OK */ 344 break; 345 default: 346 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 347 "Given depth (%d) is not supported by this driver\n", 348 pScrn->depth); 349 return FALSE; 350 } 351 } 352 353 /* Collect all of the relevant option flags (fill in pScrn->options) */ 354 xf86CollectOptions(pScrn, NULL); 355 /* Process the options */ 356 if (!(pCg6->Options = xalloc(sizeof(CG6Options)))) 357 return FALSE; 358 memcpy(pCg6->Options, CG6Options, sizeof(CG6Options)); 359 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pCg6->Options); 360 361 if (!xf86SetDefaultVisual(pScrn, -1)) 362 return FALSE; 363 364 /* 365 * The new cmap code requires this to be initialised. 366 */ 367 368 { 369 Gamma zeros = {0.0, 0.0, 0.0}; 370 371 if (!xf86SetGamma(pScrn, zeros)) { 372 return FALSE; 373 } 374 } 375 376 /* Set the bits per RGB for 8bpp mode */ 377 from = X_DEFAULT; 378 379 /* determine whether we use hardware or software cursor */ 380 381 pCg6->HWCursor = TRUE; 382 if (xf86GetOptValBool(pCg6->Options, OPTION_HW_CURSOR, &pCg6->HWCursor)) 383 from = X_CONFIG; 384 if (xf86ReturnOptValBool(pCg6->Options, OPTION_SW_CURSOR, FALSE)) { 385 from = X_CONFIG; 386 pCg6->HWCursor = FALSE; 387 } 388 389 xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n", 390 pCg6->HWCursor ? "HW" : "SW"); 391 392 if (xf86ReturnOptValBool(pCg6->Options, OPTION_NOACCEL, FALSE)) { 393 pCg6->NoAccel = TRUE; 394 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n"); 395 } 396 397 if (xf86LoadSubModule(pScrn, "fb") == NULL) { 398 CG6FreeRec(pScrn); 399 return FALSE; 400 } 401 402 if (pCg6->HWCursor && xf86LoadSubModule(pScrn, "ramdac") == NULL) { 403 CG6FreeRec(pScrn); 404 return FALSE; 405 } 406 407 /********************* 408 set up clock and mode stuff 409 *********************/ 410 411 pScrn->progClock = TRUE; 412 413 if(pScrn->display->virtualX || pScrn->display->virtualY) { 414 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 415 "CG6 does not support a virtual desktop\n"); 416 pScrn->display->virtualX = 0; 417 pScrn->display->virtualY = 0; 418 } 419 420 xf86SbusUseBuiltinMode(pScrn, pCg6->psdp); 421 pScrn->currentMode = pScrn->modes; 422 pScrn->displayWidth = pScrn->virtualX; 423 424 /* Set display resolution */ 425 xf86SetDpi(pScrn, 0, 0); 426 427 return TRUE; 428} 429 430/* Mandatory */ 431 432/* This gets called at the start of each server generation */ 433 434static Bool 435CG6ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) 436{ 437 ScrnInfoPtr pScrn; 438 Cg6Ptr pCg6; 439 int ret; 440 441 /* 442 * First get the ScrnInfoRec 443 */ 444 pScrn = xf86Screens[pScreen->myNum]; 445 446 pCg6 = GET_CG6_FROM_SCRN(pScrn); 447 448 /* Map the CG6 memory */ 449 pCg6->fbc = 450 xf86MapSbusMem (pCg6->psdp, CG6_FBC_VOFF, 451 CG6_RAM_VOFF - CG6_FBC_VOFF + 452 (pCg6->psdp->width * pCg6->psdp->height)); 453 454 if (! pCg6->fbc) 455 return FALSE; 456 457 pCg6->fb = (unsigned char *)pCg6->fbc + CG6_RAM_VOFF - CG6_FBC_VOFF; 458 pCg6->thc = (Cg6ThcPtr)((char *)pCg6->fbc + CG6_THC_VOFF - CG6_FBC_VOFF); 459 460 /* Darken the screen for aesthetic reasons and set the viewport */ 461 CG6SaveScreen(pScreen, SCREEN_SAVER_ON); 462 463 /* 464 * The next step is to setup the screen's visuals, and initialise the 465 * framebuffer code. In cases where the framebuffer's default 466 * choices for things like visual layouts and bits per RGB are OK, 467 * this may be as simple as calling the framebuffer's ScreenInit() 468 * function. If not, the visuals will need to be setup before calling 469 * a fb ScreenInit() function and fixed up after. 470 */ 471 472 /* 473 * Reset visual list. 474 */ 475 miClearVisualTypes(); 476 477 /* Set the bits per RGB for 8bpp mode */ 478 pScrn->rgbBits = 8; 479 480 /* Setup the visuals we support. */ 481 482 if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), 483 pScrn->rgbBits, pScrn->defaultVisual)) 484 return FALSE; 485 486 miSetPixmapDepths (); 487 488 /* 489 * Call the framebuffer layer's ScreenInit function, and fill in other 490 * pScreen fields. 491 */ 492 493 ret = fbScreenInit(pScreen, pCg6->fb, pScrn->virtualX, 494 pScrn->virtualY, pScrn->xDpi, pScrn->yDpi, 495 pScrn->virtualX, 8); 496 if (!ret) 497 return FALSE; 498 499#ifdef RENDER 500 fbPictureInit (pScreen, 0, 0); 501#endif 502 503 miInitializeBackingStore(pScreen); 504 xf86SetBackingStore(pScreen); 505 xf86SetSilkenMouse(pScreen); 506 507 xf86SetBlackWhitePixels(pScreen); 508 509#if 0 510 if (!pCg6->NoAccel) { 511 extern Bool CG6AccelInit(ScreenPtr pScreen, Cg6Ptr pCg6); 512 513 if (!CG6AccelInit(pScreen, pCg6)) 514 return FALSE; 515 xf86Msg(X_INFO, "%s: Using acceleration\n", pCg6->psdp->device); 516 } 517#endif 518 519 /* Initialise cursor functions */ 520 miDCInitialize (pScreen, xf86GetPointerScreenFuncs()); 521 522 /* Initialize HW cursor layer. 523 Must follow software cursor initialization*/ 524 if (pCg6->HWCursor) { 525 extern Bool CG6HWCursorInit(ScreenPtr pScreen); 526 527 if(!CG6HWCursorInit(pScreen)) { 528 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 529 "Hardware cursor initialization failed\n"); 530 return(FALSE); 531 } 532 xf86SbusHideOsHwCursor(pCg6->psdp); 533 } 534 535 /* Initialise default colourmap */ 536 if (!miCreateDefColormap(pScreen)) 537 return FALSE; 538 539 if(!xf86SbusHandleColormaps(pScreen, pCg6->psdp)) 540 return FALSE; 541 542 pCg6->CloseScreen = pScreen->CloseScreen; 543 pScreen->CloseScreen = CG6CloseScreen; 544 pScreen->SaveScreen = CG6SaveScreen; 545 546 /* Report any unused options (only for the first generation) */ 547 if (serverGeneration == 1) { 548 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); 549 } 550 551 /* unblank the screen */ 552 CG6SaveScreen(pScreen, SCREEN_SAVER_OFF); 553 554 /* Done */ 555 return TRUE; 556} 557 558 559/* Usually mandatory */ 560static Bool 561CG6SwitchMode(int scrnIndex, DisplayModePtr mode, int flags) 562{ 563 return TRUE; 564} 565 566 567/* 568 * This function is used to initialize the Start Address - the first 569 * displayed location in the video memory. 570 */ 571/* Usually mandatory */ 572static void 573CG6AdjustFrame(int scrnIndex, int x, int y, int flags) 574{ 575 /* we don't support virtual desktops */ 576 return; 577} 578 579/* 580 * This is called when VT switching back to the X server. Its job is 581 * to reinitialise the video mode. 582 */ 583 584/* Mandatory */ 585static Bool 586CG6EnterVT(int scrnIndex, int flags) 587{ 588 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 589 Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn); 590 591 if (pCg6->HWCursor) { 592 xf86SbusHideOsHwCursor (pCg6->psdp); 593 pCg6->CursorFg = 0; 594 pCg6->CursorBg = 0; 595 } 596 return TRUE; 597} 598 599 600/* 601 * This is called when VT switching away from the X server. 602 */ 603 604/* Mandatory */ 605static void 606CG6LeaveVT(int scrnIndex, int flags) 607{ 608 return; 609} 610 611 612/* 613 * This is called at the end of each server generation. It restores the 614 * original (text) mode. It should really also unmap the video memory too. 615 */ 616 617/* Mandatory */ 618static Bool 619CG6CloseScreen(int scrnIndex, ScreenPtr pScreen) 620{ 621 ScrnInfoPtr pScrn = xf86Screens[scrnIndex]; 622 Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn); 623 624 pScrn->vtSema = FALSE; 625 626 xf86UnmapSbusMem(pCg6->psdp, pCg6->fbc, 627 CG6_RAM_VOFF - CG6_FBC_VOFF + 628 (pCg6->psdp->width * pCg6->psdp->height)); 629 630 if (pCg6->HWCursor) 631 xf86SbusHideOsHwCursor(pCg6->psdp); 632 633 pScreen->CloseScreen = pCg6->CloseScreen; 634 return (*pScreen->CloseScreen)(scrnIndex, pScreen); 635 return FALSE; 636} 637 638 639/* Free up any per-generation data structures */ 640 641/* Optional */ 642static void 643CG6FreeScreen(int scrnIndex, int flags) 644{ 645 CG6FreeRec(xf86Screens[scrnIndex]); 646} 647 648 649/* Checks if a mode is suitable for the selected chipset. */ 650 651/* Optional */ 652static ModeStatus 653CG6ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) 654{ 655 if (mode->Flags & V_INTERLACE) 656 return(MODE_BAD); 657 658 return(MODE_OK); 659} 660 661/* Do screen blanking */ 662 663/* Mandatory */ 664static Bool 665CG6SaveScreen(ScreenPtr pScreen, int mode) 666{ 667 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 668 Cg6Ptr pCg6 = GET_CG6_FROM_SCRN(pScrn); 669 unsigned int tmp = pCg6->thc->thc_misc; 670 671 switch(mode) 672 { 673 case SCREEN_SAVER_ON: 674 case SCREEN_SAVER_CYCLE: 675 tmp &= ~CG6_THC_MISC_SYNC_ENAB; 676 break; 677 case SCREEN_SAVER_OFF: 678 case SCREEN_SAVER_FORCER: 679 tmp |= CG6_THC_MISC_SYNC_ENAB; 680 break; 681 default: 682 return FALSE; 683 } 684 685 pCg6->thc->thc_misc = tmp; 686 return TRUE; 687} 688 689/* 690 * This is the implementation of the Sync() function. 691 */ 692void 693CG6Sync(ScrnInfoPtr pScrn) 694{ 695 return; 696} 697