0,0 → 1,602 |
|
#include "types.h" |
#include "link.h" |
|
#include <stdio.h> |
#include <malloc.h> |
#include <memory.h> |
|
#include "pci.h" |
#include "agp.h" |
|
#include "syscall.h" |
|
|
agp_t *bridge; |
|
|
int __stdcall srv_agp(ioctl_t *io); |
|
|
u32_t __stdcall drvEntry(int action) |
{ |
u32_t retval; |
|
int i; |
|
if(action != 1) |
return 0; |
|
if(!dbg_open("/rd/1/drivers/agp.log")) |
{ |
printf("Can't open /rd/1/drivers/agp.log\nExit\n"); |
return 0; |
} |
|
if( FindPciDevice() == 0) |
{ |
dbgprintf("Device not found\n"); |
return 0; |
}; |
|
return 0; |
|
// retval = RegService("AGP", srv_2d); |
// dbgprintf("reg service %s as: %x\n", "HDRAW", retval); |
|
// return retval; |
}; |
|
|
#include "pci.inc" |
#include "isoch.inc" |
|
static void intel_8xx_tlbflush(void *mem) |
{ |
u32_t temp; |
|
temp = pciReadLong(bridge->PciTag, INTEL_AGPCTRL); |
pciWriteLong(bridge->PciTag, INTEL_AGPCTRL, temp & ~(1 << 7)); |
temp = pciReadLong(bridge->PciTag, INTEL_AGPCTRL); |
pciWriteLong(bridge->PciTag, INTEL_AGPCTRL, temp | (1 << 7)); |
} |
|
|
static aper_size_t intel_8xx_sizes[7] = |
{ |
{ 256, 65536, 64, 0 }, |
{ 128, 32768, 32, 32 }, |
{ 64, 16384, 16, 48 }, |
{ 32, 8192, 8, 56 }, |
{ 16, 4096, 4, 60 }, |
{ 8, 2048, 2, 62 }, |
{ 4, 1024, 1, 63 } |
}; |
|
|
|
static int intel_845_configure() |
{ |
u32_t temp; |
u8_t temp2; |
aper_size_t *current_size; |
|
current_size = bridge->current_size; |
|
/* aperture size */ |
pciWriteByte(bridge->PciTag, INTEL_APSIZE, current_size->size_value); |
|
dbgprintf("INTEL_APSIZE %d\n", current_size->size_value ); |
|
if (bridge->apbase_config != 0) |
{ |
pciWriteLong(bridge->PciTag, AGP_APBASE, bridge->apbase_config); |
} |
else |
{ |
/* address to map to */ |
temp = pciReadLong(bridge->PciTag, AGP_APBASE); |
bridge->gart_addr = (temp & PCI_MAP_MEMORY_ADDRESS_MASK); |
bridge->apbase_config = temp; |
} |
|
dbgprintf("AGP_APBASE %x\n", temp ); |
|
/* attbase - aperture base */ |
pciWriteLong(bridge->PciTag, INTEL_ATTBASE, bridge->gatt_dma); |
|
/* agpctrl */ |
pciWriteLong(bridge->PciTag, INTEL_AGPCTRL, 0x0000); |
|
/* agpm */ |
temp2 = pciReadByte(bridge->PciTag, INTEL_I845_AGPM); |
pciWriteByte(bridge->PciTag, INTEL_I845_AGPM, temp2 | (1 << 1)); |
/* clear any possible error conditions */ |
pciWriteWord(bridge->PciTag, INTEL_I845_ERRSTS, 0x001c); |
return 0; |
} |
|
|
int agp_generic_create_gatt_table() |
{ |
count_t pages; |
|
pages = bridge->current_size->pages_count; |
|
if( bridge->gatt_dma = AllocPages(pages)) |
{ |
if(bridge->gatt_table = |
(u32_t*)MapIoMem((void*)bridge->gatt_dma, |
pages<<12, PG_SW+PG_NOCACHE)) |
{ |
dbgprintf("gatt map %x at %x %d pages\n",bridge->gatt_dma , |
bridge->gatt_table, pages); |
|
/* AK: bogus, should encode addresses > 4GB */ |
|
u32_t volatile *table = bridge->gatt_table; |
|
count_t count = bridge->current_size->num_entries; |
|
while(count--) { /* FIXME memset */ |
addr_t tmp; |
|
*table = 0; |
table++; |
} |
return 1; |
}; |
}; |
dbgprintf("unable to get memory for " |
"graphics translation table.\n"); |
return 0; |
} |
|
|
static int __intel_8xx_fetch_size(u8_t temp) |
{ |
int i; |
aper_size_t *values; |
|
values = bridge->aperture_sizes; |
|
values = intel_8xx_sizes; |
|
for (i = 0; i < 7; i++) |
{ |
if (temp == values[i].size_value) |
{ |
bridge->previous_size = |
bridge->current_size = (void *) (values + i); |
bridge->aperture_size_idx = i; |
return values[i].size; |
} |
} |
return 0; |
} |
|
static int intel_8xx_fetch_size(void) |
{ |
u8_t temp; |
|
temp = pciReadByte(bridge->PciTag, INTEL_APSIZE); |
return __intel_8xx_fetch_size(temp); |
} |
|
|
int agp_bind_memory(addr_t agp_addr, addr_t dma_addr, size_t size) |
{ |
int ret_val; |
count_t count; |
|
// if (curr == NULL) |
// return -EINVAL; |
|
// if (curr->is_bound == TRUE) { |
// printk(KERN_INFO PFX "memory %p is already bound!\n", curr); |
// return -EINVAL; |
// } |
// if (curr->is_flushed == FALSE) { |
// curr->bridge->driver->cache_flush(); |
// curr->is_flushed = TRUE; |
// } |
// ret_val = curr->bridge->driver->insert_memory(curr, pg_start, curr->type); |
|
u32_t volatile *table = &bridge->gatt_table[agp_addr>>12]; |
|
count = size >> 12; |
|
dma_addr |= 0x00000017; |
|
while(count--) |
{ |
*table = dma_addr; |
table++; |
dma_addr+=4096; |
} |
|
bridge->tlb_flush(NULL); |
|
// if (ret_val != 0) |
// return ret_val; |
|
// curr->is_bound = TRUE; |
// curr->pg_start = pg_start; |
return 0; |
} |
|
void get_agp_version(agp_t *bridge) |
{ |
u32_t ncapid; |
|
/* Exit early if already set by errata workarounds. */ |
if (bridge->major_version != 0) |
return; |
|
ncapid = pciReadLong(bridge->PciTag, bridge->capndx); |
bridge->major_version = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf; |
bridge->minor_version = (ncapid >> AGP_MINOR_VERSION_SHIFT) & 0xf; |
} |
|
static void agp_v2_parse_one(u32_t *requested_mode, u32_t *bridge_agpstat, u32_t *vga_agpstat) |
{ |
u32_t tmp; |
|
if (*requested_mode & AGP2_RESERVED_MASK) { |
dbgprintf("reserved bits set (%x) in mode 0x%x. Fixed.\n", |
*requested_mode & AGP2_RESERVED_MASK, *requested_mode); |
*requested_mode &= ~AGP2_RESERVED_MASK; |
} |
|
/* Check the speed bits make sense. Only one should be set. */ |
tmp = *requested_mode & 7; |
switch (tmp) { |
case 0: |
dbgprintf("Setting to x1 mode.\n"); |
*requested_mode |= AGPSTAT2_1X; |
break; |
case 1: |
case 2: |
break; |
case 3: |
*requested_mode &= ~(AGPSTAT2_1X); /* rate=2 */ |
break; |
case 4: |
break; |
case 5: |
case 6: |
case 7: |
*requested_mode &= ~(AGPSTAT2_1X|AGPSTAT2_2X); /* rate=4*/ |
break; |
} |
|
/* disable SBA if it's not supported */ |
if (!((*bridge_agpstat & AGPSTAT_SBA) && (*vga_agpstat & AGPSTAT_SBA) && (*requested_mode & AGPSTAT_SBA))) |
*bridge_agpstat &= ~AGPSTAT_SBA; |
|
/* Set rate */ |
if (!((*bridge_agpstat & AGPSTAT2_4X) && (*vga_agpstat & AGPSTAT2_4X) && (*requested_mode & AGPSTAT2_4X))) |
*bridge_agpstat &= ~AGPSTAT2_4X; |
|
if (!((*bridge_agpstat & AGPSTAT2_2X) && (*vga_agpstat & AGPSTAT2_2X) && (*requested_mode & AGPSTAT2_2X))) |
*bridge_agpstat &= ~AGPSTAT2_2X; |
|
if (!((*bridge_agpstat & AGPSTAT2_1X) && (*vga_agpstat & AGPSTAT2_1X) && (*requested_mode & AGPSTAT2_1X))) |
*bridge_agpstat &= ~AGPSTAT2_1X; |
|
/* Now we know what mode it should be, clear out the unwanted bits. */ |
if (*bridge_agpstat & AGPSTAT2_4X) |
*bridge_agpstat &= ~(AGPSTAT2_1X | AGPSTAT2_2X); /* 4X */ |
|
if (*bridge_agpstat & AGPSTAT2_2X) |
*bridge_agpstat &= ~(AGPSTAT2_1X | AGPSTAT2_4X); /* 2X */ |
|
if (*bridge_agpstat & AGPSTAT2_1X) |
*bridge_agpstat &= ~(AGPSTAT2_2X | AGPSTAT2_4X); /* 1X */ |
|
/* Apply any errata. */ |
if (bridge->flags & AGP_ERRATA_FASTWRITES) |
*bridge_agpstat &= ~AGPSTAT_FW; |
|
if (bridge->flags & AGP_ERRATA_SBA) |
*bridge_agpstat &= ~AGPSTAT_SBA; |
|
if (bridge->flags & AGP_ERRATA_1X) { |
*bridge_agpstat &= ~(AGPSTAT2_2X | AGPSTAT2_4X); |
*bridge_agpstat |= AGPSTAT2_1X; |
} |
|
/* If we've dropped down to 1X, disable fast writes. */ |
if (*bridge_agpstat & AGPSTAT2_1X) |
*bridge_agpstat &= ~AGPSTAT_FW; |
} |
|
|
static void agp_v3_parse_one(u32_t *requested_mode, |
u32_t *bridge_agpstat, |
u32_t *vga_agpstat) |
{ |
u32_t origbridge = *bridge_agpstat, origvga = *vga_agpstat; |
u32_t tmp; |
|
if (*requested_mode & AGP3_RESERVED_MASK) |
{ |
dbgprintf("reserved bits set (%x) in mode 0x%x. Fixed.\n", |
*requested_mode & AGP3_RESERVED_MASK, *requested_mode); |
*requested_mode &= ~AGP3_RESERVED_MASK; |
} |
|
/* Check the speed bits make sense. */ |
tmp = *requested_mode & 7; |
if (tmp == 0) { |
dbgprintf("Setting to AGP3 x4 mode.\n"); |
*requested_mode |= AGPSTAT3_4X; |
} |
if (tmp >= 3) { |
dbgprintf("Setting to AGP3 x8 mode.\n"); |
*requested_mode = (*requested_mode & ~7) | AGPSTAT3_8X; |
} |
|
/* ARQSZ - Set the value to the maximum one. |
* Don't allow the mode register to override values. */ |
*bridge_agpstat = ((*bridge_agpstat & ~AGPSTAT_ARQSZ) | |
max_t(u32_t,(*bridge_agpstat & AGPSTAT_ARQSZ),(*vga_agpstat & AGPSTAT_ARQSZ))); |
|
/* Calibration cycle. |
* Don't allow the mode register to override values. */ |
*bridge_agpstat = ((*bridge_agpstat & ~AGPSTAT_CAL_MASK) | |
min_t(u32_t,(*bridge_agpstat & AGPSTAT_CAL_MASK),(*vga_agpstat & AGPSTAT_CAL_MASK))); |
|
/* SBA *must* be supported for AGP v3 */ |
*bridge_agpstat |= AGPSTAT_SBA; |
|
/* |
* Set speed. |
* Check for invalid speeds. This can happen when applications |
* written before the AGP 3.0 standard pass AGP2.x modes to AGP3 hardware |
*/ |
if (*requested_mode & AGPSTAT_MODE_3_0) { |
/* |
* Caller hasn't a clue what it is doing. Bridge is in 3.0 mode, |
* have been passed a 3.0 mode, but with 2.x speed bits set. |
* AGP2.x 4x -> AGP3.0 4x. |
*/ |
if (*requested_mode & AGPSTAT2_4X) { |
dbgprintf("broken AGP3 flags (%x). Fixed.\n", *requested_mode); |
*requested_mode &= ~AGPSTAT2_4X; |
*requested_mode |= AGPSTAT3_4X; |
} |
} else { |
/* |
* The caller doesn't know what they are doing. We are in 3.0 mode, |
* but have been passed an AGP 2.x mode. |
* Convert AGP 1x,2x,4x -> AGP 3.0 4x. |
*/ |
dbgprintf("broken AGP2 flags (%x) in AGP3 mode. Fixed.\n",*requested_mode); |
*requested_mode &= ~(AGPSTAT2_4X | AGPSTAT2_2X | AGPSTAT2_1X); |
*requested_mode |= AGPSTAT3_4X; |
} |
|
if (*requested_mode & AGPSTAT3_8X) { |
if (!(*bridge_agpstat & AGPSTAT3_8X)) { |
*bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); |
*bridge_agpstat |= AGPSTAT3_4X; |
dbgprintf("requested AGPx8 but bridge not capable.\n"); |
return; |
} |
if (!(*vga_agpstat & AGPSTAT3_8X)) { |
*bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); |
*bridge_agpstat |= AGPSTAT3_4X; |
dbgprintf("requested AGPx8 but graphic card not capable.\n"); |
return; |
} |
/* All set, bridge & device can do AGP x8*/ |
*bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD); |
goto done; |
|
} else { |
|
/* |
* If we didn't specify AGPx8, we can only do x4. |
* If the hardware can't do x4, we're up shit creek, and never |
* should have got this far. |
*/ |
*bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD); |
if ((*bridge_agpstat & AGPSTAT3_4X) && (*vga_agpstat & AGPSTAT3_4X)) |
*bridge_agpstat |= AGPSTAT3_4X; |
else { |
dbgprintf("Badness. Don't know which AGP mode to set. " |
"[bridge_agpstat:%x vga_agpstat:%x fell back to:- bridge_agpstat:%x vga_agpstat:%x]\n", |
origbridge, origvga, *bridge_agpstat, *vga_agpstat); |
if (!(*bridge_agpstat & AGPSTAT3_4X)) |
dbgprintf("Bridge couldn't do AGP x4.\n"); |
if (!(*vga_agpstat & AGPSTAT3_4X)) |
dbgprintf("Graphic card couldn't do AGP x4.\n"); |
return; |
} |
} |
|
done: |
/* Apply any errata. */ |
if (bridge->flags & AGP_ERRATA_FASTWRITES) |
*bridge_agpstat &= ~AGPSTAT_FW; |
|
if (bridge->flags & AGP_ERRATA_SBA) |
*bridge_agpstat &= ~AGPSTAT_SBA; |
|
if (bridge->flags & AGP_ERRATA_1X) { |
*bridge_agpstat &= ~(AGPSTAT2_2X | AGPSTAT2_4X); |
*bridge_agpstat |= AGPSTAT2_1X; |
} |
} |
|
|
u32_t agp_collect_device_status(agp_t *bridge, u32_t requested_mode, |
u32_t bridge_agpstat) |
{ |
PCITAG vgaTag; |
u32_t vga_agpstat; |
int cap_ptr; |
|
for (;;) |
{ |
vgaTag = pci_find_class(PCI_CLASS_DISPLAY_VGA); |
if (vgaTag == -1) |
{ |
dbgprintf("Couldn't find an AGP VGA controller.\n"); |
return 0; |
} |
cap_ptr = pci_find_capability(vgaTag, PCI_CAP_ID_AGP); |
if (cap_ptr) |
break; |
} |
|
/* |
* Ok, here we have a AGP device. Disable impossible |
* settings, and adjust the readqueue to the minimum. |
*/ |
vga_agpstat = pciReadLong(vgaTag, cap_ptr+PCI_AGP_STATUS); |
|
/* adjust RQ depth */ |
bridge_agpstat = ((bridge_agpstat & ~AGPSTAT_RQ_DEPTH) | |
min_t(u32_t, (requested_mode & AGPSTAT_RQ_DEPTH), |
min_t(u32_t, (bridge_agpstat & AGPSTAT_RQ_DEPTH), (vga_agpstat & AGPSTAT_RQ_DEPTH)))); |
|
/* disable FW if it's not supported */ |
if (!((bridge_agpstat & AGPSTAT_FW) && |
(vga_agpstat & AGPSTAT_FW) && |
(requested_mode & AGPSTAT_FW))) |
bridge_agpstat &= ~AGPSTAT_FW; |
|
/* Check to see if we are operating in 3.0 mode */ |
if (bridge->mode & AGPSTAT_MODE_3_0) |
agp_v3_parse_one(&requested_mode, &bridge_agpstat, &vga_agpstat); |
else |
agp_v2_parse_one(&requested_mode, &bridge_agpstat, &vga_agpstat); |
|
return bridge_agpstat; |
} |
|
|
void agp_device_command(u32_t bridge_agpstat, int agp_v3) |
{ |
PCITAG device = 0; |
int mode; |
|
mode = bridge_agpstat & 0x7; |
if (agp_v3) |
mode *= 4; |
|
for_each_pci_dev(device) |
{ |
int agp = pci_find_capability(device, PCI_CAP_ID_AGP); |
if (!agp) |
continue; |
|
dbgprintf("Putting AGP V%d device at into %dx mode\n", |
agp_v3 ? 3 : 2, mode); |
pciWriteLong(device, agp + PCI_AGP_COMMAND, bridge_agpstat); |
} |
} |
|
|
void agp_generic_enable(u32_t requested_mode) |
{ |
u32_t bridge_agpstat, temp; |
|
get_agp_version(bridge); |
|
dbgprintf("Found an AGP %d.%d compliant device.\n", |
bridge->major_version, bridge->minor_version); |
|
bridge_agpstat = pciReadLong(bridge->PciTag, |
bridge->capndx + PCI_AGP_STATUS); |
|
bridge_agpstat = agp_collect_device_status(bridge, requested_mode, bridge_agpstat); |
if (bridge_agpstat == 0) |
/* Something bad happened. FIXME: Return error code? */ |
return; |
|
bridge_agpstat |= AGPSTAT_AGP_ENABLE; |
|
/* Do AGP version specific frobbing. */ |
if (bridge->major_version >= 3) |
{ |
if (bridge->mode & AGPSTAT_MODE_3_0) |
{ |
/* If we have 3.5, we can do the isoch stuff. */ |
if (bridge->minor_version >= 5) |
agp_3_5_enable(bridge); |
agp_device_command(bridge_agpstat, TRUE); |
return; |
} |
else |
{ |
/* Disable calibration cycle in RX91<1> when not in AGP3.0 mode of operation.*/ |
bridge_agpstat &= ~(7<<10) ; |
temp = pciReadLong(bridge->PciTag, bridge->capndx+AGPCTRL); |
temp |= (1<<9); |
pciWriteLong(bridge->PciTag, bridge->capndx+AGPCTRL, temp); |
|
dbgprintf("Device is in legacy mode," |
" falling back to 2.x\n"); |
} |
} |
|
/* AGP v<3 */ |
agp_device_command(bridge_agpstat, FALSE); |
} |
|
|
static agp_t intel_845_driver = |
{ |
.aperture_sizes = intel_8xx_sizes, |
// .size_type = U8_APER_SIZE, |
// .num_aperture_sizes = 7, |
.configure = intel_845_configure, |
.fetch_size = intel_8xx_fetch_size, |
// .cleanup = intel_8xx_cleanup, |
.tlb_flush = intel_8xx_tlbflush, |
// .mask_memory = agp_generic_mask_memory, |
// .masks = intel_generic_masks, |
// .agp_enable = agp_generic_enable, |
// .cache_flush = global_cache_flush, |
.create_gatt_table = agp_generic_create_gatt_table, |
// .free_gatt_table = agp_generic_free_gatt_table, |
// .insert_memory = agp_generic_insert_memory, |
// .remove_memory = agp_generic_remove_memory, |
// .alloc_by_type = agp_generic_alloc_by_type, |
// .free_by_type = agp_generic_free_by_type, |
// .agp_alloc_page = agp_generic_alloc_page, |
// .agp_destroy_page = agp_generic_destroy_page, |
}; |
|
int init_bridge(PCITAG pciTag) |
{ |
size_t size_value; |
|
bridge = &intel_845_driver; |
|
bridge->PciTag = pciTag; |
|
bridge->capndx = pci_find_capability(pciTag, PCI_CAP_ID_AGP); |
|
size_value = bridge->fetch_size(); |
|
if (size_value == 0) { |
dbgprintf("unable to determine aperture size.\n"); |
return 0; |
}; |
|
dbgprintf("fetch size = %x\n", size_value); |
|
if( bridge->create_gatt_table() ) |
{ |
bridge->configure(); |
return 1; |
} |
return 0; |
} |
|
|
#include "detect.inc" |