482 lines
12 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 1990-2000 Microsoft Corporation
Module Name:
agpuma.c
Abstract:
This module maps all physical memory into the AGP address space. It is
used by the XBOX to simulate UMA.
--*/
// Nasty path, but there are only two files that need to make kernel calls.
#include <ntos.h>
#include <pci.h>
#include <ntddvdeo.h>
#include <ntagp.h>
#include <stdio.h>
#if defined(DBG)
#define RIP(msg) \
{ \
DbgPrint msg; \
DbgPrint("\n"); \
_asm { int 3 }; \
}
#else
#define RIP(msg) {}
#endif
//
// Conversions from APSIZE encoding to MB
//
#define AP_SIZE_4MB 0x3F
#define AP_SIZE_8MB 0x3E
#define AP_SIZE_16MB 0x3C
#define AP_SIZE_32MB 0x38
#define AP_SIZE_64MB 0x30
#define AP_SIZE_128MB 0x20
#define AP_SIZE_256MB 0x00
//
// Define the location of the GART aperture control registers
//
#define HOST_BUS 0
#define HOST_SLOT 0
//
// Define the location of the video card
//
#define CARD_BUS 1
#define CARD_SLOT 0
//
// Defines what mode we're using. If the hardware doesn't support this then
// we'll RIP.
//
#define AGP_APERTURE_SIZE AP_SIZE_64MB
#define AGP_APERTURE_BYTES (64*1024*1024)
#define AGP_APERTURE_BASE 0xF8000000
//
// Offsets for host the registers we need to poke directly.
//
#define APBASE_OFFSET 0x10 // Aperture Base Address
#define APSIZE_OFFSET 0xB4 // Aperture Size Register
#define AGPCTRL_OFFSET 0xB0 // AGP Control Register
#define ATTBASE_OFFSET 0xB8 // Aperture Translation Table Base
#define RDCR_OFFSET 0x51 // RDRAM Control register
#define AGPBCTRL_OFFSET 0xE8 // AGP buffer control register
//
// Define the layout of the hardware registers
//
typedef struct _AGPCTRL
{
ULONG FourXOverride:1; // forces AGP 2x mode
ULONG FastWriteEnable:1; // enables fast writes
ULONG Reserved1:5;
ULONG EnableGART:1; // enables the GART
ULONG Reserved2:24;
} AGPCTRL;
typedef struct _RDCR
{
UCHAR Reserved1:1;
UCHAR ApertureEnable:1; // enable AGP aperture
UCHAR Reserved2:4;
UCHAR PBS:1;
UCHAR Reserved3:1;
} RDCR;
//
// GART entry structure
//
typedef struct _GART_PTE
{
ULONG Valid : 1;
ULONG Reserved : 11;
ULONG Page : 20;
} GART_PTE, *PGART_PTE;
//
// Simple wrappers to make reading/writing host register values
// a little easier.
//
#define ReadHostRegister(_buf_, _offset_, _size_) \
\
ReadDeviceData(HOST_BUS, \
HOST_SLOT, \
(_buf_), \
(_offset_), \
(_size_));
#define WriteHostRegister(_buf_, _offset_, _size_) \
\
WriteDeviceData(HOST_BUS, \
HOST_SLOT, \
(_buf_), \
(_offset_), \
(_size_));
//============================================================================
// AGP Code
//============================================================================
//----------------------------------------------------------------------------
// Read data from a PCI device.
//
static ULONG ReadDeviceData(
ULONG Bus,
ULONG Slot,
PVOID Buffer,
ULONG Offset,
ULONG Length
)
{
ULONG Transferred;
Transferred = HalGetBusDataByOffset(PCIConfiguration,
Bus,
Slot,
Buffer,
Offset,
Length);
return (Transferred == Length);
}
//----------------------------------------------------------------------------
// Write data to a PCI device.
//
static void WriteDeviceData(
ULONG Bus,
ULONG Slot,
PVOID Buffer,
ULONG Offset,
ULONG Length
)
{
ULONG Transferred;
Transferred = HalSetBusDataByOffset(PCIConfiguration,
Bus,
Slot,
Buffer,
Offset,
Length);
ASSERT(Transferred == Length);
}
//----------------------------------------------------------------------------
// Walk an AGP device's configuration space to find a specific capability.
//
static UCHAR ReadAgpCapability(
ULONG Bus,
ULONG Slot,
PCI_AGP_CAPABILITY *Capability
)
{
PCI_COMMON_CONFIG Header;
UCHAR CapabilityOffset;
//
// Read the PCI common header to get the capabilities pointer
//
ReadDeviceData(Bus, Slot, &Header, 0, sizeof(PCI_COMMON_CONFIG));
//
// Check the Status register to see if this device supports capability lists.
// If not, it is not an AGP-compliant device.
//
if ((Header.Status & PCI_STATUS_CAPABILITIES_LIST) == 0)
{
RIP(("FindAgpCapability - Device does not support Capabilities list, not an AGP device"));
return 0;
}
//
// The device supports capability lists, find the AGP capabilities.
//
if ((Header.HeaderType & (~PCI_MULTIFUNCTION)) == PCI_BRIDGE_TYPE)
{
CapabilityOffset = Header.u.type1.CapabilitiesPtr;
}
else
{
ASSERT((Header.HeaderType & (~PCI_MULTIFUNCTION)) == PCI_DEVICE_TYPE);
CapabilityOffset = Header.u.type0.CapabilitiesPtr;
}
while (CapabilityOffset != 0)
{
//
// Read the Capability at this offset
//
ReadDeviceData(Bus, Slot, Capability, CapabilityOffset, sizeof(PCI_AGP_CAPABILITY));
// Find it?
if (Capability->Header.CapabilityID == PCI_CAPABILITY_ID_AGP)
{
break;
}
else
{
CapabilityOffset = Capability->Header.Next;
}
}
if (CapabilityOffset == 0)
{
// No AGP capability was found
RIP(("FindAgpCapability - Device does not have an AGP Capability entry, not an AGP device"));
return 0;
}
return CapabilityOffset;
}
//----------------------------------------------------------------------------
// Write a capability to a device.
//
static void WriteAgpCapability(
ULONG Bus,
ULONG Slot,
UCHAR CapabilityOffset,
PCI_AGP_CAPABILITY *Capability
)
{
// Write the new information.
WriteDeviceData(Bus,
Slot,
Capability,
CapabilityOffset,
sizeof(PCI_AGP_CAPABILITY));
}
//----------------------------------------------------------------------------
// Set up the hardware to talk to each other.
//
static void SetupAgp()
{
AGPCTRL agpctrl;
PCI_AGP_CAPABILITY HostCap;
PCI_AGP_CAPABILITY CardCap;
UCHAR HostCapOffset;
UCHAR CardCapOffset;
ULONG DataRate;
//
// Initialize the host to support fast writes.
//
ReadHostRegister(&agpctrl, AGPCTRL_OFFSET, sizeof(agpctrl));
agpctrl.FastWriteEnable = 1;
WriteHostRegister(&agpctrl, AGPCTRL_OFFSET, sizeof(agpctrl));
//
// Get the capabilities of both the host and the card.
//
HostCapOffset = ReadAgpCapability(HOST_BUS, HOST_SLOT, &HostCap);
CardCapOffset = ReadAgpCapability(CARD_BUS, CARD_SLOT, &CardCap);
//
// Check the data rate.
//
DataRate = HostCap.AGPStatus.Rate & CardCap.AGPStatus.Rate;
if (!(DataRate & PCI_AGP_RATE_4X))
{
RIP(("SetupAgp - Mainboard/graphic card does not support 4x AGP."));
}
//
// The current graphics card does not support sideband addressing. Note if
// this changes.
//
if (HostCap.AGPStatus.SideBandAddressing & CardCap.AGPStatus.SideBandAddressing)
{
RIP(("SetupAgp - Sideband addressing is now available."));
}
//
// Note if fast writes go away.
//
if (!(HostCap.AGPStatus.FastWrite & CardCap.AGPStatus.FastWrite))
{
RIP(("SetupAgp - Fast write are not available."));
}
//
// Enable the host first.
//
HostCap.AGPCommand.Rate = PCI_AGP_RATE_4X;
HostCap.AGPCommand.AGPEnable = 1;
HostCap.AGPCommand.SBAEnable = 0;
HostCap.AGPCommand.FastWriteEnable = 1;
HostCap.AGPCommand.FourGBEnable = 0;
WriteAgpCapability(HOST_BUS, HOST_SLOT, HostCapOffset, &HostCap);
//
// Now enable the card
//
CardCap.AGPCommand.Rate = PCI_AGP_RATE_4X;
CardCap.AGPCommand.AGPEnable = 1;
CardCap.AGPCommand.SBAEnable = 0;
CardCap.AGPCommand.FastWriteEnable = 1;
CardCap.AGPCommand.FourGBEnable = 0;
CardCap.AGPCommand.RequestQueueDepth = HostCap.AGPStatus.RequestQueueDepthMaximum;
WriteAgpCapability(CARD_BUS, CARD_SLOT, CardCapOffset, &CardCap);
}
//============================================================================
// GART code
//============================================================================
//----------------------------------------------------------------------------
// Initialize and enable the GART
//
static BOOLEAN SetupGART()
{
ULONG GartLength;
GART_PTE *Gart;
ULONG_PTR GartPhysical;
AGPCTRL agpctrl;
RDCR rdcr;
ULONG i;
#if DBG
ULONG ApBase;
UCHAR ApSize;
//
// Verity the current APBASE and APSIZE settings
//
ReadHostRegister(&ApBase, APBASE_OFFSET, sizeof(ApBase));
ReadHostRegister(&ApSize, APSIZE_OFFSET, sizeof(ApSize));
if (ApSize != AGP_APERTURE_SIZE)
{
RIP(("SetupGART - Bad aperture size."));
}
if ((ApBase & PCI_ADDRESS_MEMORY_ADDRESS_MASK) != AGP_APERTURE_BASE)
{
RIP(("SetupGART - Bad Aperature base."));
}
#endif DBG
//
// Try and get a chunk of contiguous memory big enough to map the
// entire aperture.
//
GartLength = BYTES_TO_PAGES(AGP_APERTURE_BYTES) * sizeof(GART_PTE);
Gart = MmAllocateContiguousMemorySpecifyCache(GartLength, 0, MAXULONG_PTR, 0, MmNonCached);
if (Gart == NULL)
{
RIP(("SetupGART - MmAllocateContiguousMemory failed\n"));
return FALSE;
}
//
// We successfully allocated a contiguous chunk of memory.
// It should be page aligned already.
//
ASSERT(((ULONG_PTR)Gart & (PAGE_SIZE - 1)) == 0);
//
// Get the physical address.
//
GartPhysical = MmGetPhysicalAddress(Gart);
//
// Initialize all the PTEs
//
for (i = 0; i < GartLength/sizeof(GART_PTE); i++)
{
Gart[i].Valid = 1;
Gart[i].Page = i;
}
//
// Update the configuration
//
WriteHostRegister(&GartPhysical, ATTBASE_OFFSET, sizeof(GartPhysical));
//
// Enable the gart apeture.
//
ReadHostRegister(&agpctrl, AGPCTRL_OFFSET, sizeof(agpctrl));
agpctrl.EnableGART = 1;
WriteHostRegister(&agpctrl, AGPCTRL_OFFSET, sizeof(agpctrl));
ReadHostRegister(&rdcr, RDCR_OFFSET, sizeof(RDCR));
rdcr.ApertureEnable = 1;
WriteHostRegister(&rdcr, RDCR_OFFSET, sizeof(RDCR));
return TRUE;
}
//============================================================================
// Main entrypoint
//============================================================================
//----------------------------------------------------------------------------
// Entrypoint for AGP initializes. Sets up all AGP stuff for both the host
// and the card.
//
BOOLEAN AgpUmaEnable()
{
SetupAgp();
if (!SetupGART())
{
return FALSE;
}
return TRUE;
}