Commit | Line | Data |
---|---|---|
aa4cc5d2 BS |
1 | #include <linux/module.h> |
2 | ||
cb75d97e | 3 | #include "nouveau_drm.h" |
aa4cc5d2 | 4 | #include "nouveau_agp.h" |
cb75d97e | 5 | #include "nouveau_reg.h" |
aa4cc5d2 BS |
6 | |
7 | #if __OS_HAS_AGP | |
8 | MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)"); | |
9 | static int nouveau_agpmode = -1; | |
10 | module_param_named(agpmode, nouveau_agpmode, int, 0400); | |
11 | ||
fd34381b IM |
12 | struct nouveau_agpmode_quirk { |
13 | u16 hostbridge_vendor; | |
14 | u16 hostbridge_device; | |
15 | u16 chip_vendor; | |
16 | u16 chip_device; | |
17 | int mode; | |
18 | }; | |
19 | ||
20 | static struct nouveau_agpmode_quirk nouveau_agpmode_quirk_list[] = { | |
21 | /* VIA Apollo PRO133x / GeForce FX 5600 Ultra, max agpmode 2, fdo #20341 */ | |
22 | { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 }, | |
23 | ||
24 | {}, | |
25 | }; | |
26 | ||
aa4cc5d2 | 27 | static unsigned long |
fd34381b | 28 | get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info) |
aa4cc5d2 | 29 | { |
967e7bde | 30 | struct nvif_device *device = &drm->device; |
fd34381b IM |
31 | struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list; |
32 | int agpmode = nouveau_agpmode; | |
33 | unsigned long mode = info->mode; | |
aa4cc5d2 BS |
34 | |
35 | /* | |
36 | * FW seems to be broken on nv18, it makes the card lock up | |
37 | * randomly. | |
38 | */ | |
967e7bde | 39 | if (device->info.chipset == 0x18) |
aa4cc5d2 BS |
40 | mode &= ~PCI_AGP_COMMAND_FW; |
41 | ||
fd34381b IM |
42 | /* |
43 | * Go through the quirks list and adjust the agpmode accordingly. | |
44 | */ | |
45 | while (agpmode == -1 && quirk->hostbridge_vendor) { | |
46 | if (info->id_vendor == quirk->hostbridge_vendor && | |
47 | info->id_device == quirk->hostbridge_device && | |
989aa5b7 BS |
48 | nvxx_device(device)->pdev->vendor == quirk->chip_vendor && |
49 | nvxx_device(device)->pdev->device == quirk->chip_device) { | |
fd34381b | 50 | agpmode = quirk->mode; |
fa2bade9 | 51 | NV_INFO(drm, "Forcing agp mode to %dX. Use agpmode to override.\n", |
fd34381b IM |
52 | agpmode); |
53 | break; | |
54 | } | |
55 | ++quirk; | |
56 | } | |
57 | ||
aa4cc5d2 BS |
58 | /* |
59 | * AGP mode set in the command line. | |
60 | */ | |
fd34381b | 61 | if (agpmode > 0) { |
aa4cc5d2 | 62 | bool agpv3 = mode & 0x8; |
fd34381b | 63 | int rate = agpv3 ? agpmode / 4 : agpmode; |
aa4cc5d2 BS |
64 | |
65 | mode = (mode & ~0x7) | (rate & 0x7); | |
66 | } | |
67 | ||
68 | return mode; | |
69 | } | |
70 | ||
71 | static bool | |
cb75d97e | 72 | nouveau_agp_enabled(struct nouveau_drm *drm) |
aa4cc5d2 | 73 | { |
cb75d97e | 74 | struct drm_device *dev = drm->dev; |
aa4cc5d2 | 75 | |
420b9469 | 76 | if (!dev->pdev || !drm_pci_device_is_agp(dev) || !dev->agp) |
aa4cc5d2 BS |
77 | return false; |
78 | ||
cb75d97e | 79 | if (drm->agp.stat == UNKNOWN) { |
aa4cc5d2 BS |
80 | if (!nouveau_agpmode) |
81 | return false; | |
650e1203 FJ |
82 | #ifdef __powerpc__ |
83 | /* Disable AGP by default on all PowerPC machines for | |
84 | * now -- At least some UniNorth-2 AGP bridges are | |
85 | * known to be broken: DMA from the host to the card | |
86 | * works just fine, but writeback from the card to the | |
87 | * host goes straight to memory untranslated bypassing | |
88 | * the GATT somehow, making them quite painful to deal | |
89 | * with... | |
90 | */ | |
91 | if (nouveau_agpmode == -1) | |
92 | return false; | |
93 | #endif | |
cb75d97e | 94 | return true; |
aa4cc5d2 BS |
95 | } |
96 | ||
cb75d97e | 97 | return (drm->agp.stat == ENABLED); |
aa4cc5d2 BS |
98 | } |
99 | #endif | |
100 | ||
101 | void | |
cb75d97e | 102 | nouveau_agp_reset(struct nouveau_drm *drm) |
aa4cc5d2 BS |
103 | { |
104 | #if __OS_HAS_AGP | |
a01ca78c | 105 | struct nvif_object *device = &drm->device.object; |
cb75d97e | 106 | struct drm_device *dev = drm->dev; |
aa4cc5d2 BS |
107 | u32 save[2]; |
108 | int ret; | |
109 | ||
cb75d97e | 110 | if (!nouveau_agp_enabled(drm)) |
aa4cc5d2 BS |
111 | return; |
112 | ||
113 | /* First of all, disable fast writes, otherwise if it's | |
114 | * already enabled in the AGP bridge and we disable the card's | |
115 | * AGP controller we might be locking ourselves out of it. */ | |
db2bec18 | 116 | if ((nvif_rd32(device, NV04_PBUS_PCI_NV_19) | |
aa4cc5d2 BS |
117 | dev->agp->mode) & PCI_AGP_COMMAND_FW) { |
118 | struct drm_agp_info info; | |
119 | struct drm_agp_mode mode; | |
120 | ||
121 | ret = drm_agp_info(dev, &info); | |
122 | if (ret) | |
123 | return; | |
124 | ||
fd34381b | 125 | mode.mode = get_agp_mode(drm, &info); |
aa4cc5d2 BS |
126 | mode.mode &= ~PCI_AGP_COMMAND_FW; |
127 | ||
128 | ret = drm_agp_enable(dev, mode); | |
129 | if (ret) | |
130 | return; | |
131 | } | |
132 | ||
133 | ||
134 | /* clear busmaster bit, and disable AGP */ | |
db2bec18 BS |
135 | save[0] = nvif_mask(device, NV04_PBUS_PCI_NV_1, 0x00000004, 0x00000000); |
136 | nvif_wr32(device, NV04_PBUS_PCI_NV_19, 0); | |
aa4cc5d2 BS |
137 | |
138 | /* reset PGRAPH, PFIFO and PTIMER */ | |
db2bec18 BS |
139 | save[1] = nvif_mask(device, 0x000200, 0x00011100, 0x00000000); |
140 | nvif_mask(device, 0x000200, 0x00011100, save[1]); | |
aa4cc5d2 BS |
141 | |
142 | /* and restore bustmaster bit (gives effect of resetting AGP) */ | |
db2bec18 | 143 | nvif_wr32(device, NV04_PBUS_PCI_NV_1, save[0]); |
aa4cc5d2 BS |
144 | #endif |
145 | } | |
146 | ||
147 | void | |
cb75d97e | 148 | nouveau_agp_init(struct nouveau_drm *drm) |
aa4cc5d2 BS |
149 | { |
150 | #if __OS_HAS_AGP | |
cb75d97e | 151 | struct drm_device *dev = drm->dev; |
aa4cc5d2 BS |
152 | struct drm_agp_info info; |
153 | struct drm_agp_mode mode; | |
154 | int ret; | |
155 | ||
cb75d97e | 156 | if (!nouveau_agp_enabled(drm)) |
aa4cc5d2 | 157 | return; |
cb75d97e | 158 | drm->agp.stat = DISABLE; |
aa4cc5d2 BS |
159 | |
160 | ret = drm_agp_acquire(dev); | |
161 | if (ret) { | |
fa2bade9 | 162 | NV_ERROR(drm, "unable to acquire AGP: %d\n", ret); |
aa4cc5d2 BS |
163 | return; |
164 | } | |
165 | ||
166 | ret = drm_agp_info(dev, &info); | |
167 | if (ret) { | |
fa2bade9 | 168 | NV_ERROR(drm, "unable to get AGP info: %d\n", ret); |
aa4cc5d2 BS |
169 | return; |
170 | } | |
171 | ||
172 | /* see agp.h for the AGPSTAT_* modes available */ | |
fd34381b | 173 | mode.mode = get_agp_mode(drm, &info); |
aa4cc5d2 BS |
174 | |
175 | ret = drm_agp_enable(dev, mode); | |
176 | if (ret) { | |
fa2bade9 | 177 | NV_ERROR(drm, "unable to enable AGP: %d\n", ret); |
aa4cc5d2 BS |
178 | return; |
179 | } | |
180 | ||
cb75d97e BS |
181 | drm->agp.stat = ENABLED; |
182 | drm->agp.base = info.aperture_base; | |
183 | drm->agp.size = info.aperture_size; | |
aa4cc5d2 BS |
184 | #endif |
185 | } | |
186 | ||
187 | void | |
cb75d97e | 188 | nouveau_agp_fini(struct nouveau_drm *drm) |
aa4cc5d2 BS |
189 | { |
190 | #if __OS_HAS_AGP | |
cb75d97e | 191 | struct drm_device *dev = drm->dev; |
aa4cc5d2 BS |
192 | if (dev->agp && dev->agp->acquired) |
193 | drm_agp_release(dev); | |
194 | #endif | |
195 | } |