diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-03-16 03:14:11 +0000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-03-16 03:14:11 +0000 |
commit | bb1cb23516f2a835bc8ba4f4bb168dad75429c35 (patch) | |
tree | f71a0291794d03c178d1d906b153a31fbc1b886e /src | |
parent | 6a7111d0b4408cc6862be2c4f39e731e081ffea4 (diff) |
Add various workarounds that seem to fix some remaning lockup scenarios I'm
experiencing with the driver when setting the memory map. Some of the
magic delays are a bit dodgy but they seem to work, I suppose I can't
do better now without help from ATI. Also removed some really too noisy
debug messages.
Diffstat (limited to 'src')
-rw-r--r-- | src/radeon_driver.c | 180 | ||||
-rw-r--r-- | src/radeon_reg.h | 5 |
2 files changed, 148 insertions, 37 deletions
diff --git a/src/radeon_driver.c b/src/radeon_driver.c index 6a004cf6..6f210472 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -1,5 +1,5 @@ /* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c,v 1.117 2004/02/19 22:38:12 tsi Exp $ */ -/* $XdotOrg: driver/xf86-video-ati/src/radeon_driver.c,v 1.92.2.6 2006/03/13 00:14:15 benh Exp $ */ +/* $XdotOrg: driver/xf86-video-ati/src/radeon_driver.c,v 1.92.2.7 2006/03/15 04:12:43 benh Exp $ */ /* * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and * VA Linux Systems Inc., Fremont, California. @@ -870,8 +870,14 @@ void RADEONWaitForVerticalSync(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; + CARD32 crtc_gen_cntl; int i; + crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL); + if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) || + !(crtc_gen_cntl & RADEON_CRTC_EN)) + return; + /* Clear the CRTC_VBLANK_SAVE bit */ OUTREG(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR); @@ -887,7 +893,13 @@ void RADEONWaitForVerticalSync2(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; + CARD32 crtc2_gen_cntl; int i; + + crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); + if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) || + !(crtc2_gen_cntl & RADEON_CRTC2_EN)) + return; /* Clear the CRTC2_VBLANK_SAVE bit */ OUTREG(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR); @@ -5168,8 +5180,6 @@ static void RADEONLoadPalette(ScrnInfoPtr pScrn, int numColors, int idx, j; unsigned char r, g, b; - RADEONTRACE(("RADEONLoadPalette !\n")); - #ifdef XF86DRI if (info->CPStarted && pScrn->pScreen) DRILock(pScrn->pScreen, 0); #endif @@ -5288,8 +5298,6 @@ static void RADEONLoadPalette(ScrnInfoPtr pScrn, int numColors, #ifdef XF86DRI if (info->CPStarted && pScrn->pScreen) DRIUnlock(pScrn->pScreen); #endif - - RADEONTRACE(("LoadPalette() end\n")); } static void RADEONBlockHandler(int i, pointer blockData, @@ -6091,6 +6099,10 @@ _X_EXPORT Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, RADEONTRACE(("Initializing Xv\n")); RADEONInitVideo(pScreen); + if(info->MergedFB) + /* need this here to fix up sarea values */ + RADEONAdjustFrameMerged(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + /* Provide SaveScreen & wrap BlockHandler and CloseScreen */ /* Wrap CloseScreen */ info->CloseScreen = pScreen->CloseScreen; @@ -6126,7 +6138,9 @@ static void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn, */ if (INREG(RADEON_MC_FB_LOCATION) != restore->mc_fb_location || INREG(RADEON_MC_AGP_LOCATION) != restore->mc_agp_location) { - CARD32 tmp; + CARD32 crtc_ext_cntl, crtc_gen_cntl, crtc2_gen_cntl=0, ov0_scale_cntl; + CARD32 old_mc_status, status_idle; + int timeout; RADEONTRACE((" Map Changed ! Applying ...\n")); @@ -6135,39 +6149,92 @@ static void RADEONRestoreMemMapRegisters(ScrnInfoPtr pScrn, */ RADEONWaitForIdleMMIO(pScrn); + if (info->IsIGP) + goto igp_no_mcfb; + + /* Capture MC_STATUS in case things go wrong ... */ + old_mc_status = INREG(RADEON_MC_STATUS); + /* Stop display & memory access */ - tmp = INREG(RADEON_CRTC_EXT_CNTL); - OUTREG(RADEON_CRTC_EXT_CNTL, tmp | RADEON_CRTC_DISPLAY_DIS); - tmp = INREG(RADEON_CRTC_GEN_CNTL); - tmp &= ~RADEON_CRTC_CUR_EN; - tmp |= RADEON_CRTC_DISP_REQ_EN_B; - OUTREG(RADEON_CRTC_GEN_CNTL, tmp); - if (info->HasCRTC2) { - tmp = INREG(RADEON_CRTC2_GEN_CNTL); - tmp &= ~RADEON_CRTC2_CUR_EN; - tmp |= RADEON_CRTC2_DISP_DIS | RADEON_CRTC2_DISP_REQ_EN_B; - OUTREG(RADEON_CRTC2_GEN_CNTL, tmp); + ov0_scale_cntl = INREG(RADEON_OV0_SCALE_CNTL); + OUTREG(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl & ~RADEON_SCALER_ENABLE); + crtc_ext_cntl = INREG(RADEON_CRTC_EXT_CNTL); + OUTREG(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl | RADEON_CRTC_DISPLAY_DIS); + crtc_gen_cntl = INREG(RADEON_CRTC_GEN_CNTL); + RADEONWaitForVerticalSync(pScrn); + OUTREG(RADEON_CRTC_GEN_CNTL, + (crtc_gen_cntl + & ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_ICON_EN | RADEON_CRTC_EN)) + | RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_EXT_DISP_EN); + + if (info->HasCRTC2) { + crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL); + RADEONWaitForVerticalSync2(pScrn); + OUTREG(RADEON_CRTC2_GEN_CNTL, + (crtc2_gen_cntl + & ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_ICON_EN | + RADEON_CRTC2_EN)) + | RADEON_CRTC2_DISP_REQ_EN_B | RADEON_CRTC2_EN); + } + + /* Make sure the chip settles down (paranoid !) */ + usleep(100000); + + /* Wait for MC idle */ + if (IS_R300_VARIANT) + status_idle = R300_MC_IDLE; + else + status_idle = RADEON_MC_IDLE; + + while (!(INREG(RADEON_MC_STATUS) & status_idle)) { + if (++timeout > 1000000) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Timeout trying to update memory controller settings !\n"); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "MC_STATUS = 0x%08x (on entry = 0x%08x)\n", + INREG(RADEON_MC_STATUS), old_mc_status); + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "You will probably crash now ... \n"); + /* Nothing we can do except maybe try to kill the server, + * let's wait 2 seconds to leave the above message a chance + * to maybe hit the disk and continue trying to setup despite + * the MC being non-idle + */ + usleep(2000000); + } } - tmp = INREG(RADEON_OV0_SCALE_CNTL); - tmp &= ~RADEON_SCALER_ENABLE; - OUTREG(RADEON_OV0_SCALE_CNTL, tmp); - /* Make sure the chip settles down and set new map*/ - usleep(100000); + /* Update maps, first clearing out AGP to make sure we don't get + * a temporary overlap + */ + OUTREG(RADEON_MC_AGP_LOCATION, 0xfffffffc); OUTREG(RADEON_MC_FB_LOCATION, restore->mc_fb_location); + igp_no_mcfb: OUTREG(RADEON_MC_AGP_LOCATION, restore->mc_agp_location); /* Make sure map fully reached the chip */ (void)INREG(RADEON_MC_FB_LOCATION); + RADEONTRACE((" Map applied, resetting engine ...\n")); + /* Reset the engine and HDP */ RADEONEngineReset(pScrn); + + RADEONTRACE((" All done.\n")); } - + + RADEONTRACE(("Updating base addresses...\n")); + /* Restore base addresses */ OUTREG(RADEON_DISPLAY_BASE_ADDR, restore->display_base_addr); - OUTREG(RADEON_DISPLAY2_BASE_ADDR, restore->display2_base_addr); + if (info->HasCRTC2) + OUTREG(RADEON_DISPLAY2_BASE_ADDR, restore->display2_base_addr); OUTREG(RADEON_OV0_BASE_ADDR, restore->ov0_base_addr); -} + + /* Flush PCI posting, make sure the above actually hit the card */ + (void)INREG(RADEON_OV0_BASE_ADDR); + + RADEONTRACE(("Done updating base addresses.\n")); + } static void RADEONAdjustMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save) { @@ -6276,7 +6343,25 @@ static void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; - OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl); + RADEONTRACE(("Programming CRTC1, offset: 0x%08x\n", + restore->crtc_offset)); + + /* Make sure we have sane offsets before enabling */ + OUTREG(RADEON_CRTC_OFFSET, 0); + OUTREG(RADEON_CRTC_OFFSET_CNTL, 0); + OUTREG(RADEON_CUR_OFFSET, 0); + + /* Magic delay ! This helps fixing a lockup on some setups, maybe + * the above need some time to properly hit the CRTC before we enable + * it, go figure ... + */ + usleep(100000); + + /* We prevent the CRTC from hitting the memory controller until + * fully programmed + */ + OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl | + RADEON_CRTC_DISP_REQ_EN_B); OUTREGP(RADEON_CRTC_EXT_CNTL, restore->crtc_ext_cntl, @@ -6305,6 +6390,8 @@ static void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn, OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); OUTREG(RADEON_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl); } + + OUTREG(RADEON_CRTC_GEN_CNTL, restore->crtc_gen_cntl); } /* Write CRTC2 registers */ @@ -6313,12 +6400,33 @@ static void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; + CARD32 crtc2_gen_cntl; - OUTREGP(RADEON_CRTC2_GEN_CNTL, - restore->crtc2_gen_cntl, - RADEON_CRTC2_VSYNC_DIS | - RADEON_CRTC2_HSYNC_DIS | - RADEON_CRTC2_DISP_DIS); + RADEONTRACE(("Programming CRTC2, offset: 0x%08x\n", + restore->crtc2_offset)); + + /* Make sure we have sane offsets before enabling */ + OUTREG(RADEON_CRTC2_OFFSET, 0); + OUTREG(RADEON_CRTC2_OFFSET_CNTL, 0); + OUTREG(RADEON_CUR2_OFFSET, 0); + + /* Magic delay ! This helps fixing a lockup on some setups, maybe + * the above need some time to properly hit the CRTC before we enable + * it, go figure ... + */ + usleep(100000); + + crtc2_gen_cntl = INREG(RADEON_CRTC2_GEN_CNTL) & + (RADEON_CRTC2_VSYNC_DIS | + RADEON_CRTC2_HSYNC_DIS | + RADEON_CRTC2_DISP_DIS); + crtc2_gen_cntl |= restore->crtc2_gen_cntl; + + /* We prevent the CRTC from hitting the memory controller until + * fully programmed + */ + OUTREG(RADEON_CRTC2_GEN_CNTL, + crtc2_gen_cntl | RADEON_CRTC2_DISP_REQ_EN_B); OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl); @@ -6345,6 +6453,9 @@ static void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn, OUTREG(RADEON_FP_V2_SYNC_STRT_WID, restore->fp2_v_sync_strt_wid); OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl); } + + OUTREG(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl); + #if 0 /* Hack for restoring text mode -- fixed elsewhere */ usleep(100000); @@ -8658,7 +8769,9 @@ void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int clone) XF86DRISAREAPtr pSAREA; #endif +#if 0 /* Verbose */ RADEONTRACE(("RADEONDoAdjustFrame(%d,%d,%d)\n", x, y, clone)); +#endif if (info->showCache && y) { int lastline = info->FbMapSize / @@ -8751,15 +8864,11 @@ void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int clone) } #endif - RADEONTRACE((" -> reg : 0x%04x = 0x%08x\n", reg, Base)); - OUTREG(reg, Base); if (IS_R300_VARIANT) { - RADEONTRACE((" regcntl : 0x%04x = 0x%08x\n", xytilereg, crtcxytile)); OUTREG(xytilereg, crtcxytile); } else { - RADEONTRACE((" regcntl : 0x%04x = 0x%08x\n", regcntl, crtcoffsetcntl)); OUTREG(regcntl, crtcoffsetcntl); } @@ -8942,7 +9051,6 @@ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen) RADEONTRACE(("Disposing DGA\n")); if (info->DGAModes) xfree(info->DGAModes); info->DGAModes = NULL; - RADEONTRACE(("Unmapping memory\n")); RADEONUnmapMem(pScrn); diff --git a/src/radeon_reg.h b/src/radeon_reg.h index c5dca461..71b10c02 100644 --- a/src/radeon_reg.h +++ b/src/radeon_reg.h @@ -307,9 +307,9 @@ # define RADEON_CRTC_DBL_SCAN_EN (1 << 0) # define RADEON_CRTC_INTERLACE_EN (1 << 1) # define RADEON_CRTC_CSYNC_EN (1 << 4) +# define RADEON_CRTC_ICON_EN (1 << 15) # define RADEON_CRTC_CUR_EN (1 << 16) # define RADEON_CRTC_CUR_MODE_MASK (7 << 17) -# define RADEON_CRTC_ICON_EN (1 << 20) # define RADEON_CRTC_EXT_DISP_EN (1 << 24) # define RADEON_CRTC_EN (1 << 25) # define RADEON_CRTC_DISP_REQ_EN_B (1 << 26) @@ -849,6 +849,9 @@ #define RADEON_MAX_LATENCY 0x0f3f /* PCI */ #define RADEON_MC_AGP_LOCATION 0x014c #define RADEON_MC_FB_LOCATION 0x0148 +#define RADEON_MC_STATUS 0x0150 +# define RADEON_MC_IDLE (1 << 2) +# define R300_MC_IDLE (1 << 4) #define RADEON_DISPLAY_BASE_ADDR 0x23c #define RADEON_DISPLAY2_BASE_ADDR 0x33c #define RADEON_OV0_BASE_ADDR 0x43c |