summaryrefslogtreecommitdiffstats
path: root/sys/pci
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2003-10-23 18:08:56 +0000
committerjhb <jhb@FreeBSD.org>2003-10-23 18:08:56 +0000
commit04bc71c638975ba3f42bb01b3696aae715321ff9 (patch)
tree51e38c43e7d232db640904ec2177def218eb2741 /sys/pci
parent3ec96cda402cf4e2cde5ccda7129fed098043061 (diff)
downloadFreeBSD-src-04bc71c638975ba3f42bb01b3696aae715321ff9.zip
FreeBSD-src-04bc71c638975ba3f42bb01b3696aae715321ff9.tar.gz
Add simple support for AGP 3.0 including enabling 8x mode. The simple
part of the support is that it still assumes one master and one target where as AGP 3.0 actually supports multiple devices on the bus. Submitted by: Keith Whitwell <keith@tungstengraphics.com> Sponsored by: The Weather Channel
Diffstat (limited to 'sys/pci')
-rw-r--r--sys/pci/agp.c121
1 files changed, 108 insertions, 13 deletions
diff --git a/sys/pci/agp.c b/sys/pci/agp.c
index ba0eae8..7bf49b2 100644
--- a/sys/pci/agp.c
+++ b/sys/pci/agp.c
@@ -278,18 +278,83 @@ agp_generic_detach(device_t dev)
return 0;
}
-int
-agp_generic_enable(device_t dev, u_int32_t mode)
+/*
+ * This does the enable logic for v3, with the same topology
+ * restrictions as in place for v2 -- one bus, one device on the bus.
+ */
+static int
+agp_v3_enable(device_t dev, device_t mdev, u_int32_t mode)
{
- device_t mdev = agp_find_display();
u_int32_t tstatus, mstatus;
u_int32_t command;
- int rq, sba, fw, rate;;
+ int rq, sba, fw, rate, arqsz, cal;
- if (!mdev) {
- AGP_DPF("can't find display\n");
- return ENXIO;
- }
+ tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
+ mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
+
+ /* Set RQ to the min of mode, tstatus and mstatus */
+ rq = AGP_MODE_GET_RQ(mode);
+ if (AGP_MODE_GET_RQ(tstatus) < rq)
+ rq = AGP_MODE_GET_RQ(tstatus);
+ if (AGP_MODE_GET_RQ(mstatus) < rq)
+ rq = AGP_MODE_GET_RQ(mstatus);
+
+ /*
+ * ARQSZ - Set the value to the maximum one.
+ * Don't allow the mode register to override values.
+ */
+ arqsz = AGP_MODE_GET_ARQSZ(mode);
+ if (AGP_MODE_GET_ARQSZ(tstatus) > rq)
+ rq = AGP_MODE_GET_ARQSZ(tstatus);
+ if (AGP_MODE_GET_ARQSZ(mstatus) > rq)
+ rq = AGP_MODE_GET_ARQSZ(mstatus);
+
+ /* Calibration cycle - don't allow override by mode register */
+ cal = AGP_MODE_GET_CAL(tstatus);
+ if (AGP_MODE_GET_CAL(mstatus) < cal)
+ cal = AGP_MODE_GET_CAL(mstatus);
+
+ /* SBA must be supported for AGP v3. */
+ sba = 1;
+
+ /* Set FW if all three support it. */
+ fw = (AGP_MODE_GET_FW(tstatus)
+ & AGP_MODE_GET_FW(mstatus)
+ & AGP_MODE_GET_FW(mode));
+
+ /* Figure out the max rate */
+ rate = (AGP_MODE_GET_RATE(tstatus)
+ & AGP_MODE_GET_RATE(mstatus)
+ & AGP_MODE_GET_RATE(mode));
+ if (rate & AGP_MODE_V3_RATE_8x)
+ rate = AGP_MODE_V3_RATE_8x;
+ else
+ rate = AGP_MODE_V3_RATE_4x;
+ if (bootverbose)
+ device_printf(dev, "Setting AGP v3 mode %d\n", rate * 4);
+
+ pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, 0, 4);
+
+ /* Construct the new mode word and tell the hardware */
+ command = AGP_MODE_SET_RQ(0, rq);
+ command = AGP_MODE_SET_ARQSZ(command, arqsz);
+ command = AGP_MODE_SET_CAL(command, cal);
+ command = AGP_MODE_SET_SBA(command, sba);
+ command = AGP_MODE_SET_FW(command, fw);
+ command = AGP_MODE_SET_RATE(command, rate);
+ command = AGP_MODE_SET_AGP(command, 1);
+ pci_write_config(dev, agp_find_caps(dev) + AGP_COMMAND, command, 4);
+ pci_write_config(mdev, agp_find_caps(mdev) + AGP_COMMAND, command, 4);
+
+ return 0;
+}
+
+static int
+agp_v2_enable(device_t dev, device_t mdev, u_int32_t mode)
+{
+ u_int32_t tstatus, mstatus;
+ u_int32_t command;
+ int rq, sba, fw, rate;
tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
@@ -315,12 +380,14 @@ agp_generic_enable(device_t dev, u_int32_t mode)
rate = (AGP_MODE_GET_RATE(tstatus)
& AGP_MODE_GET_RATE(mstatus)
& AGP_MODE_GET_RATE(mode));
- if (rate & AGP_MODE_RATE_4x)
- rate = AGP_MODE_RATE_4x;
- else if (rate & AGP_MODE_RATE_2x)
- rate = AGP_MODE_RATE_2x;
+ if (rate & AGP_MODE_V2_RATE_4x)
+ rate = AGP_MODE_V2_RATE_4x;
+ else if (rate & AGP_MODE_V2_RATE_2x)
+ rate = AGP_MODE_V2_RATE_2x;
else
- rate = AGP_MODE_RATE_1x;
+ rate = AGP_MODE_V2_RATE_1x;
+ if (bootverbose)
+ device_printf(dev, "Setting AGP v2 mode %d\n", rate);
/* Construct the new mode word and tell the hardware */
command = AGP_MODE_SET_RQ(0, rq);
@@ -334,6 +401,34 @@ agp_generic_enable(device_t dev, u_int32_t mode)
return 0;
}
+int
+agp_generic_enable(device_t dev, u_int32_t mode)
+{
+ device_t mdev = agp_find_display();
+ u_int32_t tstatus, mstatus;
+
+ if (!mdev) {
+ AGP_DPF("can't find display\n");
+ return ENXIO;
+ }
+
+ tstatus = pci_read_config(dev, agp_find_caps(dev) + AGP_STATUS, 4);
+ mstatus = pci_read_config(mdev, agp_find_caps(mdev) + AGP_STATUS, 4);
+
+ /*
+ * Check display and bridge for AGP v3 support. AGP v3 allows
+ * more variety in topology than v2, e.g. multiple AGP devices
+ * attached to one bridge, or multiple AGP bridges in one
+ * system. This doesn't attempt to address those situations,
+ * but should work fine for a classic single AGP slot system
+ * with AGP v3.
+ */
+ if (AGP_MODE_GET_MODE_3(tstatus) && AGP_MODE_GET_MODE_3(mstatus))
+ return (agp_v3_enable(dev, mdev, mode));
+ else
+ return (agp_v2_enable(dev, mdev, mode));
+}
+
struct agp_memory *
agp_generic_alloc_memory(device_t dev, int type, vm_size_t size)
{
OpenPOWER on IntegriCloud