agp_amd64.c revision 241856
1254885Sdumbbell/*-
2254885Sdumbbell * Copyright (c) 2004, 2005 Jung-uk Kim <jkim@FreeBSD.org>
3254885Sdumbbell * All rights reserved.
4254885Sdumbbell *
5254885Sdumbbell * Redistribution and use in source and binary forms, with or without
6254885Sdumbbell * modification, are permitted provided that the following conditions
7254885Sdumbbell * are met:
8254885Sdumbbell * 1. Redistributions of source code must retain the above copyright
9254885Sdumbbell *    notice, this list of conditions and the following disclaimer.
10254885Sdumbbell * 2. Redistributions in binary form must reproduce the above copyright
11254885Sdumbbell *    notice, this list of conditions and the following disclaimer in the
12254885Sdumbbell *    documentation and/or other materials provided with the distribution.
13254885Sdumbbell *
14254885Sdumbbell * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15254885Sdumbbell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16254885Sdumbbell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17254885Sdumbbell * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18254885Sdumbbell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19254885Sdumbbell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20254885Sdumbbell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21254885Sdumbbell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22254885Sdumbbell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23254885Sdumbbell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24254885Sdumbbell * SUCH DAMAGE.
25254885Sdumbbell */
26254885Sdumbbell
27254885Sdumbbell#include <sys/cdefs.h>
28254885Sdumbbell__FBSDID("$FreeBSD: head/sys/dev/agp/agp_amd64.c 241856 2012-10-22 03:41:14Z eadler $");
29254885Sdumbbell
30254885Sdumbbell#include "opt_bus.h"
31254885Sdumbbell
32254885Sdumbbell#include <sys/param.h>
33254885Sdumbbell#include <sys/systm.h>
34254885Sdumbbell#include <sys/malloc.h>
35254885Sdumbbell#include <sys/kernel.h>
36254885Sdumbbell#include <sys/module.h>
37254885Sdumbbell#include <sys/bus.h>
38254885Sdumbbell#include <sys/lock.h>
39254885Sdumbbell#include <sys/mutex.h>
40254885Sdumbbell#include <sys/proc.h>
41254885Sdumbbell
42254885Sdumbbell#include <dev/agp/agppriv.h>
43254885Sdumbbell#include <dev/agp/agpreg.h>
44254885Sdumbbell#include <dev/pci/pcivar.h>
45254885Sdumbbell#include <dev/pci/pcireg.h>
46254885Sdumbbell
47254885Sdumbbell#include <vm/vm.h>
48254885Sdumbbell#include <vm/vm_object.h>
49254885Sdumbbell#include <vm/pmap.h>
50254885Sdumbbell#include <machine/bus.h>
51254885Sdumbbell#include <machine/resource.h>
52254885Sdumbbell#include <sys/rman.h>
53254885Sdumbbell
54254885Sdumbbell/* XXX */
55254885Sdumbbellextern void pci_cfgregwrite(int, int, int, int, uint32_t, int);
56254885Sdumbbellextern uint32_t pci_cfgregread(int, int, int, int, int);
57254885Sdumbbell
58254885Sdumbbellstatic void agp_amd64_apbase_fixup(device_t);
59254885Sdumbbell
60254885Sdumbbellstatic void agp_amd64_uli_init(device_t);
61254885Sdumbbellstatic int agp_amd64_uli_set_aperture(device_t, uint32_t);
62254885Sdumbbell
63254885Sdumbbellstatic int agp_amd64_nvidia_match(uint16_t);
64254885Sdumbbellstatic void agp_amd64_nvidia_init(device_t);
65254885Sdumbbellstatic int agp_amd64_nvidia_set_aperture(device_t, uint32_t);
66254885Sdumbbell
67254885Sdumbbellstatic int agp_amd64_via_match(void);
68254885Sdumbbellstatic void agp_amd64_via_init(device_t);
69254885Sdumbbellstatic int agp_amd64_via_set_aperture(device_t, uint32_t);
70254885Sdumbbell
71254885SdumbbellMALLOC_DECLARE(M_AGP);
72254885Sdumbbell
73254885Sdumbbell#define	AMD64_MAX_MCTRL		8
74254885Sdumbbell
75254885Sdumbbellstruct agp_amd64_softc {
76254885Sdumbbell	struct agp_softc	agp;
77254885Sdumbbell	uint32_t		initial_aperture;
78254885Sdumbbell	struct agp_gatt		*gatt;
79254885Sdumbbell	uint32_t		apbase;
80254885Sdumbbell	int			mctrl[AMD64_MAX_MCTRL];
81254885Sdumbbell	int			n_mctrl;
82254885Sdumbbell	int			via_agp;
83254885Sdumbbell};
84254885Sdumbbell
85254885Sdumbbellstatic const char*
86254885Sdumbbellagp_amd64_match(device_t dev)
87254885Sdumbbell{
88254885Sdumbbell	if (pci_get_class(dev) != PCIC_BRIDGE ||
89254885Sdumbbell	    pci_get_subclass(dev) != PCIS_BRIDGE_HOST ||
90254885Sdumbbell	    agp_find_caps(dev) == 0)
91254885Sdumbbell		return (NULL);
92254885Sdumbbell
93254885Sdumbbell	switch (pci_get_devid(dev)) {
94254885Sdumbbell	case 0x74541022:
95254885Sdumbbell		return ("AMD 8151 AGP graphics tunnel");
96254885Sdumbbell	case 0x07551039:
97254885Sdumbbell		return ("SiS 755 host to AGP bridge");
98254885Sdumbbell	case 0x07601039:
99254885Sdumbbell		return ("SiS 760 host to AGP bridge");
100254885Sdumbbell	case 0x168910b9:
101254885Sdumbbell		return ("ULi M1689 AGP Controller");
102254885Sdumbbell	case 0x00d110de:
103254885Sdumbbell		if (agp_amd64_nvidia_match(0x00d2))
104254885Sdumbbell			return (NULL);
105254885Sdumbbell		return ("NVIDIA nForce3 AGP Controller");
106254885Sdumbbell	case 0x00e110de:
107254885Sdumbbell		if (agp_amd64_nvidia_match(0x00e2))
108254885Sdumbbell			return (NULL);
109254885Sdumbbell		return ("NVIDIA nForce3-250 AGP Controller");
110254885Sdumbbell	case 0x02041106:
111254885Sdumbbell		return ("VIA 8380 host to PCI bridge");
112254885Sdumbbell	case 0x02381106:
113254885Sdumbbell		return ("VIA 3238 host to PCI bridge");
114254885Sdumbbell	case 0x02821106:
115254885Sdumbbell		return ("VIA K8T800Pro host to PCI bridge");
116254885Sdumbbell	case 0x31881106:
117254885Sdumbbell		return ("VIA 8385 host to PCI bridge");
118254885Sdumbbell	};
119254885Sdumbbell
120254885Sdumbbell	return (NULL);
121254885Sdumbbell}
122254885Sdumbbell
123254885Sdumbbellstatic int
124254885Sdumbbellagp_amd64_nvidia_match(uint16_t devid)
125254885Sdumbbell{
126254885Sdumbbell	/* XXX nForce3 requires secondary AGP bridge at 0:11:0. */
127254885Sdumbbell	if (pci_cfgregread(0, 11, 0, PCIR_CLASS, 1) != PCIC_BRIDGE ||
128254885Sdumbbell	    pci_cfgregread(0, 11, 0, PCIR_SUBCLASS, 1) != PCIS_BRIDGE_PCI ||
129254885Sdumbbell	    pci_cfgregread(0, 11, 0, PCIR_VENDOR, 2) != 0x10de ||
130254885Sdumbbell	    pci_cfgregread(0, 11, 0, PCIR_DEVICE, 2) != devid)
131254885Sdumbbell		return (ENXIO);
132254885Sdumbbell
133254885Sdumbbell	return (0);
134254885Sdumbbell}
135254885Sdumbbell
136254885Sdumbbellstatic int
137254885Sdumbbellagp_amd64_via_match(void)
138254885Sdumbbell{
139254885Sdumbbell	/* XXX Some VIA bridge requires secondary AGP bridge at 0:1:0. */
140254885Sdumbbell	if (pci_cfgregread(0, 1, 0, PCIR_CLASS, 1) != PCIC_BRIDGE ||
141254885Sdumbbell	    pci_cfgregread(0, 1, 0, PCIR_SUBCLASS, 1) != PCIS_BRIDGE_PCI ||
142254885Sdumbbell	    pci_cfgregread(0, 1, 0, PCIR_VENDOR, 2) != 0x1106 ||
143254885Sdumbbell	    pci_cfgregread(0, 1, 0, PCIR_DEVICE, 2) != 0xb188 ||
144254885Sdumbbell	    (pci_cfgregread(0, 1, 0, AGP_VIA_AGPSEL, 1) & 2))
145254885Sdumbbell		return (0);
146254885Sdumbbell
147254885Sdumbbell	return (1);
148254885Sdumbbell}
149254885Sdumbbell
150254885Sdumbbellstatic int
151254885Sdumbbellagp_amd64_probe(device_t dev)
152254885Sdumbbell{
153254885Sdumbbell	const char *desc;
154254885Sdumbbell
155254885Sdumbbell	if ((desc = agp_amd64_match(dev))) {
156254885Sdumbbell		device_set_desc(dev, desc);
157254885Sdumbbell		return (BUS_PROBE_DEFAULT);
158254885Sdumbbell	}
159254885Sdumbbell
160254885Sdumbbell	return (ENXIO);
161254885Sdumbbell}
162254885Sdumbbell
163254885Sdumbbellstatic int
164254885Sdumbbellagp_amd64_attach(device_t dev)
165254885Sdumbbell{
166254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
167254885Sdumbbell	struct agp_gatt *gatt;
168254885Sdumbbell	uint32_t devid;
169254885Sdumbbell	int i, n, error;
170254885Sdumbbell
171254885Sdumbbell	for (i = 0, n = 0; i < PCI_SLOTMAX && n < AMD64_MAX_MCTRL; i++) {
172254885Sdumbbell		devid = pci_cfgregread(0, i, 3, 0, 4);
173254885Sdumbbell		if (devid == 0x11031022 || devid == 0x12031022) {
174254885Sdumbbell			sc->mctrl[n] = i;
175254885Sdumbbell			n++;
176254885Sdumbbell		}
177254885Sdumbbell	}
178254885Sdumbbell	if (n == 0)
179254885Sdumbbell		return (ENXIO);
180254885Sdumbbell
181254885Sdumbbell	sc->n_mctrl = n;
182254885Sdumbbell
183254885Sdumbbell	if (bootverbose)
184254885Sdumbbell		device_printf(dev, "%d Miscellaneous Control unit(s) found.\n",
185254885Sdumbbell		    sc->n_mctrl);
186254885Sdumbbell
187254885Sdumbbell	if ((error = agp_generic_attach(dev)))
188254885Sdumbbell		return (error);
189254885Sdumbbell
190254885Sdumbbell	sc->initial_aperture = AGP_GET_APERTURE(dev);
191254885Sdumbbell
192254885Sdumbbell	for (;;) {
193254885Sdumbbell		gatt = agp_alloc_gatt(dev);
194254885Sdumbbell		if (gatt)
195254885Sdumbbell			break;
196254885Sdumbbell
197254885Sdumbbell		/*
198254885Sdumbbell		 * Probably contigmalloc failure. Try reducing the
199254885Sdumbbell		 * aperture so that the gatt size reduces.
200254885Sdumbbell		 */
201254885Sdumbbell		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
202254885Sdumbbell			agp_generic_detach(dev);
203254885Sdumbbell			return (ENOMEM);
204254885Sdumbbell		}
205254885Sdumbbell	}
206254885Sdumbbell	sc->gatt = gatt;
207254885Sdumbbell
208254885Sdumbbell	switch (pci_get_vendor(dev)) {
209254885Sdumbbell	case 0x10b9:	/* ULi */
210254885Sdumbbell		agp_amd64_uli_init(dev);
211254885Sdumbbell		if (agp_amd64_uli_set_aperture(dev, sc->initial_aperture))
212254885Sdumbbell			return (ENXIO);
213254885Sdumbbell		break;
214254885Sdumbbell
215254885Sdumbbell	case 0x10de:	/* nVidia */
216254885Sdumbbell		agp_amd64_nvidia_init(dev);
217254885Sdumbbell		if (agp_amd64_nvidia_set_aperture(dev, sc->initial_aperture))
218254885Sdumbbell			return (ENXIO);
219254885Sdumbbell		break;
220254885Sdumbbell
221254885Sdumbbell	case 0x1106:	/* VIA */
222254885Sdumbbell		sc->via_agp = agp_amd64_via_match();
223254885Sdumbbell		if (sc->via_agp) {
224254885Sdumbbell			agp_amd64_via_init(dev);
225254885Sdumbbell			if (agp_amd64_via_set_aperture(dev,
226254885Sdumbbell			    sc->initial_aperture))
227254885Sdumbbell				return (ENXIO);
228254885Sdumbbell		}
229254885Sdumbbell		break;
230254885Sdumbbell	}
231254885Sdumbbell
232254885Sdumbbell	/* Install the gatt and enable aperture. */
233254885Sdumbbell	for (i = 0; i < sc->n_mctrl; i++) {
234254885Sdumbbell		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_ATTBASE,
235254885Sdumbbell		    (uint32_t)(gatt->ag_physical >> 8) & AGP_AMD64_ATTBASE_MASK,
236254885Sdumbbell		    4);
237254885Sdumbbell		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL,
238254885Sdumbbell		    (pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL, 4) |
239254885Sdumbbell		    AGP_AMD64_APCTRL_GARTEN) &
240254885Sdumbbell		    ~(AGP_AMD64_APCTRL_DISGARTCPU | AGP_AMD64_APCTRL_DISGARTIO),
241254885Sdumbbell		    4);
242254885Sdumbbell	}
243254885Sdumbbell
244254885Sdumbbell	agp_flush_cache();
245254885Sdumbbell
246254885Sdumbbell	return (0);
247254885Sdumbbell}
248254885Sdumbbell
249254885Sdumbbellstatic int
250254885Sdumbbellagp_amd64_detach(device_t dev)
251254885Sdumbbell{
252254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
253254885Sdumbbell	int i;
254254885Sdumbbell
255254885Sdumbbell	agp_free_cdev(dev);
256254885Sdumbbell
257254885Sdumbbell	for (i = 0; i < sc->n_mctrl; i++)
258254885Sdumbbell		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL,
259254885Sdumbbell		    pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL, 4) &
260254885Sdumbbell		    ~AGP_AMD64_APCTRL_GARTEN, 4);
261254885Sdumbbell
262254885Sdumbbell	AGP_SET_APERTURE(dev, sc->initial_aperture);
263254885Sdumbbell	agp_free_gatt(sc->gatt);
264254885Sdumbbell	agp_free_res(dev);
265254885Sdumbbell
266254885Sdumbbell	return (0);
267254885Sdumbbell}
268254885Sdumbbell
269254885Sdumbbellstatic uint32_t agp_amd64_table[] = {
270254885Sdumbbell	0x02000000,	/*   32 MB */
271254885Sdumbbell	0x04000000,	/*   64 MB */
272254885Sdumbbell	0x08000000,	/*  128 MB */
273254885Sdumbbell	0x10000000,	/*  256 MB */
274254885Sdumbbell	0x20000000,	/*  512 MB */
275254885Sdumbbell	0x40000000,	/* 1024 MB */
276254885Sdumbbell	0x80000000,	/* 2048 MB */
277254885Sdumbbell};
278254885Sdumbbell
279254885Sdumbbell#define AGP_AMD64_TABLE_SIZE \
280254885Sdumbbell	(sizeof(agp_amd64_table) / sizeof(agp_amd64_table[0]))
281254885Sdumbbell
282254885Sdumbbellstatic uint32_t
283254885Sdumbbellagp_amd64_get_aperture(device_t dev)
284254885Sdumbbell{
285254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
286254885Sdumbbell	uint32_t i;
287254885Sdumbbell
288254885Sdumbbell	i = (pci_cfgregread(0, sc->mctrl[0], 3, AGP_AMD64_APCTRL, 4) &
289254885Sdumbbell		AGP_AMD64_APCTRL_SIZE_MASK) >> 1;
290254885Sdumbbell
291254885Sdumbbell	if (i >= AGP_AMD64_TABLE_SIZE)
292254885Sdumbbell		return (0);
293254885Sdumbbell
294254885Sdumbbell	return (agp_amd64_table[i]);
295254885Sdumbbell}
296254885Sdumbbell
297254885Sdumbbellstatic int
298254885Sdumbbellagp_amd64_set_aperture(device_t dev, uint32_t aperture)
299254885Sdumbbell{
300254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
301254885Sdumbbell	uint32_t i;
302254885Sdumbbell	int j;
303254885Sdumbbell
304254885Sdumbbell	for (i = 0; i < AGP_AMD64_TABLE_SIZE; i++)
305254885Sdumbbell		if (agp_amd64_table[i] == aperture)
306254885Sdumbbell			break;
307254885Sdumbbell	if (i >= AGP_AMD64_TABLE_SIZE)
308254885Sdumbbell		return (EINVAL);
309254885Sdumbbell
310254885Sdumbbell	for (j = 0; j < sc->n_mctrl; j++)
311269790Ssbruno		pci_cfgregwrite(0, sc->mctrl[j], 3, AGP_AMD64_APCTRL,
312269790Ssbruno		    (pci_cfgregread(0, sc->mctrl[j], 3, AGP_AMD64_APCTRL, 4) &
313269790Ssbruno		    ~(AGP_AMD64_APCTRL_SIZE_MASK)) | (i << 1), 4);
314269790Ssbruno
315269790Ssbruno	switch (pci_get_vendor(dev)) {
316254885Sdumbbell	case 0x10b9:	/* ULi */
317254885Sdumbbell		return (agp_amd64_uli_set_aperture(dev, aperture));
318254885Sdumbbell		break;
319254885Sdumbbell
320254885Sdumbbell	case 0x10de:	/* nVidia */
321254885Sdumbbell		return (agp_amd64_nvidia_set_aperture(dev, aperture));
322254885Sdumbbell		break;
323254885Sdumbbell
324254885Sdumbbell	case 0x1106:	/* VIA */
325254885Sdumbbell		if (sc->via_agp)
326254885Sdumbbell			return (agp_amd64_via_set_aperture(dev, aperture));
327254885Sdumbbell		break;
328254885Sdumbbell	}
329254885Sdumbbell
330254885Sdumbbell	return (0);
331254885Sdumbbell}
332254885Sdumbbell
333254885Sdumbbellstatic int
334254885Sdumbbellagp_amd64_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical)
335254885Sdumbbell{
336254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
337254885Sdumbbell
338254885Sdumbbell	if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
339254885Sdumbbell		return (EINVAL);
340254885Sdumbbell
341254885Sdumbbell	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] =
342254885Sdumbbell	    (physical & 0xfffff000) | ((physical >> 28) & 0x00000ff0) | 3;
343254885Sdumbbell
344254885Sdumbbell	return (0);
345254885Sdumbbell}
346254885Sdumbbell
347254885Sdumbbellstatic int
348254885Sdumbbellagp_amd64_unbind_page(device_t dev, vm_offset_t offset)
349254885Sdumbbell{
350254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
351254885Sdumbbell
352254885Sdumbbell	if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
353254885Sdumbbell		return (EINVAL);
354254885Sdumbbell
355254885Sdumbbell	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
356254885Sdumbbell
357254885Sdumbbell	return (0);
358254885Sdumbbell}
359254885Sdumbbell
360254885Sdumbbellstatic void
361254885Sdumbbellagp_amd64_flush_tlb(device_t dev)
362254885Sdumbbell{
363254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
364254885Sdumbbell	int i;
365254885Sdumbbell
366254885Sdumbbell	for (i = 0; i < sc->n_mctrl; i++)
367254885Sdumbbell		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_CACHECTRL,
368254885Sdumbbell		    pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_CACHECTRL, 4) |
369254885Sdumbbell		    AGP_AMD64_CACHECTRL_INVGART, 4);
370254885Sdumbbell}
371254885Sdumbbell
372254885Sdumbbellstatic void
373254885Sdumbbellagp_amd64_apbase_fixup(device_t dev)
374254885Sdumbbell{
375254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
376254885Sdumbbell	uint32_t apbase;
377254885Sdumbbell	int i;
378254885Sdumbbell
379254885Sdumbbell	sc->apbase = rman_get_start(sc->agp.as_aperture);
380254885Sdumbbell	apbase = (sc->apbase >> 25) & AGP_AMD64_APBASE_MASK;
381254885Sdumbbell	for (i = 0; i < sc->n_mctrl; i++)
382254885Sdumbbell		pci_cfgregwrite(0, sc->mctrl[i], 3,
383254885Sdumbbell		    AGP_AMD64_APBASE, apbase, 4);
384254885Sdumbbell}
385254885Sdumbbell
386254885Sdumbbellstatic void
387254885Sdumbbellagp_amd64_uli_init(device_t dev)
388254885Sdumbbell{
389254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
390254885Sdumbbell
391254885Sdumbbell	agp_amd64_apbase_fixup(dev);
392254885Sdumbbell	pci_write_config(dev, AGP_AMD64_ULI_APBASE,
393254885Sdumbbell	    (pci_read_config(dev, AGP_AMD64_ULI_APBASE, 4) & 0x0000000f) |
394254885Sdumbbell	    sc->apbase, 4);
395254885Sdumbbell	pci_write_config(dev, AGP_AMD64_ULI_HTT_FEATURE, sc->apbase, 4);
396254885Sdumbbell}
397254885Sdumbbell
398254885Sdumbbellstatic int
399254885Sdumbbellagp_amd64_uli_set_aperture(device_t dev, uint32_t aperture)
400254885Sdumbbell{
401254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
402254885Sdumbbell
403254885Sdumbbell	switch (aperture) {
404254885Sdumbbell	case 0x02000000:	/*  32 MB */
405254885Sdumbbell	case 0x04000000:	/*  64 MB */
406254885Sdumbbell	case 0x08000000:	/* 128 MB */
407254885Sdumbbell	case 0x10000000:	/* 256 MB */
408254885Sdumbbell		break;
409254885Sdumbbell	default:
410254885Sdumbbell		return (EINVAL);
411254885Sdumbbell	}
412254885Sdumbbell
413254885Sdumbbell	pci_write_config(dev, AGP_AMD64_ULI_ENU_SCR,
414254885Sdumbbell	    sc->apbase + aperture - 1, 4);
415254885Sdumbbell
416254885Sdumbbell	return (0);
417254885Sdumbbell}
418254885Sdumbbell
419254885Sdumbbellstatic void
420254885Sdumbbellagp_amd64_nvidia_init(device_t dev)
421254885Sdumbbell{
422254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
423254885Sdumbbell
424254885Sdumbbell	agp_amd64_apbase_fixup(dev);
425254885Sdumbbell	pci_write_config(dev, AGP_AMD64_NVIDIA_0_APBASE,
426254885Sdumbbell	    (pci_read_config(dev, AGP_AMD64_NVIDIA_0_APBASE, 4) & 0x0000000f) |
427254885Sdumbbell	    sc->apbase, 4);
428254885Sdumbbell	pci_cfgregwrite(0, 11, 0, AGP_AMD64_NVIDIA_1_APBASE1, sc->apbase, 4);
429254885Sdumbbell	pci_cfgregwrite(0, 11, 0, AGP_AMD64_NVIDIA_1_APBASE2, sc->apbase, 4);
430254885Sdumbbell}
431254885Sdumbbell
432254885Sdumbbellstatic int
433254885Sdumbbellagp_amd64_nvidia_set_aperture(device_t dev, uint32_t aperture)
434254885Sdumbbell{
435254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
436254885Sdumbbell	uint32_t apsize;
437254885Sdumbbell
438254885Sdumbbell	switch (aperture) {
439254885Sdumbbell	case 0x02000000:	apsize = 0x0f;	break;	/*  32 MB */
440254885Sdumbbell	case 0x04000000:	apsize = 0x0e;	break;	/*  64 MB */
441254885Sdumbbell	case 0x08000000:	apsize = 0x0c;	break;	/* 128 MB */
442254885Sdumbbell	case 0x10000000:	apsize = 0x08;	break;	/* 256 MB */
443254885Sdumbbell	case 0x20000000:	apsize = 0x00;	break;	/* 512 MB */
444254885Sdumbbell	default:
445254885Sdumbbell		return (EINVAL);
446254885Sdumbbell	}
447254885Sdumbbell
448254885Sdumbbell	pci_cfgregwrite(0, 11, 0, AGP_AMD64_NVIDIA_1_APSIZE,
449254885Sdumbbell	    (pci_cfgregread(0, 11, 0, AGP_AMD64_NVIDIA_1_APSIZE, 4) &
450254885Sdumbbell	    0xfffffff0) | apsize, 4);
451254885Sdumbbell	pci_cfgregwrite(0, 11, 0, AGP_AMD64_NVIDIA_1_APLIMIT1,
452254885Sdumbbell	    sc->apbase + aperture - 1, 4);
453254885Sdumbbell	pci_cfgregwrite(0, 11, 0, AGP_AMD64_NVIDIA_1_APLIMIT2,
454254885Sdumbbell	    sc->apbase + aperture - 1, 4);
455254885Sdumbbell
456254885Sdumbbell	return (0);
457254885Sdumbbell}
458254885Sdumbbell
459254885Sdumbbellstatic void
460254885Sdumbbellagp_amd64_via_init(device_t dev)
461254885Sdumbbell{
462254885Sdumbbell	struct agp_amd64_softc *sc = device_get_softc(dev);
463254885Sdumbbell
464254885Sdumbbell	agp_amd64_apbase_fixup(dev);
465254885Sdumbbell	pci_cfgregwrite(0, 1, 0, AGP3_VIA_ATTBASE, sc->gatt->ag_physical, 4);
466254885Sdumbbell	pci_cfgregwrite(0, 1, 0, AGP3_VIA_GARTCTRL,
467254885Sdumbbell	    pci_cfgregread(0, 1, 0, AGP3_VIA_ATTBASE, 4) | 0x180, 4);
468254885Sdumbbell}
469254885Sdumbbell
470254885Sdumbbellstatic int
471254885Sdumbbellagp_amd64_via_set_aperture(device_t dev, uint32_t aperture)
472254885Sdumbbell{
473254885Sdumbbell	uint32_t apsize;
474254885Sdumbbell
475254885Sdumbbell	apsize = ((aperture - 1) >> 20) ^ 0xff;
476254885Sdumbbell	if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
477254885Sdumbbell		return (EINVAL);
478254885Sdumbbell	pci_cfgregwrite(0, 1, 0, AGP3_VIA_APSIZE, apsize, 1);
479254885Sdumbbell
480254885Sdumbbell	return (0);
481254885Sdumbbell}
482254885Sdumbbell
483254885Sdumbbellstatic device_method_t agp_amd64_methods[] = {
484254885Sdumbbell	/* Device interface */
485254885Sdumbbell	DEVMETHOD(device_probe,		agp_amd64_probe),
486254885Sdumbbell	DEVMETHOD(device_attach,	agp_amd64_attach),
487254885Sdumbbell	DEVMETHOD(device_detach,	agp_amd64_detach),
488254885Sdumbbell	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
489254885Sdumbbell	DEVMETHOD(device_suspend,	bus_generic_suspend),
490254885Sdumbbell	DEVMETHOD(device_resume,	bus_generic_resume),
491254885Sdumbbell
492254885Sdumbbell	/* AGP interface */
493254885Sdumbbell	DEVMETHOD(agp_get_aperture,	agp_amd64_get_aperture),
494254885Sdumbbell	DEVMETHOD(agp_set_aperture,	agp_amd64_set_aperture),
495254885Sdumbbell	DEVMETHOD(agp_bind_page,	agp_amd64_bind_page),
496254885Sdumbbell	DEVMETHOD(agp_unbind_page,	agp_amd64_unbind_page),
497254885Sdumbbell	DEVMETHOD(agp_flush_tlb,	agp_amd64_flush_tlb),
498254885Sdumbbell	DEVMETHOD(agp_enable,		agp_generic_enable),
499254885Sdumbbell	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
500254885Sdumbbell	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
501254885Sdumbbell	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
502254885Sdumbbell	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
503254885Sdumbbell
504254885Sdumbbell	{ 0, 0 }
505254885Sdumbbell};
506254885Sdumbbell
507254885Sdumbbellstatic driver_t agp_amd64_driver = {
508254885Sdumbbell	"agp",
509254885Sdumbbell	agp_amd64_methods,
510254885Sdumbbell	sizeof(struct agp_amd64_softc),
511254885Sdumbbell};
512254885Sdumbbell
513254885Sdumbbellstatic devclass_t agp_devclass;
514254885Sdumbbell
515254885SdumbbellDRIVER_MODULE(agp_amd64, hostb, agp_amd64_driver, agp_devclass, 0, 0);
516254885SdumbbellMODULE_DEPEND(agp_amd64, agp, 1, 1, 1);
517254885SdumbbellMODULE_DEPEND(agp_amd64, pci, 1, 1, 1);
518254885Sdumbbell