FreeBSD/Linux Kernel Cross Reference
sys/pci/agp_via.c
1 /*-
2 * Copyright (c) 2000 Doug Rabson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: releng/5.3/sys/pci/agp_via.c 134195 2004-08-23 05:23:16Z imp $");
29
30 #include "opt_bus.h"
31 #ifndef PC98
32 #include "opt_agp.h"
33 #endif
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/kernel.h>
39 #include <sys/module.h>
40 #include <sys/bus.h>
41 #include <sys/lock.h>
42 #include <sys/mutex.h>
43 #include <sys/proc.h>
44
45 #include <dev/pci/pcivar.h>
46 #include <dev/pci/pcireg.h>
47 #include <pci/agppriv.h>
48 #include <pci/agpreg.h>
49
50 #include <vm/vm.h>
51 #include <vm/vm_object.h>
52 #include <vm/pmap.h>
53
54 #define REG_GARTCTRL 0
55 #define REG_APSIZE 1
56 #define REG_ATTBASE 2
57
58 struct agp_via_softc {
59 struct agp_softc agp;
60 u_int32_t initial_aperture; /* aperture size at startup */
61 struct agp_gatt *gatt;
62 int *regs;
63 };
64
65 static int via_v2_regs[] = { AGP_VIA_GARTCTRL, AGP_VIA_APSIZE,
66 AGP_VIA_ATTBASE };
67 static int via_v3_regs[] = { AGP3_VIA_GARTCTRL, AGP3_VIA_APSIZE,
68 AGP3_VIA_ATTBASE };
69
70 static const char*
71 agp_via_match(device_t dev)
72 {
73 if (pci_get_class(dev) != PCIC_BRIDGE
74 || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
75 return NULL;
76
77 if (agp_find_caps(dev) == 0)
78 return NULL;
79
80 switch (pci_get_devid(dev)) {
81 case 0x03051106:
82 return ("VIA 82C8363 (Apollo KT133A) host to PCI bridge");
83 case 0x05011106:
84 return ("VIA 8501 (Apollo MVP4) host to PCI bridge");
85 case 0x05971106:
86 return ("VIA 82C597 (Apollo VP3) host to PCI bridge");
87 case 0x05981106:
88 return ("VIA 82C598 (Apollo MVP3) host to PCI bridge");
89 case 0x06051106:
90 return ("VIA 82C694X (Apollo Pro 133A) host to PCI bridge");
91 case 0x06911106:
92 return ("VIA 82C691 (Apollo Pro) host to PCI bridge");
93 case 0x31881106:
94 #if defined(__amd64__) || defined(AGP_AMD64_GART)
95 return NULL;
96 #else
97 return ("VIA 8385 host to PCI bridge");
98 #endif
99 case 0x31891106:
100 return ("VIA 8377 (Apollo KT400/KT400A/KT600) host to PCI bridge");
101 };
102
103 if (pci_get_vendor(dev) == 0x1106)
104 return ("VIA Generic host to PCI bridge");
105
106 return NULL;
107 }
108
109 static int
110 agp_via_probe(device_t dev)
111 {
112 const char *desc;
113
114 if (resource_disabled("agp", device_get_unit(dev)))
115 return (ENXIO);
116 desc = agp_via_match(dev);
117 if (desc) {
118 device_verbose(dev);
119 device_set_desc(dev, desc);
120 return 0;
121 }
122
123 return ENXIO;
124 }
125
126 static int
127 agp_via_attach(device_t dev)
128 {
129 struct agp_via_softc *sc = device_get_softc(dev);
130 struct agp_gatt *gatt;
131 int error;
132 u_int32_t agpsel;
133
134 switch (pci_get_devid(dev)) {
135 #ifdef AGP_NO_AMD64_GART
136 case 0x31881106:
137 #endif
138 case 0x31891106:
139 /* The newer VIA chipsets will select the AGP version based on
140 * what AGP versions the card supports. We still have to
141 * program it using the v2 registers if it has chosen to use
142 * compatibility mode.
143 */
144 agpsel = pci_read_config(dev, AGP_VIA_AGPSEL, 1);
145 if ((agpsel & (1 << 1)) == 0)
146 sc->regs = via_v3_regs;
147 else
148 sc->regs = via_v2_regs;
149 break;
150 default:
151 sc->regs = via_v2_regs;
152 break;
153 }
154
155 error = agp_generic_attach(dev);
156 if (error)
157 return error;
158
159 sc->initial_aperture = AGP_GET_APERTURE(dev);
160
161 for (;;) {
162 gatt = agp_alloc_gatt(dev);
163 if (gatt)
164 break;
165
166 /*
167 * Probably contigmalloc failure. Try reducing the
168 * aperture so that the gatt size reduces.
169 */
170 if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
171 agp_generic_detach(dev);
172 return ENOMEM;
173 }
174 }
175 sc->gatt = gatt;
176
177 /* Install the gatt. */
178 pci_write_config(dev, sc->regs[REG_ATTBASE], gatt->ag_physical | 3, 4);
179
180 /* Enable the aperture. */
181 pci_write_config(dev, sc->regs[REG_GARTCTRL], 0x0f, 4);
182
183 return 0;
184 }
185
186 static int
187 agp_via_detach(device_t dev)
188 {
189 struct agp_via_softc *sc = device_get_softc(dev);
190 int error;
191
192 error = agp_generic_detach(dev);
193 if (error)
194 return error;
195
196 pci_write_config(dev, sc->regs[REG_GARTCTRL], 0, 4);
197 pci_write_config(dev, sc->regs[REG_ATTBASE], 0, 4);
198 AGP_SET_APERTURE(dev, sc->initial_aperture);
199 agp_free_gatt(sc->gatt);
200
201 return 0;
202 }
203
204 static u_int32_t
205 agp_via_get_aperture(device_t dev)
206 {
207 struct agp_via_softc *sc = device_get_softc(dev);
208 u_int32_t apsize;
209
210 apsize = pci_read_config(dev, sc->regs[REG_APSIZE], 1) & 0x1f;
211
212 /*
213 * The size is determined by the number of low bits of
214 * register APBASE which are forced to zero. The low 20 bits
215 * are always forced to zero and each zero bit in the apsize
216 * field just read forces the corresponding bit in the 27:20
217 * to be zero. We calculate the aperture size accordingly.
218 */
219 return (((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1;
220 }
221
222 static int
223 agp_via_set_aperture(device_t dev, u_int32_t aperture)
224 {
225 struct agp_via_softc *sc = device_get_softc(dev);
226 u_int32_t apsize;
227
228 /*
229 * Reverse the magic from get_aperture.
230 */
231 apsize = ((aperture - 1) >> 20) ^ 0xff;
232
233 /*
234 * Double check for sanity.
235 */
236 if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
237 return EINVAL;
238
239 pci_write_config(dev, sc->regs[REG_APSIZE], apsize, 1);
240
241 return 0;
242 }
243
244 static int
245 agp_via_bind_page(device_t dev, int offset, vm_offset_t physical)
246 {
247 struct agp_via_softc *sc = device_get_softc(dev);
248
249 if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
250 return EINVAL;
251
252 sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
253 return 0;
254 }
255
256 static int
257 agp_via_unbind_page(device_t dev, int offset)
258 {
259 struct agp_via_softc *sc = device_get_softc(dev);
260
261 if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
262 return EINVAL;
263
264 sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
265 return 0;
266 }
267
268 static void
269 agp_via_flush_tlb(device_t dev)
270 {
271 struct agp_via_softc *sc = device_get_softc(dev);
272
273 pci_write_config(dev, sc->regs[REG_GARTCTRL], 0x8f, 4);
274 pci_write_config(dev, sc->regs[REG_GARTCTRL], 0x0f, 4);
275 }
276
277 static device_method_t agp_via_methods[] = {
278 /* Device interface */
279 DEVMETHOD(device_probe, agp_via_probe),
280 DEVMETHOD(device_attach, agp_via_attach),
281 DEVMETHOD(device_detach, agp_via_detach),
282 DEVMETHOD(device_shutdown, bus_generic_shutdown),
283 DEVMETHOD(device_suspend, bus_generic_suspend),
284 DEVMETHOD(device_resume, bus_generic_resume),
285
286 /* AGP interface */
287 DEVMETHOD(agp_get_aperture, agp_via_get_aperture),
288 DEVMETHOD(agp_set_aperture, agp_via_set_aperture),
289 DEVMETHOD(agp_bind_page, agp_via_bind_page),
290 DEVMETHOD(agp_unbind_page, agp_via_unbind_page),
291 DEVMETHOD(agp_flush_tlb, agp_via_flush_tlb),
292 DEVMETHOD(agp_enable, agp_generic_enable),
293 DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory),
294 DEVMETHOD(agp_free_memory, agp_generic_free_memory),
295 DEVMETHOD(agp_bind_memory, agp_generic_bind_memory),
296 DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory),
297
298 { 0, 0 }
299 };
300
301 static driver_t agp_via_driver = {
302 "agp",
303 agp_via_methods,
304 sizeof(struct agp_via_softc),
305 };
306
307 static devclass_t agp_devclass;
308
309 DRIVER_MODULE(agp_via, pci, agp_via_driver, agp_devclass, 0, 0);
310 MODULE_DEPEND(agp_via, agp, 1, 1, 1);
311 MODULE_DEPEND(agp_via, pci, 1, 1, 1);
Cache object: 3ce4105cb28b576b3d56c43cb5a9b603
|