diff options
Diffstat (limited to 'src/radeon_driver.c')
-rw-r--r-- | src/radeon_driver.c | 527 |
1 files changed, 345 insertions, 182 deletions
diff --git a/src/radeon_driver.c b/src/radeon_driver.c index bfc50c43..88183797 100644 --- a/src/radeon_driver.c +++ b/src/radeon_driver.c @@ -1,4 +1,4 @@ -/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c,v 1.104 2003/08/23 15:02:54 dawes Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c,v 1.117 2004/02/19 22:38:12 tsi Exp $ */ /* * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and * VA Linux Systems Inc., Fremont, California. @@ -154,7 +154,8 @@ typedef enum { OPTION_NORADEONXINERAMA, OPTION_CRT2ISSCRN0, OPTION_DISP_PRIORITY, - OPTION_PANEL_SIZE + OPTION_PANEL_SIZE, + OPTION_MIN_DOTCLOCK } RADEONOpts; const OptionInfoRec RADEONOptions[] = { @@ -192,6 +193,7 @@ const OptionInfoRec RADEONOptions[] = { { OPTION_CRT2ISSCRN0, "MergedXineramaCRT2IsScreen0", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_DISP_PRIORITY, "DisplayPriority", OPTV_ANYSTR, {0}, FALSE }, { OPTION_PANEL_SIZE, "PanelSize", OPTV_ANYSTR, {0}, FALSE }, + { OPTION_MIN_DOTCLOCK, "ForceMinDotClock", OPTV_FREQ, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; @@ -395,7 +397,7 @@ static struct {1024, 768, 87}, {832, 624, 75}, {800, 600, 75}, - {800, 600, 72}, + {800, 600, 72}, {800, 600, 60}, {800, 600, 56}, {640, 480, 75}, @@ -457,7 +459,7 @@ RADEONPreInt10Save(ScrnInfoPtr pScrn, void **pPtr) SaveStruct.MEMSIZE = INREG(RADEON_CONFIG_MEMSIZE); SaveStruct.MPP_TB_CONFIG = INREG(RADEON_MPP_TB_CONFIG); - /* + /* * Zap MEM_CNTL and set MPP_TB_CONFIG<31:24> to 4 */ OUTREG(RADEON_MEM_CNTL, 0); @@ -486,8 +488,8 @@ RADEONPostInt10Check(ScrnInfoPtr pScrn, void *ptr) * the saved registers. */ CardTmp = INREG(RADEON_MEM_CNTL); - if (!CardTmp || - ((CardTmp & 1) && + if (!CardTmp || + ((CardTmp & 1) && (((CardTmp >> 8) & 0xff) != ((CardTmp >> 24) & 0xff)))) { /* Restore the saved registers */ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, @@ -924,7 +926,7 @@ static RADEONMonitorType RADEONDisplayDDCConnected(ScrnInfoPtr pScrn, RADEONDDCT info->DDCReg = DDCReg; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DDC Type: %d, Detected Type: %d\n", DDCType, MonType); return MonType; @@ -935,7 +937,7 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; - int bConnected = 0; + int bConnected = 0; /* the monitor either wasn't connected or it is a non-DDC CRT. * try to probe it @@ -961,7 +963,7 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) ulData = ulOrigCRTC_EXT_CNTL; ulData |= RADEON_CRTC_CRT_ON; OUTREG(RADEON_CRTC_EXT_CNTL, ulData); - + ulOrigDAC_EXT_CNTL = INREG(RADEON_DAC_EXT_CNTL); ulData = ulOrigDAC_EXT_CNTL; ulData &= ~RADEON_DAC_FORCE_DATA_MASK; @@ -988,7 +990,7 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) ulData = INREG(RADEON_DAC_CNTL); bConnected = (RADEON_DAC_CMP_OUTPUT & ulData)?1:0; - + ulData = ulOrigVCLK_ECP_CNTL; ulMask = 0xFFFFFFFFL; OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask); @@ -998,10 +1000,10 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) OUTREG(RADEON_CRTC_EXT_CNTL, ulOrigCRTC_EXT_CNTL); } else { /* TV DAC */ - /* This doesn't seem to work reliably (maybe worse on some OEM cards), - for now we always return false. If one wants to connected a - non-DDC monitor on the DVI port when CRT port is also connected, - he will need to explicitly tell the driver in the config file + /* This doesn't seem to work reliably (maybe worse on some OEM cards), + for now we always return false. If one wants to connected a + non-DDC monitor on the DVI port when CRT port is also connected, + he will need to explicitly tell the driver in the config file with Option MonitorLayout. */ bConnected = FALSE; @@ -1065,7 +1067,7 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) ulData = INREG(RADEON_GPIO_MONID); bConnected = (ulData & RADEON_GPIO_Y_0)?1:0; if (!bConnected) break; - + usleep(1000); } @@ -1091,7 +1093,7 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) unsigned long ulOrigDAC_CNTL2; unsigned long ulData; unsigned long ulMask; - + ulOrigPIXCLKSDATA = INPLL(pScrn, RADEON_PIXCLKS_CNTL); ulData = ulOrigPIXCLKSDATA; @@ -1107,10 +1109,10 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) OUTREG(RADEON_TV_MASTER_CNTL, ulData); ulOrigDAC_CNTL2 = INREG(RADEON_DAC_CNTL2); - ulData = ulOrigDAC_CNTL2; + ulData = ulOrigDAC_CNTL2; ulData &= ~RADEON_DAC2_DAC2_CLK_SEL; OUTREG(RADEON_DAC_CNTL2, ulData); - + ulOrigTV_DAC_CNTL = INREG(RADEON_TV_DAC_CNTL); ulData = 0x00880213; @@ -1135,12 +1137,12 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) usleep(1000); ulData = INREG(RADEON_TV_DAC_CNTL); - bConnected = (ulData & RADEON_TV_DAC_CMPOUT)?1:0; + bConnected = (ulData & RADEON_TV_DAC_CMPOUT)?1:0; ulData = ulOrigPIXCLKSDATA; ulMask = 0xFFFFFFFFL; OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask); - + OUTREG(RADEON_TV_MASTER_CNTL, ulOrigTV_MASTER_CNTL); OUTREG(RADEON_DAC_CNTL2, ulOrigDAC_CNTL2); OUTREG(RADEON_TV_DAC_CNTL, ulOrigTV_DAC_CNTL); @@ -1148,7 +1150,7 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac) } #endif } - + return(bConnected ? MT_CRT : MT_NONE); } @@ -1167,7 +1169,7 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn (info->VBIOS[(v) + 1] << 8) | \ (info->VBIOS[(v) + 2] << 16) | \ (info->VBIOS[(v) + 3] << 24)) - + pRADEONEnt->MonType1 = MT_NONE; pRADEONEnt->MonType2 = MT_NONE; pRADEONEnt->MonInfo1 = NULL; @@ -1181,16 +1183,16 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn */ if (xf86GetOptValBool(info->Options, OPTION_IGNORE_EDID, &ignore_edid)) { if (ignore_edid) - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, - "IgnoreEDID is specified, EDID data will be ignored\n"); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "IgnoreEDID is specified, EDID data will be ignored\n"); } - /* + /* * MonitorLayout option takes a string for two monitors connected in following format: * Option "MonitorLayout" "primary-port-display, secondary-port-display" - * primary and secondary port displays can have one of following: - * NONE, CRT, LVDS, TMDS - * With this option, driver will bring up monitors as specified, + * primary and secondary port displays can have one of following: + * NONE, CRT, LVDS, TMDS + * With this option, driver will bring up monitors as specified, * not using auto-detection routines to probe monitors. */ @@ -1209,7 +1211,7 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn * CRTC1 -> FP/TMDS -> DVI port -> TMDS panel --> Primary or * CRTC1 -> FP/LVDS -> Int. LCD -> LVDS panel --> Primary or * CRTC1 -> TV DAC -> DVI port -> CRT monitor --> Primary - * + * * Only VGA (can be DVI on some dual-DVI boards) connected: * CRTC1 -> CRT DAC -> VGA port -> CRT monitor --> Primary or * CRTC1 -> FP2/Ext. -> DVI port -> TMDS panel --> Primary (not supported) @@ -1219,19 +1221,19 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn * otherwise, VGA port will be treated as 1st port * * Here we always treat DVI port as primary if both ports are connected. - * When only one port is connected, it will be treated as - * primary regardless which port or what type of display is involved. + * When only one port is connected, it will be treated as + * primary regardless which port or what type of display is involved. */ if ((s = xf86GetOptValString(info->Options, OPTION_MONITOR_LAYOUT))) { char s1[5], s2[5]; int i = 0, second = 0; - + /* When using user specified monitor types, we will not do DDC detection - * + * */ do { - switch(*s) + switch(*s) { case ',': s1[i] = '\0'; @@ -1262,9 +1264,9 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn pRADEONEnt->MonType1 = MT_DFP; else if (strcmp(s1, "LVDS") == 0) pRADEONEnt->MonType1 = MT_LCD; - else - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Invalid Monitor type specified for 1st port \n"); + else + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Invalid Monitor type specified for 1st port \n"); if (strcmp(s2, "NONE") == 0) pRADEONEnt->MonType2 = MT_NONE; else if (strcmp(s2, "CRT") == 0) @@ -1273,20 +1275,20 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn pRADEONEnt->MonType2 = MT_DFP; else if (strcmp(s2, "LVDS") == 0) pRADEONEnt->MonType2 = MT_LCD; - else - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Invalid Monitor type specified for 2nd port \n"); + else + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Invalid Monitor type specified for 2nd port \n"); if (!ignore_edid) { if (pRADEONEnt->MonType1) /* assuming the first port using DDC_DVI */ - if(!RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1)) { + if(!RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1)) { RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo1); ddc_crt2_used = TRUE; - } + } if (pRADEONEnt->MonType2) { /* assuming the second port using DDC_VGA/DDC_CRT2 */ if(!RADEONDisplayDDCConnected(pScrn, DDC_VGA, &pRADEONEnt->MonInfo2)) if (!ddc_crt2_used) - RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo2); + RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo2); } } @@ -1296,8 +1298,8 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn pRADEONEnt->MonInfo1 = pRADEONEnt->MonInfo2; } else { pRADEONEnt->MonType1 = MT_CRT; - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "No valid monitor specified, force to CRT on 1st port\n"); + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "No valid monitor specified, force to CRT on 1st port\n"); } pRADEONEnt->MonType2 = MT_NONE; pRADEONEnt->MonInfo2 = NULL; @@ -1344,8 +1346,8 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn * If that's the case, we need also reverse the port arrangement. * BIOS settings are supposed report this correctly, work fine for all cards tested. * But there may be some exceptions, in that case, user can reverse their monitor - * definition in config file to correct the problem. - */ + * definition in config file to correct the problem. + */ if (info->VBIOS && (tmp = RADEON_BIOS16(info->FPBIOSstart + 0x50))) { for (i = 1; i < 4; i++) { unsigned int tmp0; @@ -1357,7 +1359,7 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn } if ((((tmp0 >> 8) & 0x0f) == DDC_DVI ) && ((tmp0 >> 4) & 0x1)) { pRADEONEnt->ReversedTMDS = TRUE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reversed TMDS detected\n"); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reversed TMDS detected\n"); } } } @@ -1365,10 +1367,10 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn /* Primary Head (DVI or Laptop Int. panel)*/ /* A ddc capable display connected on DVI port */ if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1))); - else if((pRADEONEnt->MonType1 = + else if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo1))) { ddc_crt2_used = TRUE; - } else if ((info->IsMobility) && + } else if ((info->IsMobility) && (info->VBIOS && (INREG(RADEON_BIOS_4_SCRATCH) & 4))) { /* non-DDC laptop panel connected on primary */ pRADEONEnt->MonType1 = MT_LCD; @@ -1379,17 +1381,17 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn } /* Secondary Head (mostly VGA, can be DVI on some OEM boards)*/ - if((pRADEONEnt->MonType2 = + if((pRADEONEnt->MonType2 = RADEONDisplayDDCConnected(pScrn, DDC_VGA, &pRADEONEnt->MonInfo2))); - else if(!ddc_crt2_used) - pRADEONEnt->MonType2 = + else if(!ddc_crt2_used) + pRADEONEnt->MonType2 = RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo2); if (!pRADEONEnt->MonType2) pRADEONEnt->MonType2 = RADEONCrtIsPhysicallyConnected(pScrn, !pRADEONEnt->ReversedDAC); if(pRADEONEnt->ReversedTMDS) { /* always keep internal TMDS as primary head */ - if (pRADEONEnt->MonType1 == MT_DFP || + if (pRADEONEnt->MonType1 == MT_DFP || pRADEONEnt->MonType2 == MT_DFP) { int tmp1 = pRADEONEnt->MonType1; xf86MonPtr MonInfo = pRADEONEnt->MonInfo1; @@ -1397,7 +1399,7 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn pRADEONEnt->MonInfo2 = MonInfo; pRADEONEnt->MonType1 = pRADEONEnt->MonType2; pRADEONEnt->MonType2 = tmp1; - if ((pRADEONEnt->MonType1 == MT_CRT) || + if ((pRADEONEnt->MonType1 == MT_CRT) || (pRADEONEnt->MonType2 == MT_CRT)) { pRADEONEnt->ReversedDAC ^= 1; } @@ -1420,12 +1422,12 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn } if(s) { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Displays Configured by MonitorLayout: \n\tMonitor1--Type %d, Monitor2--Type %d\n\n", + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Displays Configured by MonitorLayout: \n\tMonitor1--Type %d, Monitor2--Type %d\n\n", pRADEONEnt->MonType1, pRADEONEnt->MonType2); } else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Displays Detected: Monitor1--Type %d, Monitor2--Type %d\n\n", + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Displays Detected: Monitor1--Type %d, Monitor2--Type %d\n\n", pRADEONEnt->MonType1, pRADEONEnt->MonType2); } @@ -1446,12 +1448,12 @@ static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pIn xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor2 EDID data --------------------\n"); } } - + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\n"); info->OverlayOnCRTC2 = FALSE; - if (pRADEONEnt->MonType2 == MT_NONE) + if (pRADEONEnt->MonType2 == MT_NONE) pRADEONEnt->HasSecondary = FALSE; } @@ -1461,7 +1463,6 @@ static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) { RADEONInfoPtr info = RADEONPTR(pScrn); unsigned long tmp, i; - unsigned char *RADEONMMIO; if (!(info->VBIOS = xalloc(RADEON_VBIOS_SIZE))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, @@ -1503,29 +1504,29 @@ static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) { RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); - RADEONMMIO = info->MMIO; /* info->MergedFB = FALSE; */ info->MergeType = MT_NONE; - if(info->HasCRTC2) { - if(info->IsSecondary) { - if(!(info->DisplayType = pRADEONEnt->MonType2)) return FALSE; + if(info->HasCRTC2) { + if(info->IsSecondary) { + info->DisplayType = (RADEONMonitorType)pRADEONEnt->MonType2; + if(info->DisplayType == MT_NONE) return FALSE; } else { - info->DisplayType = pRADEONEnt->MonType1; + info->DisplayType = (RADEONMonitorType)pRADEONEnt->MonType1; if(!pRADEONEnt->HasSecondary) { if ((info->MergeType = pRADEONEnt->MonType2)) { /* info->MergedFB = TRUE; */ } - } + } } } else { - info->DisplayType = pRADEONEnt->MonType1; + info->DisplayType = (RADEONMonitorType)pRADEONEnt->MonType1; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Display == Type %d\n", - (info->IsSecondary ? "Secondary" : "Primary"), + (info->IsSecondary ? "Secondary" : "Primary"), info->DisplayType); if (info->MergedFB) @@ -1563,7 +1564,7 @@ static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) info->PanelYRes = RADEON_BIOS16(tmp+27); xf86DrvMsg(0, X_INFO, "Panel Size from BIOS: %dx%d\n", info->PanelXRes, info->PanelYRes); - + info->PanelPwrDly = RADEON_BIOS16(tmp+44); if (info->PanelPwrDly > 2000 || info->PanelPwrDly < 0) info->PanelPwrDly = 2000; @@ -1573,7 +1574,7 @@ static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) info->RefDivider = RADEON_BIOS16(tmp+46); info->PostDivider = RADEON_BIOS8(tmp+48); info->FeedbackDivider = RADEON_BIOS16(tmp+49); - if ((info->RefDivider != 0) && + if ((info->RefDivider != 0) && (info->FeedbackDivider > 3)) { info->UseBiosDividers = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, @@ -1608,15 +1609,15 @@ static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) DisplayModePtr tmp_mode = NULL; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No valid timing info from BIOS.\n"); - /* No timing information for the native mode, + /* No timing information for the native mode, use whatever specified in the Modeline. - If no Modeline specified, we'll just pick - the VESA mode at 60Hz refresh rate which + If no Modeline specified, we'll just pick + the VESA mode at 60Hz refresh rate which is likely to be the best for a flat panel. - */ + */ tmp_mode = pScrn->monitor->Modes; while(tmp_mode) { - if ((tmp_mode->HDisplay == info->PanelXRes) && + if ((tmp_mode->HDisplay == info->PanelXRes) && (tmp_mode->VDisplay == info->PanelYRes)) { float refresh = @@ -1673,27 +1674,25 @@ static Bool RADEONProbePLLParameters(ScrnInfoPtr pScrn) long start_secs, start_usecs, stop_secs, stop_usecs, total_usecs; int i; - tmp = INREG(RADEON_DEVICE_ID); - for(i=0; i<1000000; i++) if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) break; - + xf86getsecs(&start_secs, &start_usecs); - + for(i=0; i<1000000; i++) if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) != 0) break; - + for(i=0; i<1000000; i++) if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0) break; - + xf86getsecs(&stop_secs, &stop_usecs); - + total_usecs = abs(stop_usecs - start_usecs); hz = 1000000/total_usecs; - + hTotal = ((INREG(RADEON_CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8; vTotal = ((INREG(RADEON_CRTC_V_TOTAL_DISP) & 0x3ff) + 1); vclk = (float)(hTotal * (float)(vTotal * hz)); @@ -1717,7 +1716,7 @@ static Bool RADEONProbePLLParameters(ScrnInfoPtr pScrn) denom = 2*m; break; } - + OUTREG(RADEON_CLOCK_CNTL_INDEX, 1); ppll_div_sel = INREG8(RADEON_CLOCK_CNTL_DATA + 1) & 0x3; @@ -1726,7 +1725,7 @@ static Bool RADEONProbePLLParameters(ScrnInfoPtr pScrn) num *= n; denom *= m; - + switch ((INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel) >> 16) & 0x7) { case 1: denom *= 2; @@ -1741,7 +1740,7 @@ static Bool RADEONProbePLLParameters(ScrnInfoPtr pScrn) denom *= 3; break; case 6: - denom *= 6; + denom *= 6; break; case 7: denom *= 12; @@ -1800,8 +1799,8 @@ static void RADEONGetTMDSInfo(ScrnInfoPtr pScrn) return; } - /* revision 4 has some problem as it appears in RV280, - comment it off for new, use default instead */ + /* revision 4 has some problem as it appears in RV280, + comment it off for new, use default instead */ /* else if (RADEON_BIOS8(tmp) == 4) { int stride = 0; @@ -1834,16 +1833,17 @@ static Bool RADEONGetPLLParameters(ScrnInfoPtr pScrn) RADEONPLLPtr pll = &info->pll; CARD16 bios_header; CARD16 pll_info_block; + double min_dotclock; if (!info->VBIOS) { pll->min_pll_freq = 12500; pll->max_pll_freq = 35000; - + if (!RADEONProbePLLParameters(pScrn)) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, - "Video BIOS not detected, using default PLL parameters!\n"); + "Video BIOS not detected, using default PLL parameters!\n"); switch (info->Chipset) { case PCI_CHIP_R200_QL: @@ -1870,7 +1870,7 @@ static Bool RADEONGetPLLParameters(ScrnInfoPtr pScrn) default: pll->reference_freq = 2700; pll->reference_div = 67; - pll->xclk = 16615; + pll->xclk = 16615; break; } } @@ -1887,6 +1887,26 @@ static Bool RADEONGetPLLParameters(ScrnInfoPtr pScrn) pll->xclk = RADEON_BIOS16(pll_info_block + 0x08); } + /* (Some?) Radeon BIOSes seem too lie about their minimum dot + * clocks. Allow users to override the detected minimum dot clock + * value (e.g., and allow it to be suitable for TV sets). + */ + if (xf86GetOptValFreq(info->Options, OPTION_MIN_DOTCLOCK, + OPTUNITS_MHZ, &min_dotclock)) { + if (min_dotclock < 12 || min_dotclock*100 >= pll->max_pll_freq) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Illegal minimum dotclock specified %.2f MHz " + "(option ignored)\n", + min_dotclock); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Forced minimum dotclock to %.2f MHz " + "(instead of detected %.2f MHz)\n", + min_dotclock, ((double)pll->min_pll_freq/1000)); + pll->min_pll_freq = min_dotclock * 1000; + } + } + return TRUE; } @@ -2274,7 +2294,7 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn) "BIOS at 0x%08lx\n", info->BIOSAddr); } - /* Read registers used to determine options */ + /* Read registers used to determine options */ from = X_PROBED; if (info->FBDev) pScrn->videoRam = fbdevHWGetVidmem(pScrn) / 1024; @@ -2334,6 +2354,67 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn) #ifdef XF86DRI /* AGP/PCI */ + /* Proper autodetection of an AGP capable device requires examining + * PCI config registers to determine if the device implements extended + * PCI capabilities, and then walking the capability list as indicated + * in the PCI 2.2 and AGP 2.0 specifications, to determine if AGP + * capability is present. The procedure is outlined as follows: + * + * 1) Test bit 4 (CAP_LIST) of the PCI status register of the device + * to determine wether or not this device implements any extended + * capabilities. If this bit is zero, then the device is a PCI 2.1 + * or earlier device and is not AGP capable, and we can conclude it + * to be a PCI device. + * + * 2) If bit 4 of the status register is set, then the device implements + * extended capabilities. There is an 8 bit wide capabilities pointer + * register located at offset 0x34 in PCI config space which points to + * the first capability in a linked list of extended capabilities that + * this device implements. The lower two bits of this register are + * reserved and MBZ so must be masked out. + * + * 3) The extended capabilities list is formed by one or more extended + * capabilities structures which are aligned on DWORD boundaries. + * The first byte of the structure is the capability ID (CAP_ID) + * indicating what extended capability this structure refers to. The + * second byte of the structure is an offset from the beginning of + * PCI config space pointing to the next capability in the linked + * list (NEXT_PTR) or NULL (0x00) at the end of the list. The lower + * two bits of this pointer are reserved and MBZ. By examining the + * CAP_ID of each capability and walking through the list, we will + * either find the AGP_CAP_ID (0x02) indicating this device is an + * AGP device, or we'll reach the end of the list, indicating it is + * a PCI device. + * + * Mike A. Harris <mharris@redhat.com> + * + * References: + * - PCI Local Bus Specification Revision 2.2, Chapter 6 + * - AGP Interface Specification Revision 2.0, Section 6.1.5 + */ + + info->IsPCI = TRUE; + + if (pciReadLong(info->PciTag, PCI_CMD_STAT_REG) & RADEON_CAP_LIST) { + CARD32 cap_ptr, cap_id; + + cap_ptr = pciReadLong(info->PciTag, + RADEON_CAPABILITIES_PTR_PCI_CONFIG) + & RADEON_CAP_PTR_MASK; + + while(cap_ptr != RADEON_CAP_ID_NULL) { + cap_id = pciReadLong(info->PciTag, cap_ptr); + if ((cap_id & 0xff)== RADEON_CAP_ID_AGP) { + info->IsPCI = FALSE; + break; + } + cap_ptr = (cap_id >> 8) & RADEON_CAP_PTR_MASK; + } + } + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s card detected\n", + (info->IsPCI) ? "PCI" : "AGP"); + if ((s = xf86GetOptValString(info->Options, OPTION_BUS_TYPE))) { if (strcmp(s, "AGP") == 0) { info->IsPCI = FALSE; @@ -2343,30 +2424,12 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn) xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI mode\n"); } else if (strcmp(s, "PCIE") == 0) { info->IsPCI = TRUE; - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "PCI Express not supported yet, use PCI mode\n"); - } else { - s = NULL; - xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Invalid BusType option, use detected type\n"); - } - } - - if (!s) { - CARD32 tmp = pciReadLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG); - /* There are signatures in BIOS and PCI-SSID for a PCI card, but they are not very reliable. - Following detection method works for all cards tested so far. - Note, checking AGP_ENABLE bit after drmAgpEnable call can also give the correct result. - However, calling drmAgpEnable on a PCI card can cause some strange lockup when the server - restarts next time. - */ - pciWriteLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG, tmp | RADEON_AGP_ENABLE); - if (pciReadLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG) & RADEON_AGP_ENABLE) { - info->IsPCI = FALSE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "AGP card detected\n"); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "PCI Express not supported yet, using PCI mode\n"); } else { - info->IsPCI = TRUE; - xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PCI card detected\n"); + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, + "Invalid BusType option, using detected type\n"); } - pciWriteLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG, tmp); } #endif @@ -2530,7 +2593,7 @@ static void RADEONSortModes(DisplayModePtr *new, DisplayModePtr *first, p = *last; while (p) { - if ((((*new)->HDisplay < p->HDisplay) && + if ((((*new)->HDisplay < p->HDisplay) && ((*new)->VDisplay < p->VDisplay)) || (((*new)->HDisplay == p->HDisplay) && ((*new)->VDisplay == p->VDisplay) && @@ -2549,7 +2612,7 @@ static void RADEONSortModes(DisplayModePtr *new, DisplayModePtr *first, p->prev = *new; *first = *new; break; - } + } p = p->prev; } @@ -2575,7 +2638,7 @@ static void RADEONSetPitch (ScrnInfoPtr pScrn) pScrn->displayWidth = dummy; } -/* When no mode provided in config file, this will add all modes supported in +/* When no mode provided in config file, this will add all modes supported in * DDC date the pScrn->modes list */ static DisplayModePtr RADEONDDCModes(ScrnInfoPtr pScrn) @@ -2685,7 +2748,7 @@ static DisplayModePtr RADEONDDCModes(ScrnInfoPtr pScrn) strcpy(new->name, p->name); new->status = MODE_OK; new->type = M_T_DEFAULT; - + count++; xf86DrvMsg(pScrn->scrnIndex, X_INFO, @@ -2817,7 +2880,7 @@ static int RADEONValidateDDCModes(ScrnInfoPtr pScrn1, char **ppModeName, } } - /* + /* * Add remaining DDC modes if they're smaller than the user * specified modes */ @@ -2975,7 +3038,7 @@ static int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName) new->HSyncEnd = new->HSyncStart + info->HSyncWidth; new->VTotal = info->PanelYRes + info->VBlank; new->VSyncStart = info->PanelYRes + info->VOverPlus; - new->VSyncEnd = new->VSyncStart + info->VSyncWidth; + new->VSyncEnd = new->VSyncStart + info->VSyncWidth; new->Clock = info->DotClock; new->Flags |= RADEON_USE_RMX; @@ -3026,7 +3089,7 @@ static int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName) new->HSyncEnd = new->HSyncStart + info->HSyncWidth; new->VTotal = info->PanelYRes + info->VBlank; new->VSyncStart = info->PanelYRes + info->VOverPlus; - new->VSyncEnd = new->VSyncStart + info->VSyncWidth; + new->VSyncEnd = new->VSyncStart + info->VSyncWidth; new->Clock = info->DotClock; new->Flags |= RADEON_USE_RMX; @@ -3366,7 +3429,7 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) info->ddc_mode = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Validating modes on %s head ---------\n", + "Validating modes on %s head ---------\n", info->IsSecondary ? "Secondary" : "Primary"); if (info->IsSecondary) @@ -3511,14 +3574,14 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) * add the flat panel modes */ if (info->DisplayType != MT_CRT) { - + /* some panels have DDC, but don't have internal scaler. * in this case, we need to validate additional modes * by using on-chip RMX. */ int user_modes_asked = 0, user_modes_found = 0, i; DisplayModePtr tmp_mode = pScrn->modes; - while (pScrn->display->modes[user_modes_asked]) user_modes_asked++; + while (pScrn->display->modes[user_modes_asked]) user_modes_asked++; if (tmp_mode) { for (i = 0; i < modesFound; i++) { if (tmp_mode->type & M_T_USERDEF) user_modes_found++; @@ -3526,8 +3589,8 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) } } - if ((modesFound <= 1) || (user_modes_found < user_modes_asked)) { - /* when panel size is not valid, try to validate + if ((modesFound <= 1) || (user_modes_found < user_modes_asked)) { + /* when panel size is not valid, try to validate * mode using xf86ValidateModes routine * This can happen when DDC is disabled. */ @@ -3549,7 +3612,7 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10) LOOKUP_BEST_REFRESH); else if (!info->IsSecondary) modesFound = RADEONValidateFPModes(pScrn, pScrn->display->modes); - } + } } /* Setup the screen's clockRanges for the VidMode extension */ @@ -3786,7 +3849,7 @@ static Bool RADEONPreInitDRI(ScrnInfoPtr pScrn) xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Enabling AGP Fast Write\n"); } else { - xf86DrvMsg(pScrn->scrnIndex, X_INFO, + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "AGP Fast Write disabled by default\n"); } } @@ -3867,7 +3930,7 @@ static Bool RADEONPreInitDRI(ScrnInfoPtr pScrn) * for dedicated 3d rendering boxes */ info->noBackBuffer = xf86ReturnOptValBool(info->Options, - OPTION_NO_BACKBUFFER, + OPTION_NO_BACKBUFFER, FALSE); if (info->noBackBuffer) { @@ -3910,7 +3973,6 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) void *int10_save = NULL; const char *s; - RADEONTRACE(("RADEONPreInit\n")); if (pScrn->numEntities != 1) return FALSE; @@ -3944,7 +4006,7 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) "MMIO registers at 0x%08lx\n", info->MMIOAddr); if(!RADEONMapMMIO(pScrn)) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Memory map the MMIO region failed\n"); goto fail1; } @@ -3958,7 +4020,7 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) * going to run it again - so make sure to "fix up" the card * so that (1) we can read the BIOS ROM and (2) the BIOS will * get the memory config right. - */ + */ RADEONPreInt10Save(pScrn, &int10_save); #endif @@ -4097,6 +4159,9 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) if (!info->IsSecondary) RADEONGetMergedFBOptions(pScrn); + if (info->DisplayType == MT_DFP) + RADEONGetTMDSInfo(pScrn); + if (!RADEONGetPLLParameters(pScrn)) goto fail; if (!RADEONPreInitGamma(pScrn)) goto fail; @@ -4121,7 +4186,7 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags) if (pInt10) xf86FreeInt10(pInt10); - if(info->MMIO) RADEONUnmapMMIO(pScrn); + if(info->MMIO) RADEONUnmapMMIO(pScrn); info->MMIO = NULL; xf86DrvMsg(pScrn->scrnIndex, X_NOTICE, @@ -4149,7 +4214,7 @@ fail: vgaHWFreeHWRec(pScrn); fail2: - if(info->MMIO) RADEONUnmapMMIO(pScrn); + if(info->MMIO) RADEONUnmapMMIO(pScrn); info->MMIO = NULL; fail1: RADEONFreeRec(pScrn); @@ -4256,7 +4321,7 @@ static void RADEONLoadPalette(ScrnInfoPtr pScrn, int numColors, g = colors[idx].green; b = colors[idx / 2].blue; OUTPAL(idx * 4, r, g, b); - + /* AH - Added to write extra green data - How come * this isn't needed on R128? We didn't load the * extra green data in the other routine. @@ -4519,7 +4584,7 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) info->textureSize = info->FbMapSize - 4 * bufferSize - depthSize; } if (info->textureSize < (int)info->FbMapSize / 2) { - info->textureSize = info->FbMapSize - 3 * bufferSize - depthSize; + info->textureSize = info->FbMapSize - 3 * bufferSize - depthSize; } /* If there's still no space for textures, try without pixmap cache */ if (info->textureSize < 0) { @@ -4993,11 +5058,11 @@ static void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) OUTREG(RADEON_FP_VERT_STRETCH, restore->fp_vert_stretch); OUTREG(RADEON_FP_GEN_CNTL, restore->fp_gen_cntl); - /* old AIW Radeon has some BIOS initialization problem + /* old AIW Radeon has some BIOS initialization problem * with display buffer underflow, only occurs to DFP - */ + */ if (!info->HasCRTC2) - OUTREG(RADEON_GRPH_BUFFER_CNTL, + OUTREG(RADEON_GRPH_BUFFER_CNTL, INREG(RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000); if (info->DisplayType != MT_DFP) { @@ -5010,7 +5075,7 @@ static void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore) */ if (!(restore->lvds_gen_cntl & RADEON_LVDS_ON)) { OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); - } + } } tmp = INREG(RADEON_LVDS_GEN_CNTL); @@ -5097,10 +5162,10 @@ static void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn, unsigned char *RADEONMMIO = info->MMIO; if (info->IsMobility) { - /* A temporal workaround for the occational blanking on certain laptop panels. - This appears to related to the PLL divider registers (fail to lock?). - It occurs even when all dividers are the same with their old settings. - In this case we really don't need to fiddle with PLL registers. + /* A temporal workaround for the occational blanking on certain laptop panels. + This appears to related to the PLL divider registers (fail to lock?). + It occurs even when all dividers are the same with their old settings. + In this case we really don't need to fiddle with PLL registers. By doing this we can avoid the blanking problem with some panels. */ if ((restore->ppll_ref_div == (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) && @@ -5139,7 +5204,7 @@ static void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn, } else { /* R300 uses ref_div_acc field as real ref divider */ OUTPLLP(pScrn, RADEON_PPLL_REF_DIV, - (restore->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), + (restore->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), ~R300_PPLL_REF_DIV_ACC_MASK); } } else { @@ -5524,12 +5589,12 @@ static void RADEONSaveMode(ScrnInfoPtr pScrn, RADEONSavePtr save) RADEONInfoPtr info = RADEONPTR(pScrn); RADEONTRACE(("RADEONSaveMode(%p)\n", save)); + RADEONSaveCommonRegisters(pScrn, save); if (info->IsSecondary) { RADEONSaveCrtc2Registers(pScrn, save); RADEONSavePLL2Registers(pScrn, save); } else { RADEONSavePLLRegisters(pScrn, save); - RADEONSaveCommonRegisters(pScrn, save); RADEONSaveCrtcRegisters(pScrn, save); RADEONSaveFPRegisters(pScrn, save); @@ -5679,6 +5744,7 @@ static void RADEONInitCommonRegisters(RADEONSavePtr save, RADEONInfoPtr info) save->bus_cntl |= RADEON_BUS_RD_DISCARD_EN; } + /* Calculate display buffer watermark to prevent buffer underflow */ static void RADEONInitDispBandwidth(ScrnInfoPtr pScrn) { @@ -6008,24 +6074,22 @@ static Bool RADEONInitCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, int hsync_wid; int hsync_fudge; int vsync_wid; - int bytpp; int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; int hsync_fudge_fp[] = { 0x02, 0x02, 0x00, 0x00, 0x05, 0x05 }; switch (info->CurrentLayout.pixel_code) { - case 4: format = 1; bytpp = 0; break; - case 8: format = 2; bytpp = 1; break; - case 15: format = 3; bytpp = 2; break; /* 555 */ - case 16: format = 4; bytpp = 2; break; /* 565 */ - case 24: format = 5; bytpp = 3; break; /* RGB */ - case 32: format = 6; bytpp = 4; break; /* xRGB */ + case 4: format = 1; break; + case 8: format = 2; break; + case 15: format = 3; break; /* 555 */ + case 16: format = 4; break; /* 565 */ + case 24: format = 5; break; /* RGB */ + case 32: format = 6; break; /* xRGB */ default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unsupported pixel depth (%d)\n", info->CurrentLayout.bitsPerPixel); return FALSE; } - RADEONTRACE(("Format = %d (%d bytes per pixel)\n", format, bytpp)); if ((info->DisplayType == MT_DFP) || (info->DisplayType == MT_LCD)) { @@ -6132,18 +6196,31 @@ static Bool RADEONInitCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save, else save->crtc_more_cntl = info->SavedReg.crtc_more_cntl; + /* Some versions of BIOS setup CRTC_MORE_CNTL for a DFP, if we + have a CRT here, it should be cleared to avoild a blank screen. + */ + if (info->DisplayType == MT_CRT) + save->crtc_more_cntl = (info->SavedReg.crtc_more_cntl & + ~(RADEON_CRTC_H_CUTOFF_ACTIVE_EN | + RADEON_CRTC_V_CUTOFF_ACTIVE_EN)); + else + save->crtc_more_cntl = info->SavedReg.crtc_more_cntl; + save->surface_cntl = 0; save->disp_merge_cntl = info->SavedReg.disp_merge_cntl; save->disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN; #if X_BYTE_ORDER == X_BIG_ENDIAN + /* Alhought we current onlu use aperture 0, also setting aperture 1 should not harm -ReneR */ switch (pScrn->bitsPerPixel) { case 16: save->surface_cntl |= RADEON_NONSURF_AP0_SWP_16BPP; + save->surface_cntl |= RADEON_NONSURF_AP1_SWP_16BPP; break; case 32: save->surface_cntl |= RADEON_NONSURF_AP0_SWP_32BPP; + save->surface_cntl |= RADEON_NONSURF_AP1_SWP_32BPP; break; } #endif @@ -6166,23 +6243,21 @@ static Bool RADEONInitCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save, int hsync_wid; int hsync_fudge; int vsync_wid; - int bytpp; int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; switch (info->CurrentLayout.pixel_code) { - case 4: format = 1; bytpp = 0; break; - case 8: format = 2; bytpp = 1; break; - case 15: format = 3; bytpp = 2; break; /* 555 */ - case 16: format = 4; bytpp = 2; break; /* 565 */ - case 24: format = 5; bytpp = 3; break; /* RGB */ - case 32: format = 6; bytpp = 4; break; /* xRGB */ + case 4: format = 1; break; + case 8: format = 2; break; + case 15: format = 3; break; /* 555 */ + case 16: format = 4; break; /* 565 */ + case 24: format = 5; break; /* RGB */ + case 32: format = 6; break; /* xRGB */ default: xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unsupported pixel depth (%d)\n", info->CurrentLayout.bitsPerPixel); return FALSE; } - RADEONTRACE(("Format = %d (%d bytes per pixel)\n", format, bytpp)); hsync_fudge = hsync_fudge_default[format-1]; @@ -6212,10 +6287,10 @@ static Bool RADEONInitCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save, save->disp_output_cntl &= ~(RADEON_DISP_DAC_SOURCE_MASK | RADEON_DISP_DAC2_SOURCE_MASK); if (pRADEONEnt->MonType1 != MT_CRT) { - save->disp_output_cntl |= (RADEON_DISP_DAC_SOURCE_CRTC2 | + save->disp_output_cntl |= (RADEON_DISP_DAC_SOURCE_CRTC2 | RADEON_DISP_DAC2_SOURCE_CRTC2); } else { - if (pRADEONEnt->ReversedDAC) { + if (pRADEONEnt->ReversedDAC) { save->disp_output_cntl |= RADEON_DISP_DAC2_SOURCE_CRTC2; } else { save->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2; @@ -6233,7 +6308,7 @@ static Bool RADEONInitCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save, save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; save->dac2_cntl |= RADEON_DAC2_DAC_CLK_SEL; } else { - if (pRADEONEnt->ReversedDAC) { + if (pRADEONEnt->ReversedDAC) { save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL; save->dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL; } else { @@ -6319,7 +6394,7 @@ static Bool RADEONInitCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save, save->fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2; } - if (pScrn->rgbBits == 8) + if (pScrn->rgbBits == 8) save->fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format */ else save->fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format */ @@ -6352,8 +6427,8 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig, int yres = mode->VDisplay; float Hratio, Vratio; - /* If the FP registers have been initialized before for a panel, - * but the primary port is a CRT, we need to reinitialize + /* If the FP registers have been initialized before for a panel, + * but the primary port is a CRT, we need to reinitialize * FP registers in order for CRT to work properly */ @@ -6391,7 +6466,7 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig, if (Hratio == 1.0 || !(mode->Flags & RADEON_USE_RMX)) { save->fp_horz_stretch = orig->fp_horz_stretch; save->fp_horz_stretch &= ~(RADEON_HORZ_STRETCH_BLEND | - RADEON_HORZ_STRETCH_ENABLE); + RADEON_HORZ_STRETCH_ENABLE); save->fp_horz_stretch &= ~(RADEON_HORZ_AUTO_RATIO | RADEON_HORZ_PANEL_SIZE); save->fp_horz_stretch |= ((xres/8-1)<<16); @@ -6446,7 +6521,7 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig, save->fp_gen_cntl |= (RADEON_FP_CRTC_DONT_SHADOW_VPAR | RADEON_FP_CRTC_DONT_SHADOW_HEND ); - if (pScrn->rgbBits == 8) + if (pScrn->rgbBits == 8) save->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */ else save->fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */ @@ -6523,7 +6598,7 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig, else /* weird, RV chips got this bit reversed? */ save->tmds_transmitter_cntl |= (RADEON_TMDS_TRANSMITTER_PLLEN); - save->fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); + save->fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN); } } @@ -6716,6 +6791,7 @@ static Bool RADEONInit(ScrnInfoPtr pScrn, DisplayModePtr mode, info->Flags = mode->Flags; + RADEONInitCommonRegisters(save, info); if (info->IsSecondary) { if (!RADEONInitCrtc2Registers(pScrn, save, mode, info)) return FALSE; @@ -6738,7 +6814,6 @@ static Bool RADEONInit(ScrnInfoPtr pScrn, DisplayModePtr mode, dot_clock = (((RADEONMergedDisplayModePtr)mode->Private)->CRT2)->Clock / 1000.0; RADEONInitPLL2Registers(save, &info->pll, dot_clock); } else { - RADEONInitCommonRegisters(save, info); if (!RADEONInitCrtcRegisters(pScrn, save, mode, info)) return FALSE; dot_clock = mode->Clock/1000.0; @@ -6877,8 +6952,8 @@ Bool RADEONHandleMessage(int scrnIndex, const char* msgtype, #endif /* Used to disallow modes that are not supported by the hardware */ -int RADEONValidMode(int scrnIndex, DisplayModePtr mode, - Bool verbose, int flag) +ModeStatus RADEONValidMode(int scrnIndex, DisplayModePtr mode, + Bool verbose, int flag) { /* There are problems with double scan mode at high clocks * They're likely related PLL and display buffer settings. @@ -6922,7 +6997,7 @@ void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int clone) #ifdef XF86DRI if (info->directRenderingEnabled) { - pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); + pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen); if (clone || info->IsSecondary) { pSAREAPriv->crtc2_base = Base; @@ -6987,7 +7062,7 @@ Bool RADEONEnterVT(int scrnIndex, int flags) RADEONDRIResume(pScrn->pScreen); } #endif - /* this will get XVideo going again, but only if XVideo was initialised + /* this will get XVideo going again, but only if XVideo was initialised during server startup (hence the info->adaptor if). */ if (info->adaptor) RADEONResetVideo(pScrn); @@ -7127,12 +7202,79 @@ void RADEONFreeScreen(int scrnIndex, int flags) RADEONFreeRec(pScrn); } +/* + * Powering done DAC, needed for DPMS problem with ViewSonic P817 (or its variant). + * + * Note for current DAC mapping when calling this function: + * For most of cards: + * single CRT: Driver doesn't change the existing CRTC->DAC mapping, + * CRTC1 could be driving either DAC or both DACs. + * CRT+CRT: CRTC1->TV DAC, CRTC2->Primary DAC + * DFP/LCD+CRT: CRTC2->TV DAC, CRTC2->Primary DAC. + * Some boards have two DACs reversed or don't even have a primary DAC, + * this is reflected in pRADEONEnt->ReversedDAC. And radeon 7200 doesn't + * have a second DAC. + * It's kind of messy, we'll need to redo DAC mapping part some day. + */ +static void RADEONDacPowerSet(ScrnInfoPtr pScrn, Bool IsOn, Bool IsPrimaryDAC) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + unsigned char *RADEONMMIO = info->MMIO; + + if (IsPrimaryDAC) { + CARD32 dac_cntl; + CARD32 dac_macro_cntl = 0; + dac_cntl = INREG(RADEON_DAC_CNTL); + if ((!info->IsMobility) || (info->ChipFamily == CHIP_FAMILY_RV350)) + dac_macro_cntl = INREG(RADEON_DAC_MACRO_CNTL); + if (IsOn) { + dac_cntl &= ~RADEON_DAC_PDWN; + dac_macro_cntl &= ~(RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + } else { + dac_cntl |= RADEON_DAC_PDWN; + dac_macro_cntl |= (RADEON_DAC_PDWN_R | + RADEON_DAC_PDWN_G | + RADEON_DAC_PDWN_B); + } + OUTREG(RADEON_DAC_CNTL, dac_cntl); + if ((!info->IsMobility) || (info->ChipFamily == CHIP_FAMILY_RV350)) + OUTREG(RADEON_DAC_MACRO_CNTL, dac_macro_cntl); + } else { + if (info->ChipFamily != CHIP_FAMILY_R200) { + CARD32 tv_dac_cntl = INREG(RADEON_TV_DAC_CNTL); + if (IsOn) { + tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + } else { + tv_dac_cntl |= (RADEON_TV_DAC_RDACPD | + RADEON_TV_DAC_GDACPD | + RADEON_TV_DAC_BDACPD | + RADEON_TV_DAC_BGSLEEP); + } + OUTREG(RADEON_TV_DAC_CNTL, tv_dac_cntl); + } else { + CARD32 fp2_gen_cntl = INREG(RADEON_FP2_GEN_CNTL); + if (IsOn) { + fp2_gen_cntl |= RADEON_FP2_DV0_EN; + } else { + fp2_gen_cntl &= ~RADEON_FP2_DV0_EN; + } + OUTREG(RADEON_FP2_GEN_CNTL, fp2_gen_cntl); + } + } +} + /* Sets VESA Display Power Management Signaling (DPMS) Mode */ static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, int flags) { RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); unsigned char *RADEONMMIO = info->MMIO; #ifdef XF86DRI @@ -7151,8 +7293,6 @@ static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, RADEON_CRTC2_VSYNC_DIS | RADEON_CRTC2_HSYNC_DIS); - /* TODO: additional handling for LCD ? */ - switch (PowerManagementMode) { case DPMSModeOn: /* Screen: On; HSync: On, VSync: On */ @@ -7219,6 +7359,8 @@ static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, if (info->ChipFamily >= CHIP_FAMILY_R200) { OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_DV0_EN, ~RADEON_FP2_DV0_EN); } + } else if (info->DisplayType == MT_CRT) { + RADEONDacPowerSet(pScrn, TRUE, !pRADEONEnt->ReversedDAC); } } else { if ((info->MergedFB) && (info->MergeType == MT_DFP)) { @@ -7229,13 +7371,21 @@ static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, } } if (info->DisplayType == MT_DFP) { - OUTREGP (RADEON_FP_GEN_CNTL, (RADEON_FP_FPON | RADEON_FP_TMDS_EN), + OUTREGP (RADEON_FP_GEN_CNTL, (RADEON_FP_FPON | RADEON_FP_TMDS_EN), ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN)); } else if (info->DisplayType == MT_LCD) { OUTREGP (RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON, ~RADEON_LVDS_BLON); usleep (info->PanelPwrDly * 1000); OUTREGP (RADEON_LVDS_GEN_CNTL, RADEON_LVDS_ON, ~RADEON_LVDS_ON); + } else if (info->DisplayType == MT_CRT) { + if ((pRADEONEnt->HasSecondary) || info->MergedFB) { + RADEONDacPowerSet(pScrn, TRUE, pRADEONEnt->ReversedDAC); + } else { + RADEONDacPowerSet(pScrn, TRUE, TRUE); + if (info->HasCRTC2) + RADEONDacPowerSet(pScrn, TRUE, FALSE); + } } } } else if ((PowerManagementMode == DPMSModeOff) || @@ -7248,6 +7398,8 @@ static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, if (info->ChipFamily >= CHIP_FAMILY_R200) { OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_DV0_EN); } + } else if (info->DisplayType == MT_CRT) { + RADEONDacPowerSet(pScrn, FALSE, !pRADEONEnt->ReversedDAC); } } else { if ((info->MergedFB) && (info->MergeType == MT_DFP)) { @@ -7269,12 +7421,23 @@ static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn, OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb); } - OUTREGP (RADEON_LVDS_GEN_CNTL, 0, + OUTREGP (RADEON_LVDS_GEN_CNTL, 0, ~(RADEON_LVDS_BLON | RADEON_LVDS_ON)); if (info->IsMobility || info->IsIGP) { OUTPLL(RADEON_PIXCLKS_CNTL, tmpPixclksCntl); } + } else if (info->DisplayType == MT_CRT) { + if ((pRADEONEnt->HasSecondary) || info->MergedFB) { + RADEONDacPowerSet(pScrn, FALSE, pRADEONEnt->ReversedDAC); + } else { + /* single CRT, turning both DACs off, we don't really know + * which DAC is actually connected. + */ + RADEONDacPowerSet(pScrn, FALSE, TRUE); + if (info->HasCRTC2) /* don't apply this to old radeon (singel CRTC) card */ + RADEONDacPowerSet(pScrn, FALSE, FALSE); + } } } } |