📄 radeon_driver.c
字号:
static RADEONMonitorTypeRADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac){ RADEONInfoPtr info = RADEONPTR(pScrn); unsigned char *RADEONMMIO = info->MMIO; int bConnected = 0; /* the monitor either wasn't connected or it is a non-DDC CRT. * try to probe it */ if(IsCrtDac) { unsigned long ulOrigVCLK_ECP_CNTL; unsigned long ulOrigDAC_CNTL; unsigned long ulOrigDAC_EXT_CNTL; unsigned long ulOrigCRTC_EXT_CNTL; unsigned long ulData; unsigned long ulMask; ulOrigVCLK_ECP_CNTL = INPLL(pScrn, RADEON_VCLK_ECP_CNTL); ulData = ulOrigVCLK_ECP_CNTL; ulData &= ~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb); ulMask = ~(RADEON_PIXCLK_ALWAYS_ONb |RADEON_PIXCLK_DAC_ALWAYS_ONb); OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask); ulOrigCRTC_EXT_CNTL = INREG(RADEON_CRTC_EXT_CNTL); 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; ulData |= (RADEON_DAC_FORCE_BLANK_OFF_EN |RADEON_DAC_FORCE_DATA_EN |RADEON_DAC_FORCE_DATA_SEL_MASK); if ((info->ChipFamily == CHIP_FAMILY_RV250) || (info->ChipFamily == CHIP_FAMILY_RV280)) ulData |= (0x01b6 << RADEON_DAC_FORCE_DATA_SHIFT); else ulData |= (0x01ac << RADEON_DAC_FORCE_DATA_SHIFT); OUTREG(RADEON_DAC_EXT_CNTL, ulData); ulOrigDAC_CNTL = INREG(RADEON_DAC_CNTL); ulData = ulOrigDAC_CNTL; ulData |= RADEON_DAC_CMP_EN; ulData &= ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN); ulData |= 0x2; OUTREG(RADEON_DAC_CNTL, ulData); usleep(1000); 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); OUTREG(RADEON_DAC_CNTL, ulOrigDAC_CNTL ); OUTREG(RADEON_DAC_EXT_CNTL, ulOrigDAC_EXT_CNTL ); 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 with Option MonitorLayout. */ bConnected = FALSE;#if 0 if (info->ChipFamily == CHIP_FAMILY_R200) { unsigned long ulOrigGPIO_MONID; unsigned long ulOrigFP2_GEN_CNTL; unsigned long ulOrigDISP_OUTPUT_CNTL; unsigned long ulOrigCRTC2_GEN_CNTL; unsigned long ulOrigDISP_LIN_TRANS_GRPH_A; unsigned long ulOrigDISP_LIN_TRANS_GRPH_B; unsigned long ulOrigDISP_LIN_TRANS_GRPH_C; unsigned long ulOrigDISP_LIN_TRANS_GRPH_D; unsigned long ulOrigDISP_LIN_TRANS_GRPH_E; unsigned long ulOrigDISP_LIN_TRANS_GRPH_F; unsigned long ulOrigCRTC2_H_TOTAL_DISP; unsigned long ulOrigCRTC2_V_TOTAL_DISP; unsigned long ulOrigCRTC2_H_SYNC_STRT_WID; unsigned long ulOrigCRTC2_V_SYNC_STRT_WID; unsigned long ulData, i; ulOrigGPIO_MONID = INREG(RADEON_GPIO_MONID); ulOrigFP2_GEN_CNTL = INREG(RADEON_FP2_GEN_CNTL); ulOrigDISP_OUTPUT_CNTL = INREG(RADEON_DISP_OUTPUT_CNTL); ulOrigCRTC2_GEN_CNTL = INREG(RADEON_CRTC2_GEN_CNTL); ulOrigDISP_LIN_TRANS_GRPH_A = INREG(RADEON_DISP_LIN_TRANS_GRPH_A); ulOrigDISP_LIN_TRANS_GRPH_B = INREG(RADEON_DISP_LIN_TRANS_GRPH_B); ulOrigDISP_LIN_TRANS_GRPH_C = INREG(RADEON_DISP_LIN_TRANS_GRPH_C); ulOrigDISP_LIN_TRANS_GRPH_D = INREG(RADEON_DISP_LIN_TRANS_GRPH_D); ulOrigDISP_LIN_TRANS_GRPH_E = INREG(RADEON_DISP_LIN_TRANS_GRPH_E); ulOrigDISP_LIN_TRANS_GRPH_F = INREG(RADEON_DISP_LIN_TRANS_GRPH_F); ulOrigCRTC2_H_TOTAL_DISP = INREG(RADEON_CRTC2_H_TOTAL_DISP); ulOrigCRTC2_V_TOTAL_DISP = INREG(RADEON_CRTC2_V_TOTAL_DISP); ulOrigCRTC2_H_SYNC_STRT_WID = INREG(RADEON_CRTC2_H_SYNC_STRT_WID); ulOrigCRTC2_V_SYNC_STRT_WID = INREG(RADEON_CRTC2_V_SYNC_STRT_WID); ulData = INREG(RADEON_GPIO_MONID); ulData &= ~RADEON_GPIO_A_0; OUTREG(RADEON_GPIO_MONID, ulData); OUTREG(RADEON_FP2_GEN_CNTL, 0x0a000c0c); OUTREG(RADEON_DISP_OUTPUT_CNTL, 0x00000012); OUTREG(RADEON_CRTC2_GEN_CNTL, 0x06000000); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0); OUTREG(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008); OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800); OUTREG(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001); OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080); for (i = 0; i < 200; i++) { ulData = INREG(RADEON_GPIO_MONID); bConnected = (ulData & RADEON_GPIO_Y_0)?1:0; if (!bConnected) break; usleep(1000); } OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, ulOrigDISP_LIN_TRANS_GRPH_A); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, ulOrigDISP_LIN_TRANS_GRPH_B); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, ulOrigDISP_LIN_TRANS_GRPH_C); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, ulOrigDISP_LIN_TRANS_GRPH_D); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, ulOrigDISP_LIN_TRANS_GRPH_E); OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, ulOrigDISP_LIN_TRANS_GRPH_F); OUTREG(RADEON_CRTC2_H_TOTAL_DISP, ulOrigCRTC2_H_TOTAL_DISP); OUTREG(RADEON_CRTC2_V_TOTAL_DISP, ulOrigCRTC2_V_TOTAL_DISP); OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, ulOrigCRTC2_H_SYNC_STRT_WID); OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, ulOrigCRTC2_V_SYNC_STRT_WID); OUTREG(RADEON_CRTC2_GEN_CNTL, ulOrigCRTC2_GEN_CNTL); OUTREG(RADEON_DISP_OUTPUT_CNTL, ulOrigDISP_OUTPUT_CNTL); OUTREG(RADEON_FP2_GEN_CNTL, ulOrigFP2_GEN_CNTL); OUTREG(RADEON_GPIO_MONID, ulOrigGPIO_MONID); } else { unsigned long ulOrigPIXCLKSDATA; unsigned long ulOrigTV_MASTER_CNTL; unsigned long ulOrigTV_DAC_CNTL; unsigned long ulOrigTV_PRE_DAC_MUX_CNTL; unsigned long ulOrigDAC_CNTL2; unsigned long ulData; unsigned long ulMask; ulOrigPIXCLKSDATA = INPLL(pScrn, RADEON_PIXCLKS_CNTL); ulData = ulOrigPIXCLKSDATA; ulData &= ~(RADEON_PIX2CLK_ALWAYS_ONb | RADEON_PIX2CLK_DAC_ALWAYS_ONb); ulMask = ~(RADEON_PIX2CLK_ALWAYS_ONb | RADEON_PIX2CLK_DAC_ALWAYS_ONb); OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask); ulOrigTV_MASTER_CNTL = INREG(RADEON_TV_MASTER_CNTL); ulData = ulOrigTV_MASTER_CNTL; ulData &= ~RADEON_TVCLK_ALWAYS_ONb; OUTREG(RADEON_TV_MASTER_CNTL, ulData); ulOrigDAC_CNTL2 = INREG(RADEON_DAC_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; OUTREG(RADEON_TV_DAC_CNTL, ulData); ulOrigTV_PRE_DAC_MUX_CNTL = INREG(RADEON_TV_PRE_DAC_MUX_CNTL); ulData = (RADEON_Y_RED_EN | RADEON_C_GRN_EN | RADEON_CMP_BLU_EN | RADEON_RED_MX_FORCE_DAC_DATA | RADEON_GRN_MX_FORCE_DAC_DATA | RADEON_BLU_MX_FORCE_DAC_DATA); if ((info->ChipFamily == CHIP_FAMILY_R300) || (info->ChipFamily == CHIP_FAMILY_R350) || (info->ChipFamily == CHIP_FAMILY_RV350)) ulData |= 0x180 << RADEON_TV_FORCE_DAC_DATA_SHIFT; else ulData |= 0x1f5 << RADEON_TV_FORCE_DAC_DATA_SHIFT; OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulData); usleep(1000); ulData = INREG(RADEON_TV_DAC_CNTL); 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); OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulOrigTV_PRE_DAC_MUX_CNTL); }#endif } return(bConnected ? MT_CRT : MT_NONE);}static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10){ RADEONInfoPtr info = RADEONPTR(pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); unsigned char *RADEONMMIO = info->MMIO; const char *s; Bool ignore_edid = FALSE, ddc_crt2_used = FALSE;#define RADEON_BIOS8(v) (info->VBIOS[v])#define RADEON_BIOS16(v) (info->VBIOS[v] | \ (info->VBIOS[(v) + 1] << 8))#define RADEON_BIOS32(v) (info->VBIOS[v] | \ (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; pRADEONEnt->MonInfo2 = NULL; pRADEONEnt->ReversedDAC = FALSE; pRADEONEnt->ReversedTMDS = FALSE; /* IgnoreEDID option is different from NoDDC options used by DDC module * When IgnoreEDID is used, monitor detection will still use DDC * detection, but all EDID data will not be used in mode validation. */ 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"); } /* * 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, * not using auto-detection routines to probe monitors. */ /* current monitor mapping scheme: * Two displays connected: * Primary Port: * 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 * * Secondary Port * CRTC2 -> CRT DAC -> VGA port -> CRT monitor --> Secondary or * CRTC2 -> FP2/Ext. -> DVI port -> TMDS panel --> Secondary * * Only DVI (or Int. LDC) conneced: * 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) * * Note, this is different from Windows scheme where * if a digital panel is connected to DVI port, DVI will be the 1st port * 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. */ 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) { case ',': s1[i] = '\0'; i = 0; second = 1; break; case ' ': case '\t': case '\n': case '\r': break; default: if (second) s2[i] = *s; else s1[i] = *s; i++; if (i == 4) break; } } while(*s++); s2[i] = '\0'; if (strcmp(s1, "NONE") == 0) pRADEONEnt->MonType1 = MT_NONE; else if (strcmp(s1, "CRT") == 0) pRADEONEnt->MonType1 = MT_CRT; else if (strcmp(s1, "TMDS") == 0) 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"); if (strcmp(s2, "NONE") == 0) pRADEONEnt->MonType2 = MT_NONE; else if (strcmp(s2, "CRT") == 0) pRADEONEnt->MonType2 = MT_CRT; else if (strcmp(s2, "TMDS") == 0) 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"); if (!ignore_edid) { if (pRADEONEnt->MonType1) /* assuming the first port using DDC_DVI */ 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); } } if (!pRADEONEnt->MonType1) { if (pRADEONEnt->MonType2) { pRADEONEnt->MonType1 = pRADEONEnt->MonType2; 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"); } pRADEONEnt->MonType2 = MT_NONE; pRADEONEnt->MonInfo2 = NULL; } } else { /* Auto detection */ int i; CARD32 tmp; /* Old single head radeon cards */ if(!info->HasCRTC2) { if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1))); else if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_VGA, &pRADEONEnt->MonInfo1))); else if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo1))); else if (pInt10) { if (xf86LoadSubModule(pScrn, "vbe")) { vbeInfoPtr pVbe; pVbe = VBEInit(pInt10, info->pEnt->index); if (pVbe) { for (i = 0; i < 5; i++) { pRADEONEnt->MonInfo1 = vbeDoEDID(pVbe, NULL); } if (pRADEONEnt->MonInfo1->rawData[0x14] & 0x80) pRADEONEnt->MonType1 = MT_DFP; else pRADEONEnt->MonType1 = MT_CRT; } } } else pRADEONEnt->MonType1 = MT_CRT; pRADEONEnt->HasSecondary = FALSE; if (!ignore_edid) { if (pRADEONEnt->MonInfo1) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitor1 EDID data ---------------------------\n"); xf86PrintEDID( pRADEONEnt->MonInfo1 ); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor1 EDID data --------------------\n"); } } return; } /* Normally the port uses DDC_DVI connected with TVDAC, * But this is not true for OEM cards which have TVDAC and CRT DAC reversed. * 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. */ if (info->VBIOS && (tmp = RADEON_BIOS16(info->FPBIOSstart + 0x50))) { for (i = 1; i < 4; i++) { unsigned int tmp0; if (!RADEON_BIOS8(tmp + i*2) && i > 1) break; tmp0 = RADEON_BIOS16(tmp + i*2); if ((!(tmp0 & 0x01)) && (((tmp0 >> 8) & 0xf) == DDC_DVI)) { pRADEONEnt->ReversedDAC = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reversed DACs detected\n"); } if ((((tmp0 >> 8) & 0x0f) == DDC_DVI ) && ((tmp0 >> 4) & 0x1)) { pRADEONEnt->ReversedTMDS = TRUE; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reversed TMDS detected\n"); } } } /* Primary Head (DVI or Laptop Int. panel)*/ /* A ddc capable display connected on DVI port */ if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -