📄 r128_driver.c
字号:
if (info->FBDev) fbdevHWUnmapMMIO(pScrn); else { xf86UnMapVidMem(pScrn->scrnIndex, info->MMIO, R128_MMIOSIZE); } info->MMIO = NULL; return TRUE;}/* Memory map the frame buffer. Used by R128MapMem, below. */static Bool R128MapFB(ScrnInfoPtr pScrn){ R128InfoPtr info = R128PTR(pScrn); if (info->FBDev) { info->FB = fbdevHWMapVidmem(pScrn); } else { info->FB = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, info->PciTag, info->LinearAddr, info->FbMapSize); } if (!info->FB) return FALSE; return TRUE;}/* Unmap the frame buffer. Used by R128UnmapMem, below. */static Bool R128UnmapFB(ScrnInfoPtr pScrn){ R128InfoPtr info = R128PTR(pScrn); if (info->FBDev) fbdevHWUnmapVidmem(pScrn); else xf86UnMapVidMem(pScrn->scrnIndex, info->FB, info->FbMapSize); info->FB = NULL; return TRUE;}/* Memory map the MMIO region and the frame buffer. */static Bool R128MapMem(ScrnInfoPtr pScrn){ if (!R128MapMMIO(pScrn)) return FALSE; if (!R128MapFB(pScrn)) { R128UnmapMMIO(pScrn); return FALSE; } return TRUE;}/* Unmap the MMIO region and the frame buffer. */static Bool R128UnmapMem(ScrnInfoPtr pScrn){ if (!R128UnmapMMIO(pScrn) || !R128UnmapFB(pScrn)) return FALSE; return TRUE;}/* Read PLL information */unsigned R128INPLL(ScrnInfoPtr pScrn, int addr){ R128InfoPtr info = R128PTR(pScrn); unsigned char *R128MMIO = info->MMIO; OUTREG8(R128_CLOCK_CNTL_INDEX, addr & 0x3f); return INREG(R128_CLOCK_CNTL_DATA);}#if 0/* Read PAL information (only used for debugging). */static int R128INPAL(int idx){ R128InfoPtr info = R128PTR(pScrn); unsigned char *R128MMIO = info->MMIO; OUTREG(R128_PALETTE_INDEX, idx << 16); return INREG(R128_PALETTE_DATA);}#endif/* Wait for vertical sync. */void R128WaitForVerticalSync(ScrnInfoPtr pScrn){ R128InfoPtr info = R128PTR(pScrn); unsigned char *R128MMIO = info->MMIO; int i; OUTREG(R128_GEN_INT_STATUS, R128_VSYNC_INT_AK); for (i = 0; i < R128_TIMEOUT; i++) { if (INREG(R128_GEN_INT_STATUS) & R128_VSYNC_INT) break; }}/* Blank screen. */static void R128Blank(ScrnInfoPtr pScrn){ R128InfoPtr info = R128PTR(pScrn); unsigned char *R128MMIO = info->MMIO; if(!info->IsSecondary) { switch(info->DisplayType) { case MT_LCD: OUTREGP(R128_LVDS_GEN_CNTL, R128_LVDS_DISPLAY_DIS, ~R128_LVDS_DISPLAY_DIS); break; case MT_CRT: OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS); break; case MT_DFP: OUTREGP(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, ~R128_FP_BLANK_DIS); break; case MT_NONE: default: break; } } else { OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_DISP_DIS, ~R128_CRTC2_DISP_DIS); }}/* Unblank screen. */static void R128Unblank(ScrnInfoPtr pScrn){ R128InfoPtr info = R128PTR(pScrn); unsigned char *R128MMIO = info->MMIO; if(!info->IsSecondary) { switch(info->DisplayType) { case MT_LCD: OUTREGP(R128_LVDS_GEN_CNTL, 0, ~R128_LVDS_DISPLAY_DIS); break; case MT_CRT: OUTREGP(R128_CRTC_EXT_CNTL, 0, ~R128_CRTC_DISPLAY_DIS); break; case MT_DFP: OUTREGP(R128_FP_GEN_CNTL, 0, ~R128_FP_BLANK_DIS); break; case MT_NONE: default: break; } } else { switch(info->DisplayType) { case MT_LCD: case MT_DFP: case MT_CRT: OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_DISP_DIS); break; case MT_NONE: default: break; } }}/* Compute log base 2 of val. */int R128MinBits(int val){ int bits; if (!val) return 1; for (bits = 0; val; val >>= 1, ++bits); return bits;}/* Compute n/d with rounding. */static int R128Div(int n, int d){ return (n + (d / 2)) / d;}/* Read the Video BIOS block and the FP registers (if applicable). */static Bool R128GetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10){ R128InfoPtr info = R128PTR(pScrn); int i; int FPHeader = 0;#define R128_BIOS8(v) (info->VBIOS[v])#define R128_BIOS16(v) (info->VBIOS[v] | \ (info->VBIOS[(v) + 1] << 8))#define R128_BIOS32(v) (info->VBIOS[v] | \ (info->VBIOS[(v) + 1] << 8) | \ (info->VBIOS[(v) + 2] << 16) | \ (info->VBIOS[(v) + 3] << 24)) if (!(info->VBIOS = xalloc(R128_VBIOS_SIZE))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot allocate space for hold Video BIOS!\n"); return FALSE; } if (pInt10) { info->BIOSAddr = pInt10->BIOSseg << 4; (void)memcpy(info->VBIOS, xf86int10Addr(pInt10, info->BIOSAddr), R128_VBIOS_SIZE); } else { xf86ReadPciBIOS(0, info->PciTag, 0, info->VBIOS, R128_VBIOS_SIZE); if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Video BIOS not detected in PCI space!\n"); xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Attempting to read Video BIOS from legacy ISA space!\n"); info->BIOSAddr = 0x000c0000; xf86ReadDomainMemory(info->PciTag, info->BIOSAddr, R128_VBIOS_SIZE, info->VBIOS); } } if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { info->BIOSAddr = 0x00000000; xfree(info->VBIOS); info->VBIOS = NULL; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Video BIOS not found!\n"); } if(info->HasCRTC2) { if(info->IsSecondary) { /* there may be a way to detect this, for now, just assume second head is CRT */ info->DisplayType = MT_CRT; if(info->DisplayType > MT_NONE) { DevUnion* pPriv; R128EntPtr pR128Ent; pPriv = xf86GetEntityPrivate(pScrn->entityList[0], getR128EntityIndex()); pR128Ent = pPriv->ptr; pR128Ent->HasSecondary = TRUE; } else return FALSE; } else { /* really need some sort of detection here */ if (info->HasPanelRegs) { info->DisplayType = MT_LCD; } else if (info->isDFP) { info->DisplayType = MT_DFP; } else { /*DVI port has no monitor connected, try CRT port. If something on CRT port, treat it as primary*/ if(xf86IsEntityShared(pScrn->entityList[0])) { DevUnion* pPriv; R128EntPtr pR128Ent; pPriv = xf86GetEntityPrivate(pScrn->entityList[0], getR128EntityIndex()); pR128Ent = pPriv->ptr; pR128Ent->BypassSecondary = TRUE; } info->DisplayType = MT_CRT;#if 0 { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No monitor detected!!!\n"); return FALSE; }#endif } } } else { /*Regular Radeon ASIC, only one CRTC, but it could be used for DFP with a DVI output, like AIW board*/ if(info->isDFP) info->DisplayType = MT_DFP; else info->DisplayType = MT_CRT; } xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Display == Type %d\n", (info->IsSecondary ? "Secondary" : "Primary"), info->DisplayType); if (info->VBIOS && info->DisplayType == MT_LCD) { info->FPBIOSstart = 0; /* FIXME: There should be direct access to the start of the FP info tables, but until we find out where that offset is stored, we must search for the ATI signature string: "M3 ". */ for (i = 4; i < R128_VBIOS_SIZE-8; i++) { if (R128_BIOS8(i) == 'M' && R128_BIOS8(i+1) == '3' && R128_BIOS8(i+2) == ' ' && R128_BIOS8(i+3) == ' ' && R128_BIOS8(i+4) == ' ' && R128_BIOS8(i+5) == ' ' && R128_BIOS8(i+6) == ' ' && R128_BIOS8(i+7) == ' ') { FPHeader = i-2; break; } } if (!FPHeader) return TRUE; /* Assume that only one panel is attached and supported */ for (i = FPHeader+20; i < FPHeader+84; i += 2) { if (R128_BIOS16(i) != 0) { info->FPBIOSstart = R128_BIOS16(i); break; } } if (!info->FPBIOSstart) return TRUE; if (!info->PanelXRes) info->PanelXRes = R128_BIOS16(info->FPBIOSstart+25); if (!info->PanelYRes) info->PanelYRes = R128_BIOS16(info->FPBIOSstart+27); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel size: %dx%d\n", info->PanelXRes, info->PanelYRes); info->PanelPwrDly = R128_BIOS8(info->FPBIOSstart+56); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel ID: "); for (i = 1; i <= 24; i++) ErrorF("%c", R128_BIOS8(info->FPBIOSstart+i)); ErrorF("\n"); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel Type: "); i = R128_BIOS16(info->FPBIOSstart+29); if (i & 1) ErrorF("Color, "); else ErrorF("Monochrome, "); if (i & 2) ErrorF("Dual(split), "); else ErrorF("Single, "); switch ((i >> 2) & 0x3f) { case 0: ErrorF("STN"); break; case 1: ErrorF("TFT"); break; case 2: ErrorF("Active STN"); break; case 3: ErrorF("EL"); break; case 4: ErrorF("Plasma"); break; default: ErrorF("UNKNOWN"); break; } ErrorF("\n"); if (R128_BIOS8(info->FPBIOSstart+61) & 1) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel Interface: LVDS\n"); } else { /* FIXME: Add Non-LVDS flat pael support */ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Non-LVDS panel interface detected! " "This support is untested and may not " "function properly\n"); } } if (!info->PanelXRes || !info->PanelYRes) { info->HasPanelRegs = FALSE; xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Can't determine panel dimensions, and none specified.\n" "\tDisabling programming of FP registers.\n"); } return TRUE;}/* Read PLL parameters from BIOS block. Default to typical values if there is no BIOS. */static Bool R128GetPLLParameters(ScrnInfoPtr pScrn){ R128InfoPtr info = R128PTR(pScrn); R128PLLPtr pll = &info->pll;#if defined(__powerpc__) || defined(__alpha__) /* there is no bios under Linux PowerPC but Open Firmware does set up the PLL registers properly and we can use those to calculate xclk and find the reference divider */ unsigned x_mpll_ref_fb_div; unsigned xclk_cntl; unsigned Nx, M; unsigned PostDivSet[] = {0, 1, 2, 4, 8, 3, 6, 12}; /* Assume REF clock is 2950 (in units of 10khz) */ /* and that all pllclk must be between 125 Mhz and 250Mhz */ pll->reference_freq = 2950; pll->min_pll_freq = 12500; pll->max_pll_freq = 25000; /* need to memory map the io to use INPLL since it has not been done yet at this point in the startup */ R128MapMMIO(pScrn); x_mpll_ref_fb_div = INPLL(pScrn, R128_X_MPLL_REF_FB_DIV); xclk_cntl = INPLL(pScrn, R128_XCLK_CNTL) & 0x7; pll->reference_div = INPLL(pScrn,R128_PPLL_REF_DIV) & R128_PPLL_REF_DIV_MASK; /* unmap it again */ R128UnmapMMIO(pScrn); Nx = (x_mpll_ref_fb_div & 0x00FF00) >> 8; M = (x_mpll_ref_fb_div & 0x0000FF); pll->xclk = R128Div((2 * Nx * pll->reference_freq), (M * PostDivSet[xclk_cntl]));#else /* !defined(__powerpc__) */ if (!info->VBIOS) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Video BIOS not detected, using default PLL parameters!\n"); /* These probably aren't going to work for the card you are using. Specifically, reference freq can be 29.50MHz, 28.63MHz, or 14.32MHz. YMMV. */ pll->reference_freq = 2950; pll->reference_div = 65; pll->min_pll_freq = 12500; pll->max_pll_freq = 25000; pll->xclk = 10300; } else { CARD16 bios_header = R128_BIOS16(0x48); CARD16 pll_info_block = R128_BIOS16(bios_header + 0x30); R128TRACE(("Header at 0x%04x; PLL Information at 0x%04x\n", bios_header, pll_info_block)); pll->reference_freq = R128_BIOS16(pll_info_block + 0x0e); pll->reference_div = R128_BIOS16(pll_info_block + 0x10); pll->min_pll_freq = R128_BIOS32(pll_info_block + 0x12); pll->max_pll_freq = R128_BIOS32(pll_info_block + 0x16); pll->xclk = R128_BIOS16(pll_info_block + 0x08); }#endif /* __powerpc__ */ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PLL parameters: rf=%d rd=%d min=%d max=%d; xclk=%d\n", pll->reference_freq, pll->reference_div,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -