lx_display.c revision e9a8eab3
1/* Copyright (c) 2008 Advanced Micro Devices, Inc. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 * 21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its 22 * contributors may be used to endorse or promote products derived from this 23 * software without specific prior written permission. 24 */ 25 26#ifdef HAVE_CONFIG_H 27#include "config.h" 28#endif 29 30#include "xf86.h" 31#include "geode.h" 32#include "xf86Crtc.h" 33#include "cim/cim_defs.h" 34#include "cim/cim_regs.h" 35 36typedef struct _LXOutputPrivateRec { 37 int video_enable; 38 unsigned long video_flags; 39 GeodeMemPtr rotate_mem; 40} LXCrtcPrivateRec, *LXCrtcPrivatePtr; 41 42void 43lx_enable_dac_power(ScrnInfoPtr pScrni, int option) 44{ 45 GeodeRec *pGeode = GEODEPTR(pScrni); 46 47 df_set_crt_enable(DF_CRT_ENABLE); 48 49 /* Turn off the DAC if we don't need the CRT */ 50 51 if (option && (!(pGeode->Output & OUTPUT_CRT))) { 52 unsigned int misc = READ_VID32(DF_VID_MISC); 53 54 misc |= DF_DAC_POWER_DOWN; 55 WRITE_VID32(DF_VID_MISC, misc); 56 } 57 58 if (pGeode->Output & OUTPUT_PANEL) 59 df_set_panel_enable(1); 60} 61 62void 63lx_disable_dac_power(ScrnInfoPtr pScrni, int option) 64{ 65 GeodeRec *pGeode = GEODEPTR(pScrni); 66 67 if (pGeode->Output & OUTPUT_PANEL) 68 df_set_panel_enable(0); 69 70 if (pGeode->Output & OUTPUT_CRT) { 71 72 /* Wait for the panel to finish its procedure */ 73 74 if (pGeode->Output & OUTPUT_PANEL) 75 while ((READ_VID32(DF_POWER_MANAGEMENT) & 2) == 0); 76 df_set_crt_enable(option); 77 } 78} 79 80static void 81lx_set_panel_mode(VG_DISPLAY_MODE * mode, DisplayModePtr pMode) 82{ 83 int hsync, vsync; 84 85 mode->mode_width = mode->panel_width = pMode->HDisplay; 86 mode->mode_height = mode->panel_height = pMode->VDisplay; 87 88 mode->hactive = pMode->HDisplay; 89 mode->hblankstart = pMode->HDisplay; 90 mode->hsyncstart = pMode->HSyncStart; 91 mode->hsyncend = pMode->HSyncEnd; 92 mode->hblankend = pMode->HTotal; 93 mode->htotal = pMode->HTotal; 94 95 mode->vactive = pMode->VDisplay; 96 mode->vblankstart = pMode->VDisplay; 97 mode->vsyncstart = pMode->VSyncStart; 98 mode->vsyncend = pMode->VSyncEnd; 99 mode->vblankend = pMode->VTotal; 100 mode->vtotal = pMode->VTotal; 101 102 mode->vactive_even = pMode->VDisplay; 103 mode->vblankstart_even = pMode->VDisplay; 104 mode->vsyncstart_even = pMode->VSyncStart; 105 mode->vsyncend_even = pMode->VSyncEnd; 106 mode->vblankend_even = pMode->VTotal; 107 mode->vtotal_even = pMode->VTotal; 108 109 mode->frequency = (int) ((pMode->Clock / 1000.0) * 0x10000); 110 111 /* In panel mode, Cimarron purposely swizzles these, 112 * so we swizzle them first */ 113 114 hsync = (pMode->Flags & V_NHSYNC) ? 0 : 1; 115 vsync = (pMode->Flags & V_NVSYNC) ? 0 : 1; 116 117 mode->flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0; 118 mode->flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0; 119} 120 121static void 122lx_set_crt_mode(VG_DISPLAY_MODE * mode, DisplayModePtr pMode) 123{ 124 int hsync, vsync; 125 126 mode->mode_width = mode->panel_width = pMode->HDisplay; 127 mode->mode_height = mode->panel_height = pMode->VDisplay; 128 129 mode->hactive = pMode->CrtcHDisplay; 130 mode->hblankstart = pMode->CrtcHBlankStart; 131 mode->hsyncstart = pMode->CrtcHSyncStart; 132 mode->hsyncend = pMode->CrtcHSyncEnd; 133 mode->hblankend = pMode->CrtcHBlankEnd; 134 mode->htotal = pMode->CrtcHTotal; 135 136 mode->vactive = pMode->CrtcVDisplay; 137 mode->vblankstart = pMode->CrtcVBlankStart; 138 mode->vsyncstart = pMode->CrtcVSyncStart; 139 mode->vsyncend = pMode->CrtcVSyncEnd; 140 mode->vblankend = pMode->CrtcVBlankEnd; 141 mode->vtotal = pMode->CrtcVTotal; 142 143 mode->vactive_even = pMode->CrtcVDisplay; 144 mode->vblankstart_even = pMode->CrtcVBlankStart; 145 mode->vsyncstart_even = pMode->CrtcVSyncStart; 146 mode->vsyncend_even = pMode->CrtcVSyncEnd; 147 mode->vblankend_even = pMode->CrtcVBlankEnd; 148 mode->vtotal_even = pMode->CrtcVTotal; 149 150 mode->frequency = (int) ((pMode->Clock / 1000.0) * 0x10000); 151 152 hsync = (pMode->Flags & V_NHSYNC) ? 1 : 0; 153 vsync = (pMode->Flags & V_NVSYNC) ? 1 : 0; 154 155 mode->flags |= (hsync) ? VG_MODEFLAG_NEG_HSYNC : 0; 156 mode->flags |= (vsync) ? VG_MODEFLAG_NEG_VSYNC : 0; 157} 158 159static int 160lx_set_mode(ScrnInfoPtr pScrni, DisplayModePtr pMode, int bpp) 161{ 162 GeodeRec *pGeode = GEODEPTR(pScrni); 163 VG_DISPLAY_MODE mode; 164 int ret; 165 166 memset(&mode, 0, sizeof(mode)); 167 168 mode.flags |= pGeode->Output & OUTPUT_CRT ? VG_MODEFLAG_CRT_AND_FP : 0; 169 170 if (pGeode->Output & OUTPUT_PANEL) { 171 mode.flags |= VG_MODEFLAG_PANELOUT; 172 if (pGeode->Output & OUTPUT_CRT) 173 mode.flags |= VG_MODEFLAG_CRT_AND_FP; 174 } 175 176 if (pGeode->Output & OUTPUT_PANEL && pGeode->Scale) 177 lx_set_panel_mode(&mode, pGeode->panelMode); 178 else 179 lx_set_crt_mode(&mode, pMode); 180 181 mode.src_width = pMode->HDisplay; 182 mode.src_height = pMode->VDisplay; 183 184 /* Set the filter coefficients to the default values */ 185 vg_set_scaler_filter_coefficients(NULL, NULL); 186 187 ret = vg_set_custom_mode(&mode, bpp); 188 return (ret == CIM_STATUS_OK) ? 0 : -1; 189} 190 191static void 192lx_crtc_dpms(xf86CrtcPtr crtc, int mode) 193{ 194 ScrnInfoPtr pScrni = crtc->scrn; 195 GeodeRec *pGeode = GEODEPTR(pScrni); 196 197 if (pGeode->Output & OUTPUT_DCON) 198 DCONDPMSSet(pScrni, mode); 199 200 switch (mode) { 201 case DPMSModeOn: 202 lx_enable_dac_power(pScrni, 1); 203 break; 204 205 case DPMSModeStandby: 206 lx_disable_dac_power(pScrni, DF_CRT_STANDBY); 207 break; 208 209 case DPMSModeSuspend: 210 lx_disable_dac_power(pScrni, DF_CRT_SUSPEND); 211 break; 212 213 case DPMSModeOff: 214 lx_disable_dac_power(pScrni, DF_CRT_DISABLE); 215 break; 216 } 217} 218 219static Bool 220lx_crtc_lock(xf86CrtcPtr crtc) 221{ 222 /* Wait until the GPU is idle */ 223 gp_wait_until_idle(); 224 return TRUE; 225} 226 227static void 228lx_crtc_unlock(xf86CrtcPtr crtc) 229{ 230 /* Nothing to do here */ 231} 232 233static void 234lx_crtc_prepare(xf86CrtcPtr crtc) 235{ 236 LXCrtcPrivatePtr lx_crtc = crtc->driver_private; 237 238 /* Disable the video */ 239 df_get_video_enable(&lx_crtc->video_enable, &lx_crtc->video_flags); 240 241 if (lx_crtc->video_enable) 242 df_set_video_enable(0, 0); 243 244 /* Turn off compression */ 245 vg_set_compression_enable(0); 246 247 /* Hide the cursor */ 248 crtc->funcs->hide_cursor(crtc); 249 250 /* Turn off the display */ 251 crtc->funcs->dpms(crtc, DPMSModeOff); 252} 253 254static Bool 255lx_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, 256 DisplayModePtr adjusted_mode) 257{ 258 return TRUE; 259} 260 261static void 262lx_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, 263 DisplayModePtr adjusted_mode, int x, int y) 264{ 265 ScrnInfoPtr pScrni = crtc->scrn; 266 GeodeRec *pGeode = GEODEPTR(pScrni); 267 DF_VIDEO_SOURCE_PARAMS vs_odd, vs_even; 268 unsigned int rpitch; 269 270 df_get_video_source_configuration(&vs_odd, &vs_even); 271 272 /* Note - the memory gets adjusted when virtualX/virtualY 273 * gets changed - so we don't need to worry about it here 274 */ 275 276 if (lx_set_mode(pScrni, adjusted_mode, pScrni->bitsPerPixel)) 277 ErrorF("ERROR! Unable to set the mode!\n"); 278 279 /* The output gets turned in in the output code as 280 * per convention */ 281 282 /* For rotation, any write to the frame buffer region marks 283 * the retire frame as dirty. 284 */ 285 if (crtc->rotatedData != NULL) { 286 rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8); 287 vg_set_display_pitch(rpitch); 288 } 289 else 290 vg_set_display_pitch(pGeode->Pitch); 291 gp_set_bpp(pScrni->bitsPerPixel); 292 293 /* Set the acceleration offset if we are drawing to a shadow */ 294 if (crtc->rotatedData != NULL) 295 vg_set_display_offset((unsigned int) ((char *) crtc->rotatedData - 296 (char *) pGeode->FBBase)); 297 else 298 vg_set_display_offset(0); 299 300 /* FIXME: Whats up with X and Y? Does that come into play 301 * here? */ 302 303 df_configure_video_source(&vs_odd, &vs_even); 304 305 vg_wait_vertical_blank(); 306} 307 308static void 309lx_crtc_commit(xf86CrtcPtr crtc) 310{ 311 LXCrtcPrivatePtr lx_crtc = crtc->driver_private; 312 ScrnInfoPtr pScrni = crtc->scrn; 313 GeodeRec *pGeode = GEODEPTR(pScrni); 314 315 /* Turn back on the sreen */ 316 crtc->funcs->dpms(crtc, DPMSModeOn); 317 318 /* Turn on compression */ 319 320 if (pGeode->Compression) { 321 vg_configure_compression(&(pGeode->CBData)); 322 vg_set_compression_enable(1); 323 } 324 325 /* Load the cursor */ 326 if (crtc->scrn->pScreen != NULL) { 327 xf86_reload_cursors(crtc->scrn->pScreen); 328 crtc->funcs->hide_cursor(crtc); 329 crtc->cursor_shown = FALSE; 330 } 331 332 /* Renable the video */ 333 334 if (lx_crtc->video_enable) 335 df_set_video_enable(lx_crtc->video_enable, lx_crtc->video_flags); 336 337 lx_crtc->video_enable = 0; 338 lx_crtc->video_flags = 0; 339} 340 341static void 342lx_crtc_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, 343 CARD16 *blue, int size) 344{ 345 unsigned int dcfg; 346 int i; 347 348 assert(size == 256); 349 350 /* We need the Gamma Correction for video - fading operation, 351 * the values address should be plused for every cycle. 352 * Special for Screensaver Operation. 353 */ 354 355 for (i = 0; i < 256; i++) { 356 unsigned int val; 357 358 (*red) &= 0xff00; 359 (*green) &= 0xff00; 360 (*blue) &= 0xff00; 361 val = (*(red++) << 8) | *(green++) | (*(blue++) >> 8); 362 363 df_set_video_palette_entry(i, val); 364 } 365 366 /* df_set_video_palette_entry automatically turns on 367 * gamma for video - if this gets called, we assume that 368 * RandR wants it set for graphics, so reverse cimarron 369 */ 370 371 dcfg = READ_VID32(DF_DISPLAY_CONFIG); 372 dcfg &= ~DF_DCFG_GV_PAL_BYP; 373 WRITE_VID32(DF_DISPLAY_CONFIG, dcfg); 374} 375 376 /* The Xserver has a scratch pixmap allocation routine that will 377 * try to use the existing scratch pixmap if possible. When the driver 378 * or any other user stop using it, it need to clear out any pixmap 379 * state (private data etc) otherwise the next user may get stale data. 380 */ 381 382 /* Use our own wrapper to allocate a pixmap for wrapping a buffer object 383 * It removes using scratch pixmaps for rotate. 384 */ 385static PixmapPtr 386lx_create_bo_pixmap(ScreenPtr pScreen, 387 int width, int height, 388 int depth, int bpp, int pitch, pointer pPixData) 389{ 390 PixmapPtr pixmap; 391 392#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,0,0,0) 393 pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0); 394#else 395 pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth); 396#endif 397 398 if (!pixmap) 399 return NULL; 400 if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height, 401 depth, bpp, pitch, pPixData)) { 402 /* ModifyPixmapHeader failed, so we can't use it as scratch pixmap 403 */ 404 (*pScreen->DestroyPixmap) (pixmap); 405 return NULL; 406 } 407 408 return pixmap; 409} 410 411static void 412lx_destory_bo_pixmap(PixmapPtr pixmap) 413{ 414 ScreenPtr pScreen = pixmap->drawable.pScreen; 415 416 (*pScreen->DestroyPixmap) (pixmap); 417} 418 419 /* Allocates shadow memory, and allocating a new space for Rotation. 420 * The size is measured in bytes, and the offset from the beginning 421 * of card space is returned. 422 */ 423 424static Bool 425LXAllocShadow(ScrnInfoPtr pScrni, int size) 426{ 427 GeodeRec *pGeode = GEODEPTR(pScrni); 428 429 if (pGeode->shadowArea) { 430 if (pGeode->shadowArea->size != size) { 431 exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea); 432 pGeode->shadowArea = NULL; 433 } 434 } 435 436 if (pGeode->shadowArea == NULL) { 437 pGeode->shadowArea = 438 exaOffscreenAlloc(pScrni->pScreen, size, 4, TRUE, NULL, NULL); 439 440 if (pGeode->shadowArea == NULL) 441 return FALSE; 442 } 443 444 pScrni->fbOffset = pGeode->shadowArea->offset; 445 return TRUE; 446} 447 448static void * 449lx_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 450{ 451 ScrnInfoPtr pScrni = crtc->scrn; 452 GeodePtr pGeode = GEODEPTR(pScrni); 453 unsigned int rpitch, size; 454 455 rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8); 456 size = rpitch * height; 457 458 /* Allocate shadow memory */ 459 if (LXAllocShadow(pScrni, size) == FALSE) { 460 xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 461 "Couldn't allocate the shadow memory for rotation\n"); 462 xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 463 " You need 0x%x bytes, but only 0x%x bytes are available\n", 464 size, GeodeOffscreenFreeSize(pGeode)); 465 466 return NULL; 467 } 468 469 memset(pGeode->FBBase + pGeode->shadowArea->offset, 0, size); 470 return pGeode->FBBase + pGeode->shadowArea->offset; 471} 472 473static PixmapPtr 474lx_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 475{ 476 ScrnInfoPtr pScrni = crtc->scrn; 477 PixmapPtr rpixmap; 478 unsigned int rpitch; 479 480 rpitch = pScrni->displayWidth * (pScrni->bitsPerPixel / 8); 481 if (!data) 482 data = lx_crtc_shadow_allocate(crtc, width, height); 483 484 rpixmap = lx_create_bo_pixmap(pScrni->pScreen, 485 width, height, pScrni->depth, 486 pScrni->bitsPerPixel, rpitch, data); 487 488 if (rpixmap == NULL) { 489 xf86DrvMsg(pScrni->scrnIndex, X_ERROR, 490 "Couldn't allocate shadow pixmap for rotated CRTC\n"); 491 } 492 493 return rpixmap; 494} 495 496static void 497lx_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rpixmap, void *data) 498{ 499 ScrnInfoPtr pScrni = crtc->scrn; 500 GeodeRec *pGeode = GEODEPTR(pScrni); 501 502 if (rpixmap) 503 lx_destory_bo_pixmap(rpixmap); 504 505 /* Free shadow memory */ 506 if (data) { 507 gp_wait_until_idle(); 508 if (pGeode->shadowArea != NULL) { 509 exaOffscreenFree(pScrni->pScreen, pGeode->shadowArea); 510 pGeode->shadowArea = NULL; 511 } 512 } 513} 514 515static void 516lx_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 517{ 518 vg_set_mono_cursor_colors(bg, fg); 519} 520 521static void 522lx_crtc_set_cursor_position(xf86CrtcPtr crtc, int x, int y) 523{ 524 VG_PANNING_COORDINATES panning; 525 526 vg_set_cursor_position(x, y, &panning); 527} 528 529static void 530lx_crtc_show_cursor(xf86CrtcPtr crtc) 531{ 532 vg_set_cursor_enable(1); 533} 534 535static void 536lx_crtc_hide_cursor(xf86CrtcPtr crtc) 537{ 538 vg_set_cursor_enable(0); 539} 540 541static void 542lx_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image) 543{ 544 LXLoadARGBCursorImage(crtc->scrn, (unsigned char *) image); 545} 546 547static const xf86CrtcFuncsRec lx_crtc_funcs = { 548 .dpms = lx_crtc_dpms, 549 .lock = lx_crtc_lock, 550 .unlock = lx_crtc_unlock, 551 .mode_fixup = lx_crtc_mode_fixup, 552 .prepare = lx_crtc_prepare, 553 .mode_set = lx_crtc_mode_set, 554 .commit = lx_crtc_commit, 555 .gamma_set = lx_crtc_gamma_set, 556 .shadow_create = lx_crtc_shadow_create, 557 .shadow_allocate = lx_crtc_shadow_allocate, 558 .shadow_destroy = lx_crtc_shadow_destroy, 559 .set_cursor_colors = lx_crtc_set_cursor_colors, 560 .set_cursor_position = lx_crtc_set_cursor_position, 561 .show_cursor = lx_crtc_show_cursor, 562 .hide_cursor = lx_crtc_hide_cursor, 563 .load_cursor_argb = lx_crtc_load_cursor_argb, 564}; 565 566void 567LXSetupCrtc(ScrnInfoPtr pScrni) 568{ 569 xf86CrtcPtr crtc; 570 LXCrtcPrivatePtr lxpriv; 571 572 crtc = xf86CrtcCreate(pScrni, &lx_crtc_funcs); 573 574 if (crtc == NULL) { 575 ErrorF("ERROR - failed to create a CRTC\n"); 576 return; 577 } 578 579 lxpriv = xnfcalloc(1, sizeof(LXCrtcPrivateRec)); 580 581 if (!lxpriv) { 582 xf86CrtcDestroy(crtc); 583 ErrorF("unable to allocate memory for lxpriv\n"); 584 return; 585 } 586 587 crtc->driver_private = lxpriv; 588} 589