8800305655
ati2d: fixed log creation git-svn-id: svn://kolibrios.org@9583 a494cfbc-eb01-0410-851d-a64ba20cac60
1165 lines
31 KiB
C
1165 lines
31 KiB
C
/*
|
|
* Copyright 2007 Luc Verhaegen <lverhaegen@novell.com>
|
|
* Copyright 2007 Matthias Hopf <mhopf@novell.com>
|
|
* Copyright 2007 Egbert Eich <eich@novell.com>
|
|
* Copyright 2007 Advanced Micro Devices, Inc.
|
|
*
|
|
* 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
|
|
* 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 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 NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
|
|
*/
|
|
|
|
//ld -T ld.x -s --shared --image-base 0 --file-alignment 32 -o test.exe test.obj core.lib
|
|
|
|
#include "common.h"
|
|
#include "rhd.h"
|
|
#include "edid.h"
|
|
|
|
#include "rhd_atombios.h"
|
|
#include "rhd_regs.h"
|
|
#include "rhd_mc.h"
|
|
#include "rhd_atombios.h"
|
|
#include "rhd_connector.h"
|
|
#include "rhd_output.h"
|
|
#include "rhd_biosscratch.h"
|
|
#include "rhd_card.h"
|
|
#include "rhd_vga.h"
|
|
#include "rhd_crtc.h"
|
|
#include "rhd_monitor.h"
|
|
#include "rhd_modes.h"
|
|
#include "rhd_pll.h"
|
|
#include "rhd_lut.h"
|
|
#include "rhd_i2c.h"
|
|
|
|
#define PG_SW 0x003
|
|
#define PG_NOCACHE 0x018
|
|
|
|
void sysSetScreen(int width, int height);
|
|
|
|
static void rhdModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
|
|
static void rhdSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode);
|
|
static void RHDAdjustFrame(RHDPtr rhdPtr, int x, int y, int flags);
|
|
static Bool rhdMapFB(RHDPtr rhdPtr);
|
|
static void rhdGetIGPNorthBridgeInfo(RHDPtr rhdPtr);
|
|
|
|
Bool OldSetupConnectors(RHDPtr rhdPtr);
|
|
Bool OldConnectorsInit(RHDPtr rhdPtr);
|
|
|
|
int rhdInitHeap(RHDPtr rhdPtr);
|
|
|
|
static enum rhdCardType rhdGetCardType(RHDPtr rhdPtr);
|
|
|
|
|
|
static u32_t _PciApi(int cmd);
|
|
static int SupportedModes;
|
|
|
|
int __stdcall drvEntry(int)__asm__("_drvEntry");
|
|
|
|
typedef struct
|
|
{
|
|
unsigned handle;
|
|
unsigned io_code;
|
|
void *input;
|
|
int inp_size;
|
|
void *output;
|
|
int out_size;
|
|
}ioctl_t;
|
|
|
|
typedef int (_stdcall *srv_proc_t)(ioctl_t *);
|
|
|
|
int _stdcall srv_proc(ioctl_t *io);
|
|
|
|
extern PciChipset_t RHDPCIchipsets[];
|
|
extern struct rhdCard *RHDCardIdentify(RHDPtr rhdPtr);
|
|
|
|
static struct RHDRec rhd;
|
|
static struct _ScrnInfoRec Scrn;
|
|
|
|
void sysSetScreen(int width, int height)
|
|
{
|
|
asm __volatile__
|
|
(
|
|
"dec eax \n\t"
|
|
"dec edx \n\t"
|
|
"call [DWORD PTR __imp__SetScreen] \n\t"
|
|
:
|
|
:"a" (width),"d"(height)
|
|
:"memory","cc"
|
|
);
|
|
}
|
|
|
|
static int RegService(char *name, srv_proc_t proc)
|
|
{
|
|
int retval;
|
|
|
|
asm __volatile__
|
|
(
|
|
"push %[t] \n\t"
|
|
"push %[t1] \n\t"
|
|
"call [DWORD PTR __imp__RegService] \n\t"
|
|
:"=eax" (retval)
|
|
:[t] "g" (proc),[t1] "g" (name)
|
|
:"memory", "ebx"
|
|
);
|
|
return retval;
|
|
};
|
|
|
|
static u32_t _PciApi(int cmd)
|
|
{
|
|
u32_t retval;
|
|
|
|
asm __volatile__
|
|
(
|
|
"call [DWORD PTR __imp__PciApi]"
|
|
:"=eax" (retval)
|
|
:"a" (cmd)
|
|
:"memory"
|
|
);
|
|
return retval;
|
|
};
|
|
|
|
const PciChipset_t *PciDevMatch(CARD16 dev,const PciChipset_t *list)
|
|
{
|
|
while(list->device)
|
|
{
|
|
if(dev==list->device)
|
|
return list;
|
|
list++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const char *
|
|
xf86TokenToString(SymTabPtr table, int token)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; table[i].token >= 0 && table[i].token != token; i++){};
|
|
|
|
if (table[i].token < 0)
|
|
return NULL;
|
|
else
|
|
return(table[i].name);
|
|
}
|
|
|
|
int FindPciDevice()
|
|
{
|
|
const PciChipset_t *dev;
|
|
u32_t bus, last_bus;
|
|
|
|
if( (last_bus = _PciApi(1))==-1)
|
|
return 0;
|
|
|
|
for(bus=0;bus<=last_bus;bus++)
|
|
{
|
|
u32_t devfn;
|
|
|
|
for(devfn=0;devfn<256;devfn++)
|
|
{
|
|
u32_t id;
|
|
id = PciRead32(bus,devfn, 0);
|
|
|
|
if( (CARD16)id != VENDOR_ATI)
|
|
continue;
|
|
|
|
if( (dev=PciDevMatch(id>>16,RHDPCIchipsets))!=0)
|
|
{
|
|
|
|
rhd.PciDeviceID = (id>>16);
|
|
|
|
rhd.bus = bus;
|
|
rhd.pci.bus = bus;
|
|
rhd.devfn = devfn;
|
|
rhd.pci.devfn = devfn;
|
|
rhd.PciTag = pciTag(bus,(devfn>>3)&0x1F,devfn&0x7);
|
|
|
|
rhd.ChipSet = dev->family;
|
|
// rhd.IsMobility = dev->mobility;
|
|
// rhd.IsIGP = dev->igp;
|
|
// rhd.HasCRTC2 = !dev->nocrtc2;
|
|
// rhd.HasSingleDAC = dev->singledac;
|
|
// rhd.InternalTVOut = !dev->nointtvout;
|
|
|
|
pciGetInfo(&rhd.pci);
|
|
|
|
rhd.subvendor_id = rhd.pci.subsysVendor;
|
|
rhd.subdevice_id = rhd.pci.subsysCard;
|
|
|
|
//rhd.chipset = (char*)xf86TokenToString(RADEONChipsets, rhd.device_id);
|
|
|
|
return 1;
|
|
};
|
|
};
|
|
};
|
|
|
|
dbgprintf("Device not found\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static Bool
|
|
rhdMapMMIO()
|
|
{
|
|
|
|
rhd.MMIOMapSize = 1 << rhd.pci.size[RHD_MMIO_BAR];
|
|
rhd.MMIOBase = MapIoMem(rhd.pci.memBase[RHD_MMIO_BAR],
|
|
rhd.MMIOMapSize,PG_SW+PG_NOCACHE);
|
|
if( !rhd.MMIOBase)
|
|
return 0;
|
|
|
|
DBG(dbgprintf("Mapped IO at %x (size %x)\n", rhd.MMIOBase, rhd.MMIOMapSize));
|
|
|
|
return 1;
|
|
}
|
|
|
|
#define RADEON_NB_TOM 0x15c
|
|
static CARD32
|
|
rhdGetVideoRamSize(RHDPtr rhdPtr)
|
|
{
|
|
CARD32 RamSize, BARSize;
|
|
|
|
if (rhdPtr->ChipSet == RHD_RS690)
|
|
RamSize = (_RHDRegRead(rhdPtr, R5XX_CONFIG_MEMSIZE))>>10;
|
|
else
|
|
if (rhdPtr->IsIGP)
|
|
{
|
|
CARD32 tom = _RHDRegRead(rhdPtr, RADEON_NB_TOM);
|
|
RamSize = (((tom >> 16) - (tom & 0xffff) + 1) << 6);
|
|
_RHDRegWrite(rhdPtr,R5XX_CONFIG_MEMSIZE, RamSize<<10);
|
|
}
|
|
else
|
|
{
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
{
|
|
RamSize = (_RHDRegRead(rhdPtr, R5XX_CONFIG_MEMSIZE)) >> 10;
|
|
if(RamSize==0) RamSize=8192;
|
|
}
|
|
else
|
|
RamSize = (_RHDRegRead(rhdPtr, R6XX_CONFIG_MEMSIZE)) >> 10;
|
|
};
|
|
|
|
BARSize = 1 << (rhdPtr->pci.size[RHD_FB_BAR] - 10);
|
|
if(BARSize==0)
|
|
BARSize = 0x20000;
|
|
|
|
if (RamSize > BARSize) {
|
|
DBG(dbgprintf("The detected amount of videoram"
|
|
" exceeds the PCI BAR aperture.\n"));
|
|
DBG(dbgprintf("Using only %dkB of the total "
|
|
"%dkB.\n", (int) BARSize, (int) RamSize));
|
|
return BARSize;
|
|
}
|
|
else return RamSize;
|
|
}
|
|
|
|
|
|
Bool RHDScalePolicy(struct rhdMonitor *Monitor, struct rhdConnector *Connector)
|
|
{
|
|
if (!Monitor || !Monitor->UseFixedModes || !Monitor->NativeMode)
|
|
return FALSE;
|
|
|
|
if (Connector->Type != RHD_CONNECTOR_PANEL)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
rhdOutputConnectorCheck(struct rhdConnector *Connector)
|
|
{
|
|
struct rhdOutput *Output;
|
|
int i;
|
|
|
|
/* First, try to sense */
|
|
for (i = 0; i < 2; i++) {
|
|
Output = Connector->Output[i];
|
|
if (Output && Output->Sense) {
|
|
/*
|
|
* This is ugly and needs to change when the TV support patches are in.
|
|
* The problem here is that the Output struct can be used for two connectors
|
|
* and thus two different devices
|
|
*/
|
|
if (Output->SensedType == RHD_SENSED_NONE) {
|
|
/* Do this before sensing as AtomBIOS sense needs this info */
|
|
if ((Output->SensedType = Output->Sense(Output, Connector)) != RHD_SENSED_NONE) {
|
|
RHDOutputPrintSensedType(Output);
|
|
Output->Connector = Connector;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i == 2) {
|
|
/* now just enable the ones without sensing */
|
|
for (i = 0; i < 2; i++) {
|
|
Output = Connector->Output[i];
|
|
if (Output && !Output->Sense) {
|
|
Output->Connector = Connector;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static Bool
|
|
rhdModeLayoutSelect(RHDPtr rhdPtr)
|
|
{
|
|
struct rhdOutput *Output;
|
|
struct rhdConnector *Connector;
|
|
Bool Found = FALSE;
|
|
char *ignore = NULL;
|
|
Bool ConnectorIsDMS59 = FALSE;
|
|
int i = 0;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
/* housekeeping */
|
|
rhdPtr->Crtc[0]->PLL = rhdPtr->PLLs[0];
|
|
rhdPtr->Crtc[0]->LUT = rhdPtr->LUT[0];
|
|
|
|
rhdPtr->Crtc[1]->PLL = rhdPtr->PLLs[1];
|
|
rhdPtr->Crtc[1]->LUT = rhdPtr->LUT[1];
|
|
|
|
/* start layout afresh */
|
|
for (Output = rhdPtr->Outputs; Output; Output = Output->Next)
|
|
{
|
|
Output->Active = FALSE;
|
|
Output->Crtc = NULL;
|
|
Output->Connector = NULL;
|
|
}
|
|
|
|
/* quick and dirty option so that some output choice exists */
|
|
// ignore = xf86GetOptValString(rhdPtr->Options, OPTION_IGNORECONNECTOR);
|
|
|
|
/* handle cards with DMS-59 connectors appropriately. The DMS-59 to VGA
|
|
adapter does not raise HPD at all, so we need a fallback there. */
|
|
if (rhdPtr->Card)
|
|
{
|
|
ConnectorIsDMS59 = rhdPtr->Card->flags & RHD_CARD_FLAG_DMS59;
|
|
if (ConnectorIsDMS59)
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Card %s has a DMS-59"
|
|
" connector.\n", rhdPtr->Card->name);
|
|
}
|
|
|
|
/* Check on the basis of Connector->HPD */
|
|
for (i = 0; i < RHD_CONNECTORS_MAX; i++)
|
|
{
|
|
Connector = rhdPtr->Connector[i];
|
|
|
|
if (!Connector)
|
|
continue;
|
|
|
|
|
|
if (Connector->HPDCheck) {
|
|
if (Connector->HPDCheck(Connector)) {
|
|
Connector->HPDAttached = TRUE;
|
|
rhdOutputConnectorCheck(Connector);
|
|
} else {
|
|
Connector->HPDAttached = FALSE;
|
|
if (ConnectorIsDMS59)
|
|
rhdOutputConnectorCheck(Connector);
|
|
}
|
|
} else
|
|
rhdOutputConnectorCheck(Connector);
|
|
}
|
|
|
|
i = 0; /* counter for CRTCs */
|
|
for (Output = rhdPtr->Outputs; Output; Output = Output->Next)
|
|
if (Output->Connector) {
|
|
struct rhdMonitor *Monitor = NULL;
|
|
|
|
Connector = Output->Connector;
|
|
|
|
Monitor = RHDMonitorInit(Connector);
|
|
|
|
if (!Monitor && (Connector->Type == RHD_CONNECTOR_PANEL)) {
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING, "Unable to attach a"
|
|
" monitor to connector \"%s\"\n", Connector->Name);
|
|
Output->Active = FALSE;
|
|
} else if (!Output->AllocFree || Output->AllocFree(Output, RHD_OUTPUT_ALLOC)){
|
|
Connector->Monitor = Monitor;
|
|
|
|
Output->Active = TRUE;
|
|
|
|
Output->Crtc = rhdPtr->Crtc[i & 1]; /* ;) */
|
|
i++;
|
|
|
|
Output->Crtc->Active = TRUE;
|
|
|
|
if (RHDScalePolicy(Monitor, Connector)) {
|
|
Output->Crtc->ScaledToMode = RHDModeCopy(Monitor->NativeMode);
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_INFO,
|
|
"Crtc[%i]: found native mode from Monitor[%s]: ",
|
|
Output->Crtc->Id, Monitor->Name);
|
|
RHDPrintModeline(Output->Crtc->ScaledToMode);
|
|
}
|
|
Found = TRUE;
|
|
|
|
if (Monitor) {
|
|
/* If this is a DVI attached monitor, enable reduced blanking.
|
|
* TODO: iiyama vm pro 453: CRT with DVI-D == No reduced.
|
|
*/
|
|
if ((Output->Id == RHD_OUTPUT_TMDSA) ||
|
|
(Output->Id == RHD_OUTPUT_LVTMA) ||
|
|
(Output->Id == RHD_OUTPUT_KLDSKP_LVTMA) ||
|
|
(Output->Id == RHD_OUTPUT_UNIPHYA) ||
|
|
(Output->Id == RHD_OUTPUT_UNIPHYB))
|
|
Monitor->ReducedAllowed = TRUE;
|
|
|
|
/* allow user to override settings globally */
|
|
if (rhdPtr->forceReduced.set)
|
|
Monitor->ReducedAllowed = rhdPtr->forceReduced.val.bool;
|
|
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_INFO,
|
|
"Connector \"%s\" uses Monitor \"%s\":\n",
|
|
Connector->Name, Monitor->Name);
|
|
RHDMonitorPrint(Monitor);
|
|
} else
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_WARNING,
|
|
"Connector \"%s\": Failed to retrieve Monitor"
|
|
" information.\n", Connector->Name);
|
|
}
|
|
}
|
|
|
|
/* Now validate the scaled modes attached to crtcs */
|
|
for (i = 0; i < 2; i++) {
|
|
struct rhdCrtc *crtc = rhdPtr->Crtc[i];
|
|
if (crtc->ScaledToMode && RHDValidateScaledToMode(crtc, crtc->ScaledToMode) != MODE_OK) {
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR, "Crtc[%i]: scaled mode invalid.\n", crtc->Id);
|
|
xfree(crtc->ScaledToMode);
|
|
crtc->ScaledToMode = NULL;
|
|
}
|
|
}
|
|
return Found;
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
rhdModeLayoutPrint(RHDPtr rhdPtr)
|
|
{
|
|
struct rhdCrtc *Crtc;
|
|
struct rhdOutput *Output;
|
|
Bool Found;
|
|
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "Listing modesetting layout:\n\n");
|
|
|
|
/* CRTC 1 */
|
|
Crtc = rhdPtr->Crtc[0];
|
|
if (Crtc->Active) {
|
|
xf86Msg(X_NONE, "\t%s: tied to %s and %s:\n",
|
|
Crtc->Name, Crtc->PLL->Name, Crtc->LUT->Name);
|
|
|
|
Found = FALSE;
|
|
for (Output = rhdPtr->Outputs; Output; Output = Output->Next)
|
|
if (Output->Active && (Output->Crtc == Crtc)) {
|
|
if (!Found) {
|
|
xf86Msg(X_NONE, "\t\tOutputs: %s (%s)",
|
|
Output->Name, Output->Connector->Name);
|
|
Found = TRUE;
|
|
} else
|
|
xf86Msg(X_NONE, ", %s (%s)", Output->Name,
|
|
Output->Connector->Name);
|
|
}
|
|
|
|
if (!Found)
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
|
|
"%s is active without outputs\n", Crtc->Name);
|
|
else
|
|
xf86Msg(X_NONE, "\n");
|
|
} else
|
|
xf86Msg(X_NONE, "\t%s: unused\n", Crtc->Name);
|
|
xf86Msg(X_NONE, "\n");
|
|
|
|
/* CRTC 2 */
|
|
Crtc = rhdPtr->Crtc[1];
|
|
if (Crtc->Active) {
|
|
xf86Msg(X_NONE, "\t%s: tied to %s and %s:\n",
|
|
Crtc->Name, Crtc->PLL->Name, Crtc->LUT->Name);
|
|
|
|
Found = FALSE;
|
|
for (Output = rhdPtr->Outputs; Output; Output = Output->Next)
|
|
if (Output->Active && (Output->Crtc == Crtc)) {
|
|
if (!Found) {
|
|
xf86Msg(X_NONE, "\t\tOutputs: %s (%s)",
|
|
Output->Name, Output->Connector->Name);
|
|
Found = TRUE;
|
|
} else
|
|
xf86Msg(X_NONE, ", %s (%s)", Output->Name,
|
|
Output->Connector->Name);
|
|
}
|
|
|
|
if (!Found)
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
|
|
"%s is active without outputs\n", Crtc->Name);
|
|
else
|
|
xf86Msg(X_NONE, "\n");
|
|
} else
|
|
xf86Msg(X_NONE, "\t%s: unused\n", Crtc->Name);
|
|
xf86Msg(X_NONE, "\n");
|
|
|
|
/* Print out unused Outputs */
|
|
Found = FALSE;
|
|
for (Output = rhdPtr->Outputs; Output; Output = Output->Next)
|
|
if (!Output->Active) {
|
|
if (!Found) {
|
|
xf86Msg(X_NONE, "\t\tUnused Outputs: %s", Output->Name);
|
|
Found = TRUE;
|
|
} else
|
|
xf86Msg(X_NONE, ", %s", Output->Name);
|
|
}
|
|
|
|
if (Found)
|
|
xf86Msg(X_NONE, "\n");
|
|
xf86Msg(X_NONE, "\n");
|
|
}
|
|
|
|
|
|
DisplayModePtr
|
|
rhdCreateModesListAndValidate(ScrnInfoPtr pScrn, Bool Silent);
|
|
void RHDPrintModeline(DisplayModePtr mode);
|
|
|
|
int RHDPreInit()
|
|
{
|
|
RHDI2CDataArg i2cArg;
|
|
RHDPtr rhdPtr = &rhd;
|
|
|
|
/* We need access to IO space already */
|
|
if (!rhdMapMMIO()) {
|
|
dbgprintf("Failed to map MMIO.\n");
|
|
return 0;
|
|
};
|
|
|
|
|
|
if (RHDIsIGP(rhd.ChipSet))
|
|
rhdGetIGPNorthBridgeInfo(&rhd);
|
|
|
|
rhd.Card = RHDCardIdentify(&rhd);
|
|
if (rhd.Card)
|
|
dbgprintf("Detected an %s on a %s\n", rhd.chipset_name, rhd.Card->name);
|
|
else
|
|
dbgprintf("Detected an %s on an unidentified card\n", rhd.chipset_name);
|
|
|
|
if (rhdPtr->Card && rhdPtr->Card->flags & RHD_CARD_FLAG_HPDSWAP &&
|
|
rhdPtr->hpdUsage == RHD_HPD_USAGE_AUTO)
|
|
rhdPtr->hpdUsage = RHD_HPD_USAGE_AUTO_SWAP;
|
|
if (rhdPtr->Card && rhdPtr->Card->flags & RHD_CARD_FLAG_HPDOFF &&
|
|
rhdPtr->hpdUsage == RHD_HPD_USAGE_AUTO)
|
|
rhdPtr->hpdUsage = RHD_HPD_USAGE_AUTO_OFF;
|
|
|
|
rhdPtr->cardType = rhdGetCardType(rhdPtr);
|
|
|
|
|
|
{
|
|
AtomBiosArgRec atomBiosArg;
|
|
|
|
rhd.UseAtomFlags = (RHD_ATOMBIOS_ON << RHD_ATOMBIOS_CRTC) |
|
|
(RHD_ATOMBIOS_ON << RHD_ATOMBIOS_OUTPUT) |
|
|
(RHD_ATOMBIOS_ON << RHD_ATOMBIOS_PLL);
|
|
|
|
// rhd.UseAtomFlags = 0;
|
|
|
|
if (RHDAtomBiosFunc(&rhd, NULL, ATOMBIOS_INIT, &atomBiosArg) == ATOM_SUCCESS)
|
|
{
|
|
rhd.atomBIOS = atomBiosArg.atomhandle;
|
|
}
|
|
}
|
|
|
|
rhd.videoRam = rhdGetVideoRamSize(&rhd);
|
|
if (!rhd.videoRam)
|
|
{
|
|
dbgprintf("No Video RAM detected.\n");
|
|
goto error1;
|
|
}
|
|
dbgprintf("VideoRAM: %d kByte\n",rhd.videoRam);
|
|
|
|
if (rhd.atomBIOS) /* for testing functions */
|
|
{
|
|
AtomBiosArgRec atomBiosArg;
|
|
|
|
atomBiosArg.fb.start = rhd.FbFreeStart;
|
|
atomBiosArg.fb.size = rhd.FbFreeSize;
|
|
if (RHDAtomBiosFunc(&rhd, rhd.atomBIOS, ATOMBIOS_ALLOCATE_FB_SCRATCH,
|
|
&atomBiosArg) == ATOM_SUCCESS)
|
|
{
|
|
rhd.FbFreeStart = atomBiosArg.fb.start;
|
|
rhd.FbFreeSize = atomBiosArg.fb.size;
|
|
};
|
|
RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_DEFAULT_ENGINE_CLOCK, &atomBiosArg);
|
|
RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_DEFAULT_MEMORY_CLOCK, &atomBiosArg);
|
|
RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_MAX_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg);
|
|
RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_MIN_PIXEL_CLOCK_PLL_OUTPUT, &atomBiosArg);
|
|
RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_MAX_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg);
|
|
RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_MIN_PIXEL_CLOCK_PLL_INPUT, &atomBiosArg);
|
|
RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_MAX_PIXEL_CLK, &atomBiosArg);
|
|
RHDAtomBiosFunc(&rhd, rhd.atomBIOS, GET_REF_CLOCK, &atomBiosArg);
|
|
}
|
|
|
|
|
|
rhd.FbFreeStart = 0;
|
|
rhd.FbFreeSize = rhd.videoRam << 10;
|
|
|
|
|
|
if (RHDI2CFunc((int)&rhd, NULL, RHD_I2C_INIT, &i2cArg) == RHD_I2C_SUCCESS)
|
|
rhd.I2C = i2cArg.I2CBusList;
|
|
else
|
|
{
|
|
dbgprintf("I2C init failed\n");
|
|
goto error1;
|
|
};
|
|
|
|
if (!rhd.atomBIOS)
|
|
{
|
|
dbgprintf("No ATOMBIOS detected. Done.\n");
|
|
return 0;
|
|
}
|
|
|
|
// rhdMapFB(&rhd);
|
|
|
|
Scrn.rhdPtr = &rhd;
|
|
Scrn.driverName = "Radeon HD driver";
|
|
Scrn.bitsPerPixel = 32;
|
|
Scrn.depth = 32;
|
|
Scrn.virtualX = 1280;
|
|
Scrn.virtualY = 1024;
|
|
Scrn.displayWidth = 1280;
|
|
|
|
rhd.pScrn = &Scrn;
|
|
|
|
rhd.FbScanoutStart = 0;
|
|
rhd.FbScanoutSize = 8*1024*1024;
|
|
rhd.FbFreeStart = 8*1024*1024;
|
|
rhd.FbFreeSize = rhd.FbMapSize - 8*1024*1024;
|
|
|
|
rhdInitHeap(&rhd);
|
|
|
|
RHDVGAInit(&rhd);
|
|
RHDMCInit(&rhd);
|
|
|
|
if (!RHDCrtcsInit(&rhd))
|
|
RHDAtomCrtcsInit(&rhd);
|
|
if (!RHDPLLsInit(&rhd))
|
|
RHDAtomPLLsInit(&rhd);
|
|
|
|
RHDLUTsInit(&rhd);
|
|
|
|
if (!RHDConnectorsInit(&rhd, rhd.Card))
|
|
{
|
|
dbgprintf("Card information has invalid connector information\n");
|
|
goto error1;
|
|
}
|
|
|
|
{
|
|
struct rhdAtomOutputDeviceList *OutputDeviceList = NULL;
|
|
|
|
if (rhdPtr->Card
|
|
&& rhdPtr->Card->ConnectorInfo[0].Type != RHD_CONNECTOR_NONE
|
|
&& (rhdPtr->Card->DeviceInfo[0][0] != atomNone
|
|
|| rhdPtr->Card->DeviceInfo[0][1] != atomNone))
|
|
{
|
|
int i, k = 0;
|
|
|
|
for (i = 0; i < RHD_CONNECTORS_MAX; i++)
|
|
{
|
|
int j;
|
|
if (rhdPtr->Card->ConnectorInfo[i].Type == RHD_CONNECTOR_NONE)
|
|
break;
|
|
for (j = 0; j < MAX_OUTPUTS_PER_CONNECTOR; j++)
|
|
{
|
|
if (rhdPtr->Card->ConnectorInfo[i].Output[j] != RHD_OUTPUT_NONE)
|
|
{
|
|
if (!(OutputDeviceList =
|
|
(struct rhdAtomOutputDeviceList *)
|
|
xrealloc(OutputDeviceList,
|
|
sizeof (struct rhdAtomOutputDeviceList) * (k + 1))))
|
|
break;
|
|
OutputDeviceList[k].ConnectorType = rhdPtr->Card->ConnectorInfo[i].Type;
|
|
OutputDeviceList[k].DeviceId = rhdPtr->Card->DeviceInfo[i][j];
|
|
OutputDeviceList[k].OutputType = rhdPtr->Card->ConnectorInfo[i].Output[j];
|
|
dbgprintf("OutputDevice: C: 0x%2.2x O: 0x%2.2x DevID: 0x%2.2x\n",
|
|
OutputDeviceList[k].ConnectorType,
|
|
OutputDeviceList[k].OutputType,
|
|
OutputDeviceList[k].DeviceId);
|
|
k++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AtomBiosArgRec data;
|
|
|
|
data.chipset = rhdPtr->ChipSet;
|
|
if (RHDAtomBiosFunc(rhdPtr, rhdPtr->atomBIOS,
|
|
ATOMBIOS_GET_OUTPUT_DEVICE_LIST, &data) == ATOM_SUCCESS)
|
|
OutputDeviceList = data.OutputDeviceList;
|
|
}
|
|
|
|
if (OutputDeviceList)
|
|
{
|
|
struct rhdOutput *Output;
|
|
|
|
for (Output = rhdPtr->Outputs; Output; Output = Output->Next)
|
|
RHDAtomSetupOutputDriverPrivate(OutputDeviceList, Output);
|
|
xfree(OutputDeviceList);
|
|
}
|
|
}
|
|
|
|
|
|
if (!rhdModeLayoutSelect(&rhd))
|
|
{
|
|
dbgprintf("Failed to detect a connected monitor\n");
|
|
goto error1;
|
|
}
|
|
|
|
RHDConfigMonitorSet(&rhd, FALSE);
|
|
rhdModeLayoutPrint(&rhd);
|
|
|
|
{
|
|
DisplayModePtr Modes, tmp;
|
|
|
|
Modes = RHDModesPoolCreate(&Scrn, FALSE);
|
|
Scrn.modePool = Modes;
|
|
|
|
tmp = Modes;
|
|
SupportedModes=0;
|
|
while(tmp)
|
|
{
|
|
dbgprintf("%dx%d@%3.1fHz\n",tmp->CrtcHDisplay,
|
|
tmp->CrtcVDisplay,tmp->VRefresh);
|
|
tmp=tmp->next;
|
|
SupportedModes++;
|
|
};
|
|
// rhdModeInit(&Scrn,Modes);
|
|
//RHDAdjustFrame(&rhd,0,0,0);
|
|
};
|
|
dbgprintf("All done\n");
|
|
return 1;
|
|
|
|
error1:
|
|
return 0;
|
|
};
|
|
|
|
int __stdcall drvEntry(int action)
|
|
{
|
|
int i;
|
|
|
|
if(action != 1)
|
|
return 0;
|
|
|
|
if(!dbg_open("/sys/drivers/ati.txt"))
|
|
{
|
|
printf("Can't open /sys/drivers/ati.txt\nExit\n");
|
|
return 0;
|
|
}
|
|
if(!FindPciDevice())
|
|
return 0;
|
|
|
|
rhd.scrnIndex = (int)&rhd;
|
|
|
|
for(i=0;i<6;i++)
|
|
{
|
|
if(rhd.pci.memBase[i])
|
|
dbgprintf("Memory base_%d 0x%x size 0x%x\n",
|
|
i,rhd.pci.memBase[i],(1<<rhd.pci.size[i]));
|
|
};
|
|
for(i=0;i<6;i++)
|
|
{
|
|
if(rhd.pci.ioBase[i])
|
|
dbgprintf("Io base_%d 0x%x size 0x%x\n",
|
|
i,rhd.pci.ioBase[i],(1<<rhd.pci.size[i]));
|
|
};
|
|
if(RHDPreInit()==0)
|
|
return 0;
|
|
|
|
return RegService("RHD", srv_proc);
|
|
};
|
|
|
|
|
|
void usleep(u32_t delay)
|
|
{
|
|
if(!delay) delay++;
|
|
delay*=1000;
|
|
|
|
asm(
|
|
"1:\n\t"
|
|
"xor eax, eax \n\t"
|
|
"cpuid \n\t"
|
|
"dec edi \n\t"
|
|
"jnz 1b"
|
|
:
|
|
:"D"(delay)
|
|
:"eax","ebx","ecx","edx"
|
|
);
|
|
}
|
|
|
|
|
|
//git://anongit.freedesktop.org/git/xorg/xserver
|
|
//git://anongit.freedesktop.org/git/xorg/lib/libpciaccess
|
|
|
|
int KernelFree(void *p)
|
|
{
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
rhdPrepareMode(RHDPtr rhdPtr)
|
|
{
|
|
RHDFUNC(rhdPtr);
|
|
|
|
/* no active outputs == no mess */
|
|
RHDOutputsPower(rhdPtr, RHD_POWER_RESET);
|
|
}
|
|
|
|
/*
|
|
* */static void
|
|
rhdModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
|
|
{
|
|
RHDPtr rhdPtr = pScrn->rhdPtr;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
rhdSetMode(pScrn, mode);
|
|
}
|
|
|
|
/* * */static void
|
|
rhdSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
|
|
{
|
|
RHDPtr rhdPtr = RHDPTR(pScrn);
|
|
int i;
|
|
|
|
RHDFUNC(rhdPtr);
|
|
|
|
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Setting up \"%s\" (%dx%d@%3.1fHz)\n",
|
|
mode->name, mode->CrtcHDisplay, mode->CrtcVDisplay,
|
|
mode->VRefresh);
|
|
|
|
/* Set up D1/D2 and appendages */
|
|
for (i = 0; i < 2; i++) {
|
|
struct rhdCrtc *Crtc;
|
|
|
|
Crtc = rhdPtr->Crtc[i];
|
|
if (Crtc->Active) {
|
|
Crtc->FBSet(Crtc, pScrn->displayWidth, pScrn->virtualX, pScrn->virtualY,
|
|
pScrn->depth, rhdPtr->FbScanoutStart);
|
|
if (Crtc->ScaledToMode) {
|
|
Crtc->ModeSet(Crtc, Crtc->ScaledToMode);
|
|
if (Crtc->ScaleSet)
|
|
Crtc->ScaleSet(Crtc, Crtc->ScaleType, mode, Crtc->ScaledToMode);
|
|
} else {
|
|
Crtc->ModeSet(Crtc, mode);
|
|
if (Crtc->ScaleSet)
|
|
Crtc->ScaleSet(Crtc, RHD_CRTC_SCALE_TYPE_NONE, mode, NULL);
|
|
}
|
|
RHDPLLSet(Crtc->PLL, mode->Clock);
|
|
Crtc->LUTSelect(Crtc, Crtc->LUT);
|
|
RHDOutputsMode(rhdPtr, Crtc, Crtc->ScaledToMode
|
|
? Crtc->ScaledToMode : mode);
|
|
}
|
|
}
|
|
|
|
/* shut down that what we don't use */
|
|
RHDPLLsShutdownInactive(rhdPtr);
|
|
RHDOutputsShutdownInactive(rhdPtr);
|
|
|
|
if (rhdPtr->Crtc[0]->Active)
|
|
rhdPtr->Crtc[0]->Power(rhdPtr->Crtc[0], RHD_POWER_ON);
|
|
else
|
|
rhdPtr->Crtc[0]->Power(rhdPtr->Crtc[0], RHD_POWER_SHUTDOWN);
|
|
|
|
if (rhdPtr->Crtc[1]->Active)
|
|
rhdPtr->Crtc[1]->Power(rhdPtr->Crtc[1], RHD_POWER_ON);
|
|
else
|
|
rhdPtr->Crtc[1]->Power(rhdPtr->Crtc[1], RHD_POWER_SHUTDOWN);
|
|
|
|
RHDOutputsPower(rhdPtr, RHD_POWER_ON);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
RHDAdjustFrame(RHDPtr rhdPtr, int x, int y, int flags)
|
|
{
|
|
// ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
|
|
// RHDPtr rhdPtr = RHDPTR(pScrn);
|
|
struct rhdCrtc *Crtc;
|
|
|
|
Crtc = rhdPtr->Crtc[0];
|
|
if (Crtc->Active)
|
|
Crtc->FrameSet(Crtc, x, y);
|
|
|
|
Crtc = rhdPtr->Crtc[1];
|
|
if ( Crtc->Active)
|
|
Crtc->FrameSet(Crtc, x, y);
|
|
|
|
}
|
|
|
|
static Bool
|
|
rhdMapFB(RHDPtr rhdPtr)
|
|
{
|
|
CARD32 membase;
|
|
RHDFUNC(rhdPtr);
|
|
|
|
rhdPtr->FbMapSize = 1 << rhdPtr->pci.size[RHD_FB_BAR];
|
|
membase = rhdPtr->pci.memBase[RHD_FB_BAR];
|
|
|
|
rhdPtr->FbBase = MapIoMem(membase, rhdPtr->FbMapSize,PG_SW+PG_NOCACHE);
|
|
|
|
if (!rhdPtr->FbBase)
|
|
return FALSE;
|
|
|
|
/* These devices have an internal address reference, which some other
|
|
* address registers in there also use. This can be different from the
|
|
* address in the BAR */
|
|
if (rhdPtr->ChipSet < RHD_R600)
|
|
rhdPtr->FbIntAddress = _RHDRegRead(rhdPtr, HDP_FB_LOCATION)<< 16;
|
|
else
|
|
rhdPtr->FbIntAddress = _RHDRegRead(rhdPtr, R6XX_CONFIG_FB_BASE);
|
|
|
|
if (rhdPtr->FbIntAddress != membase)
|
|
dbgprintf("PCI FB Address (BAR) is at "
|
|
"0x%08X while card Internal Address is 0x%08X\n",
|
|
(unsigned int) membase,rhdPtr->FbIntAddress);
|
|
dbgprintf("Mapped FB at %p (size 0x%08X)\n",rhdPtr->FbBase, rhdPtr->FbMapSize);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#define ERR_PARAM -1
|
|
|
|
#pragma pack (push,1)
|
|
typedef struct
|
|
{
|
|
short width;
|
|
short height;
|
|
short bpp;
|
|
short freq;
|
|
}mode_t;
|
|
#pragma pack (pop)
|
|
|
|
int get_modes(mode_t *mode, int count)
|
|
{
|
|
if(count==0)
|
|
count = SupportedModes;
|
|
else
|
|
{
|
|
DisplayModePtr tmp;
|
|
int i;
|
|
|
|
if(count>SupportedModes)
|
|
count = SupportedModes;
|
|
|
|
for(i=0,tmp = Scrn.modePool;i<count;i++,tmp=tmp->next,mode++)
|
|
{
|
|
mode->width = tmp->CrtcHDisplay;
|
|
mode->height = tmp->CrtcVDisplay;
|
|
mode->bpp = 32;
|
|
mode->freq = (short)__builtin_ceilf(tmp->VRefresh);
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int set_mode(mode_t *mode)
|
|
{
|
|
DisplayModePtr tmp;
|
|
int i;
|
|
|
|
for(i=0,tmp = Scrn.modePool;i<SupportedModes;i++,tmp=tmp->next)
|
|
{
|
|
if( (mode->width == tmp->CrtcHDisplay) &&
|
|
(mode->height == tmp->CrtcVDisplay) &&
|
|
(mode->freq == (short)__builtin_ceilf(tmp->VRefresh)))
|
|
{
|
|
Scrn.virtualX = mode->width ;
|
|
Scrn.virtualY = mode->height;
|
|
Scrn.displayWidth = mode->width;
|
|
rhdModeInit(&Scrn,tmp);
|
|
sysSetScreen(mode->width,mode->height);
|
|
dbgprintf("set_mode OK\n");
|
|
return 1;
|
|
};
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
#define API_VERSION 0x01000100
|
|
|
|
#define SRV_GETVERSION 0
|
|
#define SRV_ENUM_MODES 1
|
|
#define SRV_SET_MODE 2
|
|
|
|
int _stdcall srv_proc(ioctl_t *io)
|
|
{
|
|
u32_t *inp;
|
|
u32_t *outp;
|
|
|
|
inp = io->input;
|
|
outp = io->output;
|
|
|
|
switch(io->io_code)
|
|
{
|
|
case SRV_GETVERSION:
|
|
if(io->out_size==4)
|
|
{
|
|
*(u32_t*)io->output = API_VERSION;
|
|
return 0;
|
|
}
|
|
break;
|
|
case SRV_ENUM_MODES:
|
|
if(io->inp_size==8)
|
|
{
|
|
int count;
|
|
count = get_modes((mode_t*)(*inp),(int)*(inp+1));
|
|
|
|
if(io->out_size==4)
|
|
{
|
|
*outp = count;
|
|
return 0;
|
|
}
|
|
};
|
|
break;
|
|
case SRV_SET_MODE:
|
|
if(io->inp_size==8)
|
|
{
|
|
int err;
|
|
err = set_mode((mode_t*)inp);
|
|
|
|
if(io->out_size==4)
|
|
{
|
|
*outp = err;
|
|
return 0;
|
|
}
|
|
};
|
|
break;
|
|
|
|
};
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
CARD32
|
|
_RHDReadMC(int scrnIndex, CARD32 addr)
|
|
{
|
|
RHDPtr rhdPtr = (RHDPtr)scrnIndex;
|
|
CARD32 ret;
|
|
|
|
if (rhdPtr->ChipSet < RHD_RS600) {
|
|
_RHDRegWrite(rhdPtr, MC_IND_INDEX, addr);
|
|
ret = _RHDRegRead(rhdPtr, MC_IND_DATA);
|
|
} else if (rhdPtr->ChipSet == RHD_RS600) {
|
|
_RHDRegWrite(rhdPtr, RS60_MC_NB_MC_INDEX, addr);
|
|
ret = _RHDRegRead(rhdPtr, RS60_MC_NB_MC_DATA);
|
|
} else if (rhdPtr->ChipSet == RHD_RS690 || rhdPtr->ChipSet == RHD_RS740) {
|
|
pciWriteLong(rhdPtr->NBPciTag, RS69_MC_INDEX, addr & ~RS69_MC_IND_WR_EN);
|
|
ret = pciReadLong(rhdPtr->NBPciTag, RS69_MC_DATA);
|
|
} else {
|
|
pciWriteLong(rhdPtr->NBPciTag, RS78_NB_MC_IND_INDEX, (addr & ~RS78_MC_IND_WR_EN));
|
|
ret = pciReadLong(rhdPtr->NBPciTag, RS78_NB_MC_IND_DATA);
|
|
}
|
|
|
|
RHDDebug(scrnIndex,"%s(0x%08X) = 0x%08X\n",__func__,(unsigned int)addr,
|
|
(unsigned int)ret);
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
_RHDWriteMC(int scrnIndex, CARD32 addr, CARD32 data)
|
|
{
|
|
RHDPtr rhdPtr = (RHDPtr)scrnIndex;
|
|
|
|
RHDDebug(scrnIndex,"%s(0x%08X, 0x%08X)\n",__func__,(unsigned int)addr,
|
|
(unsigned int)data);
|
|
|
|
if (rhdPtr->ChipSet < RHD_RS600) {
|
|
_RHDRegWrite(rhdPtr, MC_IND_INDEX, addr | MC_IND_WR_EN);
|
|
_RHDRegWrite(rhdPtr, MC_IND_DATA, data);
|
|
} else if (rhdPtr->ChipSet == RHD_RS600) {
|
|
_RHDRegWrite(rhdPtr, RS60_MC_NB_MC_INDEX, addr | RS60_NB_MC_IND_WR_EN);
|
|
_RHDRegWrite(rhdPtr, RS60_MC_NB_MC_DATA, data);
|
|
} else if (rhdPtr->ChipSet == RHD_RS690 || rhdPtr->ChipSet == RHD_RS740) {
|
|
pciWriteLong(rhdPtr->NBPciTag, RS69_MC_INDEX, addr | RS69_MC_IND_WR_EN);
|
|
pciWriteLong(rhdPtr->NBPciTag, RS69_MC_DATA, data);
|
|
} else {
|
|
pciWriteLong(rhdPtr->NBPciTag, RS78_NB_MC_IND_INDEX, addr | RS78_MC_IND_WR_EN);
|
|
pciWriteLong(rhdPtr->NBPciTag, RS78_NB_MC_IND_DATA, data);
|
|
}
|
|
}
|
|
|
|
/*
|
|
*
|
|
*/
|
|
static void
|
|
rhdGetIGPNorthBridgeInfo(RHDPtr rhdPtr)
|
|
{
|
|
switch (rhdPtr->ChipSet)
|
|
{
|
|
case RHD_RS600:
|
|
break;
|
|
case RHD_RS690:
|
|
case RHD_RS740:
|
|
case RHD_RS780:
|
|
rhdPtr->NBPciTag = pciTag(0,0,0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static enum rhdCardType
|
|
rhdGetCardType(RHDPtr rhdPtr)
|
|
{
|
|
CARD32 cmd_stat;
|
|
|
|
if (rhdPtr->ChipSet == RHD_RS780)
|
|
return RHD_CARD_PCIE;
|
|
|
|
cmd_stat = pciReadLong(rhdPtr->PciTag, PCI_CMD_STAT_REG);
|
|
|
|
if (cmd_stat & 0x100000) {
|
|
CARD32 cap_ptr, cap_id;
|
|
|
|
cap_ptr = pciReadLong(rhdPtr->PciTag, 0x34);
|
|
cap_ptr &= 0xfc;
|
|
|
|
while (cap_ptr)
|
|
{
|
|
cap_id = pciReadLong(rhdPtr->PciTag, cap_ptr);
|
|
switch (cap_id & 0xff) {
|
|
case RHD_PCI_CAPID_AGP:
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "AGP Card Detected\n");
|
|
return RHD_CARD_AGP;
|
|
case RHD_PCI_CAPID_PCIE:
|
|
xf86DrvMsg(rhdPtr->scrnIndex, X_INFO, "PCIE Card Detected\n");
|
|
return RHD_CARD_PCIE;
|
|
}
|
|
cap_ptr = (cap_id >> 8) & 0xff;
|
|
}
|
|
}
|
|
return RHD_CARD_NONE;
|
|
}
|
|
|
|
|