diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-03-16 03:09:34 +0000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-03-16 03:09:34 +0000 |
commit | 4d6656062129da0489eb4bc898871379ba891d8f (patch) | |
tree | 8aca9273a5eb9b75b64e880b605aaef8dcb08a03 | |
parent | 36799e3ea7ddde5fce528e8bc17ea942933a9111 (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.
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | src/radeon_driver.c | 180 | ||||
-rw-r--r-- | src/radeon_reg.h | 5 |
3 files changed, 162 insertions, 37 deletions
@@ -1,3 +1,17 @@ +2006-03-16 Benjamin Herrenschmidt <benh@kernel.crashing.org> + + * src/radeon_driver.c: (RADEONWaitForVerticalSync), + (RADEONWaitForVerticalSync2), (RADEONLoadPalette), + (RADEONScreenInit), (RADEONRestoreMemMapRegisters), + (RADEONRestoreCrtcRegisters), (RADEONRestoreCrtc2Registers), + (RADEONDoAdjustFrame), (RADEONCloseScreen): + * src/radeon_reg.h: + 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. + 2006-03-15 Benjamin Herrenschmidt <benh@kernel.crashing.org> * src/radeon.h: diff --git a/src/radeon_driver.c b/src/radeon_driver.c index 093f614..b90c305 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.100 2006/03/15 00:46:33 libv Exp $ */ +/* $XdotOrg: driver/xf86-video-ati/src/radeon_driver.c,v 1.101 2006/03/15 04:03:37 benh Exp $ */ /* * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and * VA Linux Systems Inc., Fremont, California. @@ -871,8 +871,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); @@ -888,7 +894,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); @@ -5171,8 +5183,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 @@ -5291,8 +5301,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, @@ -6094,6 +6102,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; @@ -6129,7 +6141,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")); @@ -6138,39 +6152,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) { @@ -6279,7 +6346,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, @@ -6308,6 +6393,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 */ @@ -6316,12 +6403,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); @@ -6348,6 +6456,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); @@ -8661,7 +8772,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 / @@ -8754,15 +8867,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); } @@ -8945,7 +9054,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 c5dca46..71b10c0 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 |