kolibrios-fun/drivers/video/agp/agp.c
Sergey Semyonov (Serge) fb8dc89b4d move drivers from programs/system/drivers into /drivers
git-svn-id: svn://kolibrios.org@1029 a494cfbc-eb01-0410-851d-a64ba20cac60
2009-02-11 06:52:01 +00:00

603 lines
16 KiB
C

#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"