diff --git a/sys/dev/agp/agp.c b/sys/dev/agp/agp.c index ba0eae8d614..7bf49b29c3c 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 ba0eae8d614..7bf49b29c3c 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 c2b8c9a835c..8c1294f6986 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)