📄 radeon_bios.c
字号:
/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_bios.c,v 1.0 Exp $ *//* * Copyright 2004 ATI Technologies Inc., Markham, Ontario * * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation on the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial * portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <string.h>#include "xf86.h"#include "xf86_OSproc.h"#include "radeon.h"#include "radeon_reg.h"#include "radeon_macros.h"#include "radeon_probe.h"#include "vbe.h"/* Read the Video BIOS block and the FP registers (if applicable). */Bool RADEONGetBIOSInfo(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10){ RADEONInfoPtr info = RADEONPTR(pScrn); int tmp; unsigned short dptr; if (!(info->VBIOS = xalloc(RADEON_VBIOS_SIZE))) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Cannot allocate space for hold Video BIOS!\n"); return FALSE; } else { if (pInt10) { info->BIOSAddr = pInt10->BIOSseg << 4; (void)memcpy(info->VBIOS, xf86int10Addr(pInt10, info->BIOSAddr), RADEON_VBIOS_SIZE); } else { xf86ReadPciBIOS(0, info->PciTag, 0, info->VBIOS, RADEON_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, RADEON_VBIOS_SIZE, info->VBIOS); } } } if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unrecognized BIOS signature, BIOS data will not be used\n"); xfree (info->VBIOS); info->VBIOS = NULL; return FALSE; } /* Verify it's an x86 BIOS not OF firmware, copied from radeonfb */ dptr = RADEON_BIOS16(0x18); /* If PCI data signature is wrong assume x86 video BIOS anyway */ if (RADEON_BIOS32(dptr) != (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "ROM PCI data signature incorrect, ignoring\n"); } else if (info->VBIOS[dptr + 0x14] != 0x0) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Not an x86 BIOS ROM image, BIOS data will not be used\n"); xfree (info->VBIOS); info->VBIOS = NULL; return FALSE; } if (info->VBIOS) info->ROMHeaderStart = RADEON_BIOS16(0x48); if(!info->ROMHeaderStart) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Invalid ROM pointer, BIOS data will not be used\n"); xfree (info->VBIOS); info->VBIOS = NULL; return FALSE; } tmp = info->ROMHeaderStart + 4; if ((RADEON_BIOS8(tmp) == 'A' && RADEON_BIOS8(tmp+1) == 'T' && RADEON_BIOS8(tmp+2) == 'O' && RADEON_BIOS8(tmp+3) == 'M') || (RADEON_BIOS8(tmp) == 'M' && RADEON_BIOS8(tmp+1) == 'O' && RADEON_BIOS8(tmp+2) == 'T' && RADEON_BIOS8(tmp+3) == 'A')) info->IsAtomBios = TRUE; else info->IsAtomBios = FALSE; if (info->IsAtomBios) info->MasterDataStart = RADEON_BIOS16 (info->ROMHeaderStart + 32); xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s BIOS detected\n", info->IsAtomBios ? "ATOM":"Legacy"); return TRUE;}Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn){ RADEONInfoPtr info = RADEONPTR (pScrn); RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); int i = 0, j, tmp, tmp0=0, tmp1=0; if(!info->VBIOS) return FALSE; if (info->IsAtomBios) { if((tmp = RADEON_BIOS16 (info->MasterDataStart + 22))) { int crtc = 0, id[2]; tmp1 = RADEON_BIOS16 (tmp + 4); for (i=0; i<8; i++) { if(tmp1 & (1<<i)) { CARD16 portinfo = RADEON_BIOS16(tmp+6+i*2); if (crtc < 2) { if ((i==2) || (i==6)) continue; /* ignore TV here */ if (crtc == 1) { /* sharing same port with id[0] */ if (((portinfo>>8) & 0xf) == id[0]) { if (i == 3) pRADEONEnt->PortInfo[0].TMDSType = TMDS_INT; else if (i == 7) pRADEONEnt->PortInfo[0].TMDSType = TMDS_EXT; if (pRADEONEnt->PortInfo[0].DACType == DAC_UNKNOWN) pRADEONEnt->PortInfo[0].DACType = (portinfo & 0xf) - 1; continue; } } id[crtc] = (portinfo>>8) & 0xf; pRADEONEnt->PortInfo[crtc].DACType = (portinfo & 0xf) - 1; pRADEONEnt->PortInfo[crtc].ConnectorType = (portinfo>>4) & 0xf; if (i == 3) pRADEONEnt->PortInfo[crtc].TMDSType = TMDS_INT; else if (i == 7) pRADEONEnt->PortInfo[crtc].TMDSType = TMDS_EXT; if((tmp0 = RADEON_BIOS16 (info->MasterDataStart + 24)) && id[crtc]) { switch (RADEON_BIOS16 (tmp0 + 4 + 27 * id[crtc]) * 4) { case RADEON_GPIO_MONID: pRADEONEnt->PortInfo[crtc].DDCType = DDC_MONID; break; case RADEON_GPIO_DVI_DDC: pRADEONEnt->PortInfo[crtc].DDCType = DDC_DVI; break; case RADEON_GPIO_VGA_DDC: pRADEONEnt->PortInfo[crtc].DDCType = DDC_VGA; break; case RADEON_GPIO_CRT2_DDC: pRADEONEnt->PortInfo[crtc].DDCType = DDC_CRT2; break; default: pRADEONEnt->PortInfo[crtc].DDCType = DDC_NONE_DETECTED; break; } } else { pRADEONEnt->PortInfo[crtc].DDCType = DDC_NONE_DETECTED; } crtc++; } else { /* we have already had two CRTCs assigned. the rest may share the same * port with the existing connector, fill in them accordingly. */ for (j=0; j<2; j++) { if (((portinfo>>8) & 0xf) == id[j]) { if (i == 3) pRADEONEnt->PortInfo[j].TMDSType = TMDS_INT; else if (i == 7) pRADEONEnt->PortInfo[j].TMDSType = TMDS_EXT; if (pRADEONEnt->PortInfo[j].DACType == DAC_UNKNOWN) pRADEONEnt->PortInfo[j].DACType = (portinfo & 0xf) - 1; } } } } } for (i=0; i<2; i++) { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Port%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n", i, pRADEONEnt->PortInfo[i].DDCType, pRADEONEnt->PortInfo[i].DACType, pRADEONEnt->PortInfo[i].TMDSType, pRADEONEnt->PortInfo[i].ConnectorType); } } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Device Info Table found!\n"); return FALSE; } } else { /* Some laptops only have one connector (VGA) listed in the connector table, * we need to add LVDS in as a non-DDC display. * Note, we can't assume the listed VGA will be filled in PortInfo[0], * when walking through connector table. connector_found has following meaning: * 0 -- nothing found, * 1 -- only PortInfo[0] filled, * 2 -- only PortInfo[1] filled, * 3 -- both are filled. */ int connector_found = 0; if ((tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x50))) { for (i = 1; i < 4; i++) { if (!RADEON_BIOS16(tmp + i*2)) break; /* end of table */ tmp0 = RADEON_BIOS16(tmp + i*2); if (((tmp0 >> 12) & 0x0f) == 0) continue; /* no connector */ if (connector_found > 0) { if (pRADEONEnt->PortInfo[tmp1].DDCType == ((tmp0 >> 8) & 0x0f)) continue; /* same connector */ } /* internal DDC_DVI port will get assigned to PortInfo[0], or if there is no DDC_DVI (like in some IGPs). */ tmp1 = ((((tmp0 >> 8) & 0xf) == DDC_DVI) || (tmp1 == 1)) ? 0 : 1; /* determine port info index */ pRADEONEnt->PortInfo[tmp1].DDCType = (tmp0 >> 8) & 0x0f; if (pRADEONEnt->PortInfo[tmp1].DDCType > DDC_CRT2) pRADEONEnt->PortInfo[tmp1].DDCType = DDC_NONE_DETECTED; pRADEONEnt->PortInfo[tmp1].DACType = (tmp0 & 0x01) ? DAC_TVDAC : DAC_PRIMARY; pRADEONEnt->PortInfo[tmp1].ConnectorType = (tmp0 >> 12) & 0x0f; if (pRADEONEnt->PortInfo[tmp1].ConnectorType > CONNECTOR_UNSUPPORTED) pRADEONEnt->PortInfo[tmp1].ConnectorType = CONNECTOR_UNSUPPORTED; pRADEONEnt->PortInfo[tmp1].TMDSType = ((tmp0 >> 4) & 0x01) ? TMDS_EXT : TMDS_INT; /* some sanity checks */ if (((pRADEONEnt->PortInfo[tmp1].ConnectorType != CONNECTOR_DVI_D) && (pRADEONEnt->PortInfo[tmp1].ConnectorType != CONNECTOR_DVI_I)) && pRADEONEnt->PortInfo[tmp1].TMDSType == TMDS_INT) pRADEONEnt->PortInfo[tmp1].TMDSType = TMDS_UNKNOWN; connector_found += (tmp1 + 1); } } else { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Connector Info Table found!\n"); return FALSE; } if (info->IsMobility) { /* For the cases where only one VGA connector is found, we assume LVDS is not listed in the connector table, add it in here as the first port. */ if ((connector_found < 3) && (pRADEONEnt->PortInfo[tmp1].ConnectorType == CONNECTOR_CRT)) { if (connector_found == 1) { memcpy (&pRADEONEnt->PortInfo[1], &pRADEONEnt->PortInfo[0], sizeof (pRADEONEnt->PortInfo[0])); } pRADEONEnt->PortInfo[0].DACType = DAC_TVDAC; pRADEONEnt->PortInfo[0].TMDSType = TMDS_UNKNOWN; pRADEONEnt->PortInfo[0].DDCType = DDC_NONE_DETECTED; pRADEONEnt->PortInfo[0].ConnectorType = CONNECTOR_PROPRIETARY; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS port is not in connector table, added in.\n"); if (connector_found == 0) connector_found = 1; else connector_found = 3; } if ((tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x42))) { if ((tmp0 = RADEON_BIOS16(tmp + 0x15))) { if ((tmp1 = RADEON_BIOS8(tmp0+2) & 0x07)) { pRADEONEnt->PortInfo[0].DDCType = tmp1; if (pRADEONEnt->PortInfo[0].DDCType > DDC_CRT2) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unknown DDCType %d found\n", pRADEONEnt->PortInfo[0].DDCType); pRADEONEnt->PortInfo[0].DDCType = DDC_NONE_DETECTED; } xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "LCD DDC Info Table found!\n"); } } } } else if (connector_found == 2) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -