summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--sys/dev/agp/agp.c121
-rw-r--r--sys/pci/agp.c121
-rw-r--r--sys/sys/agpio.h28
3 files changed, 239 insertions, 31 deletions
diff --git a/sys/dev/agp/agp.c b/sys/dev/agp/agp.c
index ba0eae8..7bf49b2 100644
--- a/sys/dev/agp/agp.c
+++ b/sys/dev/agp/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)
{
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)
{
diff --git a/sys/sys/agpio.h b/sys/sys/agpio.h
index c2b8c9a..8c1294f 100644
--- a/sys/sys/agpio.h
+++ b/sys/sys/agpio.h
@@ -42,20 +42,38 @@
* FW = Fast Writes
*/
#define AGP_MODE_GET_RQ(x) (((x) & 0xff000000U) >> 24)
+#define AGP_MODE_GET_ARQSZ(x) (((x) & 0x0000e000U) >> 13)
+#define AGP_MODE_GET_CAL(x) (((x) & 0x00001c00U) >> 10)
#define AGP_MODE_GET_SBA(x) (((x) & 0x00000200U) >> 9)
#define AGP_MODE_GET_AGP(x) (((x) & 0x00000100U) >> 8)
-#define AGP_MODE_GET_4G(x) (((x) & 0x00000020U) >> 5)
+#define AGP_MODE_GET_GART_64(x) (((x) & 0x00000080U) >> 7)
+#define AGP_MODE_GET_OVER_4G(x) (((x) & 0x00000020U) >> 5)
#define AGP_MODE_GET_FW(x) (((x) & 0x00000010U) >> 4)
+#define AGP_MODE_GET_MODE_3(x) (((x) & 0x00000008U) >> 3)
#define AGP_MODE_GET_RATE(x) ((x) & 0x00000007U)
#define AGP_MODE_SET_RQ(x,v) (((x) & ~0xff000000U) | ((v) << 24))
+#define AGP_MODE_SET_ARQSZ(x,v) (((x) & ~0x0000e000U) | ((v) << 13))
+#define AGP_MODE_SET_CAL(x,v) (((x) & ~0x00001c00U) | ((v) << 10))
#define AGP_MODE_SET_SBA(x,v) (((x) & ~0x00000200U) | ((v) << 9))
#define AGP_MODE_SET_AGP(x,v) (((x) & ~0x00000100U) | ((v) << 8))
-#define AGP_MODE_SET_4G(x,v) (((x) & ~0x00000020U) | ((v) << 5))
+#define AGP_MODE_SET_GART_64(x,v) (((x) & ~0x00000080U) | ((v) << 7))
+#define AGP_MODE_SET_OVER_4G(x,v) (((x) & ~0x00000020U) | ((v) << 5))
#define AGP_MODE_SET_FW(x,v) (((x) & ~0x00000010U) | ((v) << 4))
+#define AGP_MODE_SET_MODE_3(x,v) (((x) & ~0x00000008U) | ((v) << 3))
#define AGP_MODE_SET_RATE(x,v) (((x) & ~0x00000007U) | (v))
-#define AGP_MODE_RATE_1x 0x00000001
-#define AGP_MODE_RATE_2x 0x00000002
-#define AGP_MODE_RATE_4x 0x00000004
+#define AGP_MODE_V2_RATE_1x 0x00000001
+#define AGP_MODE_V2_RATE_2x 0x00000002
+#define AGP_MODE_V2_RATE_4x 0x00000004
+#define AGP_MODE_V3_RATE_4x 0x00000001
+#define AGP_MODE_V3_RATE_8x 0x00000002
+#define AGP_MODE_V3_RATE_RSVD 0x00000004
+
+/* XXX: Compat */
+#define AGP_MODE_GET_4G(x) AGP_MODE_GET_OVER_4G(x)
+#define AGP_MODE_SET_4G(x) AGP_MODE_SET_OVER_4G(x)
+#define AGP_MODE_RATE_1x AGP_MODE_V2_RATE_1x
+#define AGP_MODE_RATE_2x AGP_MODE_V2_RATE_2x
+#define AGP_MODE_RATE_4x AGP_MODE_V2_RATE_4x
#define AGPIOC_BASE 'A'
#define AGPIOC_INFO _IOR (AGPIOC_BASE, 0, agp_info)
OpenPOWER on IntegriCloud