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