agp_amd64.c revision 241885
1133852Sobrien/*-
2150645Sjkim * Copyright (c) 2004, 2005 Jung-uk Kim <jkim@FreeBSD.org>
3133852Sobrien * All rights reserved.
4133852Sobrien *
5133852Sobrien * Redistribution and use in source and binary forms, with or without
6133852Sobrien * modification, are permitted provided that the following conditions
7133852Sobrien * are met:
8133852Sobrien * 1. Redistributions of source code must retain the above copyright
9133852Sobrien *    notice, this list of conditions and the following disclaimer.
10133852Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11133852Sobrien *    notice, this list of conditions and the following disclaimer in the
12133852Sobrien *    documentation and/or other materials provided with the distribution.
13133852Sobrien *
14133852Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15133852Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16133852Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17133852Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18133852Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19133852Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20133852Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21133852Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22133852Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23133852Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24133852Sobrien * SUCH DAMAGE.
25133852Sobrien */
26133852Sobrien
27133852Sobrien#include <sys/cdefs.h>
28133852Sobrien__FBSDID("$FreeBSD: head/sys/dev/agp/agp_amd64.c 241885 2012-10-22 13:06:09Z eadler $");
29133852Sobrien
30133852Sobrien#include "opt_bus.h"
31133852Sobrien
32133852Sobrien#include <sys/param.h>
33133852Sobrien#include <sys/systm.h>
34133852Sobrien#include <sys/malloc.h>
35133852Sobrien#include <sys/kernel.h>
36133852Sobrien#include <sys/module.h>
37133852Sobrien#include <sys/bus.h>
38133852Sobrien#include <sys/lock.h>
39133852Sobrien#include <sys/mutex.h>
40133852Sobrien#include <sys/proc.h>
41133852Sobrien
42173573Sjhb#include <dev/agp/agppriv.h>
43173573Sjhb#include <dev/agp/agpreg.h>
44133852Sobrien#include <dev/pci/pcivar.h>
45133852Sobrien#include <dev/pci/pcireg.h>
46133852Sobrien
47133852Sobrien#include <vm/vm.h>
48133852Sobrien#include <vm/vm_object.h>
49133852Sobrien#include <vm/pmap.h>
50133852Sobrien#include <machine/bus.h>
51133852Sobrien#include <machine/resource.h>
52133852Sobrien#include <sys/rman.h>
53133852Sobrien
54133852Sobrien/* XXX */
55133852Sobrienextern void pci_cfgregwrite(int, int, int, int, uint32_t, int);
56133852Sobrienextern uint32_t pci_cfgregread(int, int, int, int, int);
57133852Sobrien
58150645Sjkimstatic void agp_amd64_apbase_fixup(device_t);
59150645Sjkim
60150645Sjkimstatic void agp_amd64_uli_init(device_t);
61150645Sjkimstatic int agp_amd64_uli_set_aperture(device_t, uint32_t);
62150645Sjkim
63150645Sjkimstatic int agp_amd64_nvidia_match(uint16_t);
64150645Sjkimstatic void agp_amd64_nvidia_init(device_t);
65150645Sjkimstatic int agp_amd64_nvidia_set_aperture(device_t, uint32_t);
66150645Sjkim
67152435Sjkimstatic int agp_amd64_via_match(void);
68152435Sjkimstatic void agp_amd64_via_init(device_t);
69152435Sjkimstatic int agp_amd64_via_set_aperture(device_t, uint32_t);
70152435Sjkim
71133852SobrienMALLOC_DECLARE(M_AGP);
72133852Sobrien
73133852Sobrien#define	AMD64_MAX_MCTRL		8
74133852Sobrien
75133852Sobrienstruct agp_amd64_softc {
76133852Sobrien	struct agp_softc	agp;
77150645Sjkim	uint32_t		initial_aperture;
78150645Sjkim	struct agp_gatt		*gatt;
79150645Sjkim	uint32_t		apbase;
80150645Sjkim	int			mctrl[AMD64_MAX_MCTRL];
81150645Sjkim	int			n_mctrl;
82152435Sjkim	int			via_agp;
83133852Sobrien};
84133852Sobrien
85133852Sobrienstatic const char*
86133852Sobrienagp_amd64_match(device_t dev)
87133852Sobrien{
88163181Sjkim	if (pci_get_class(dev) != PCIC_BRIDGE ||
89163181Sjkim	    pci_get_subclass(dev) != PCIS_BRIDGE_HOST ||
90163181Sjkim	    agp_find_caps(dev) == 0)
91163181Sjkim		return (NULL);
92133852Sobrien
93133852Sobrien	switch (pci_get_devid(dev)) {
94133852Sobrien	case 0x74541022:
95133852Sobrien		return ("AMD 8151 AGP graphics tunnel");
96141885Sanholt	case 0x07551039:
97133852Sobrien		return ("SiS 755 host to AGP bridge");
98159075Sjkim	case 0x07601039:
99159075Sjkim		return ("SiS 760 host to AGP bridge");
100150645Sjkim	case 0x168910b9:
101150645Sjkim		return ("ULi M1689 AGP Controller");
102144517Sobrien	case 0x00d110de:
103150645Sjkim		if (agp_amd64_nvidia_match(0x00d2))
104163181Sjkim			return (NULL);
105144517Sobrien		return ("NVIDIA nForce3 AGP Controller");
106144809Sobrien	case 0x00e110de:
107150645Sjkim		if (agp_amd64_nvidia_match(0x00e2))
108163181Sjkim			return (NULL);
109144809Sobrien		return ("NVIDIA nForce3-250 AGP Controller");
110133852Sobrien	case 0x02041106:
111133852Sobrien		return ("VIA 8380 host to PCI bridge");
112150645Sjkim	case 0x02381106:
113150645Sjkim		return ("VIA 3238 host to PCI bridge");
114136133Sanholt	case 0x02821106:
115136133Sanholt		return ("VIA K8T800Pro host to PCI bridge");
116133852Sobrien	case 0x31881106:
117133852Sobrien		return ("VIA 8385 host to PCI bridge");
118133852Sobrien	};
119133852Sobrien
120163181Sjkim	return (NULL);
121133852Sobrien}
122133852Sobrien
123133852Sobrienstatic int
124150645Sjkimagp_amd64_nvidia_match(uint16_t devid)
125150645Sjkim{
126150645Sjkim	/* XXX nForce3 requires secondary AGP bridge at 0:11:0. */
127150645Sjkim	if (pci_cfgregread(0, 11, 0, PCIR_CLASS, 1) != PCIC_BRIDGE ||
128150645Sjkim	    pci_cfgregread(0, 11, 0, PCIR_SUBCLASS, 1) != PCIS_BRIDGE_PCI ||
129150645Sjkim	    pci_cfgregread(0, 11, 0, PCIR_VENDOR, 2) != 0x10de ||
130150645Sjkim	    pci_cfgregread(0, 11, 0, PCIR_DEVICE, 2) != devid)
131163181Sjkim		return (ENXIO);
132150645Sjkim
133163181Sjkim	return (0);
134150645Sjkim}
135150645Sjkim
136150645Sjkimstatic int
137152435Sjkimagp_amd64_via_match(void)
138152435Sjkim{
139152435Sjkim	/* XXX Some VIA bridge requires secondary AGP bridge at 0:1:0. */
140152435Sjkim	if (pci_cfgregread(0, 1, 0, PCIR_CLASS, 1) != PCIC_BRIDGE ||
141152435Sjkim	    pci_cfgregread(0, 1, 0, PCIR_SUBCLASS, 1) != PCIS_BRIDGE_PCI ||
142152435Sjkim	    pci_cfgregread(0, 1, 0, PCIR_VENDOR, 2) != 0x1106 ||
143152435Sjkim	    pci_cfgregread(0, 1, 0, PCIR_DEVICE, 2) != 0xb188 ||
144152435Sjkim	    (pci_cfgregread(0, 1, 0, AGP_VIA_AGPSEL, 1) & 2))
145163181Sjkim		return (0);
146152435Sjkim
147163181Sjkim	return (1);
148152435Sjkim}
149152435Sjkim
150152435Sjkimstatic int
151133852Sobrienagp_amd64_probe(device_t dev)
152133852Sobrien{
153133852Sobrien	const char *desc;
154133852Sobrien
155241885Seadler	if (resource_disabled("agp", device_get_unit(dev)))
156241885Seadler		return (ENXIO);
157133852Sobrien	if ((desc = agp_amd64_match(dev))) {
158133852Sobrien		device_set_desc(dev, desc);
159163181Sjkim		return (BUS_PROBE_DEFAULT);
160133852Sobrien	}
161133852Sobrien
162163181Sjkim	return (ENXIO);
163133852Sobrien}
164133852Sobrien
165133852Sobrienstatic int
166133852Sobrienagp_amd64_attach(device_t dev)
167133852Sobrien{
168133852Sobrien	struct agp_amd64_softc *sc = device_get_softc(dev);
169133852Sobrien	struct agp_gatt *gatt;
170187100Sjkim	uint32_t devid;
171133852Sobrien	int i, n, error;
172133852Sobrien
173187100Sjkim	for (i = 0, n = 0; i < PCI_SLOTMAX && n < AMD64_MAX_MCTRL; i++) {
174187100Sjkim		devid = pci_cfgregread(0, i, 3, 0, 4);
175187100Sjkim		if (devid == 0x11031022 || devid == 0x12031022) {
176133852Sobrien			sc->mctrl[n] = i;
177133852Sobrien			n++;
178133852Sobrien		}
179187100Sjkim	}
180133852Sobrien	if (n == 0)
181163181Sjkim		return (ENXIO);
182133852Sobrien
183133852Sobrien	sc->n_mctrl = n;
184133852Sobrien
185161518Sjkim	if (bootverbose)
186150645Sjkim		device_printf(dev, "%d Miscellaneous Control unit(s) found.\n",
187150645Sjkim		    sc->n_mctrl);
188133852Sobrien
189133852Sobrien	if ((error = agp_generic_attach(dev)))
190163181Sjkim		return (error);
191133852Sobrien
192133852Sobrien	sc->initial_aperture = AGP_GET_APERTURE(dev);
193133852Sobrien
194133852Sobrien	for (;;) {
195133852Sobrien		gatt = agp_alloc_gatt(dev);
196133852Sobrien		if (gatt)
197133852Sobrien			break;
198133852Sobrien
199133852Sobrien		/*
200133852Sobrien		 * Probably contigmalloc failure. Try reducing the
201133852Sobrien		 * aperture so that the gatt size reduces.
202133852Sobrien		 */
203133852Sobrien		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
204133852Sobrien			agp_generic_detach(dev);
205163181Sjkim			return (ENOMEM);
206133852Sobrien		}
207133852Sobrien	}
208133852Sobrien	sc->gatt = gatt;
209133852Sobrien
210152435Sjkim	switch (pci_get_vendor(dev)) {
211152435Sjkim	case 0x10b9:	/* ULi */
212152435Sjkim		agp_amd64_uli_init(dev);
213152435Sjkim		if (agp_amd64_uli_set_aperture(dev, sc->initial_aperture))
214163181Sjkim			return (ENXIO);
215152435Sjkim		break;
216152435Sjkim
217152435Sjkim	case 0x10de:	/* nVidia */
218152435Sjkim		agp_amd64_nvidia_init(dev);
219152435Sjkim		if (agp_amd64_nvidia_set_aperture(dev, sc->initial_aperture))
220163181Sjkim			return (ENXIO);
221152435Sjkim		break;
222152435Sjkim
223152435Sjkim	case 0x1106:	/* VIA */
224152435Sjkim		sc->via_agp = agp_amd64_via_match();
225152435Sjkim		if (sc->via_agp) {
226152435Sjkim			agp_amd64_via_init(dev);
227152435Sjkim			if (agp_amd64_via_set_aperture(dev,
228152435Sjkim			    sc->initial_aperture))
229163181Sjkim				return (ENXIO);
230152435Sjkim		}
231152435Sjkim		break;
232152435Sjkim	}
233152435Sjkim
234133852Sobrien	/* Install the gatt and enable aperture. */
235133852Sobrien	for (i = 0; i < sc->n_mctrl; i++) {
236133852Sobrien		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_ATTBASE,
237133852Sobrien		    (uint32_t)(gatt->ag_physical >> 8) & AGP_AMD64_ATTBASE_MASK,
238133852Sobrien		    4);
239133852Sobrien		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL,
240133852Sobrien		    (pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL, 4) |
241133852Sobrien		    AGP_AMD64_APCTRL_GARTEN) &
242133852Sobrien		    ~(AGP_AMD64_APCTRL_DISGARTCPU | AGP_AMD64_APCTRL_DISGARTIO),
243133852Sobrien		    4);
244133852Sobrien	}
245133852Sobrien
246133852Sobrien	agp_flush_cache();
247133852Sobrien
248163181Sjkim	return (0);
249133852Sobrien}
250133852Sobrien
251133852Sobrienstatic int
252133852Sobrienagp_amd64_detach(device_t dev)
253133852Sobrien{
254133852Sobrien	struct agp_amd64_softc *sc = device_get_softc(dev);
255173203Sjhb	int i;
256133852Sobrien
257173203Sjhb	agp_free_cdev(dev);
258133852Sobrien
259133852Sobrien	for (i = 0; i < sc->n_mctrl; i++)
260133852Sobrien		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL,
261133852Sobrien		    pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_APCTRL, 4) &
262133852Sobrien		    ~AGP_AMD64_APCTRL_GARTEN, 4);
263133852Sobrien
264133852Sobrien	AGP_SET_APERTURE(dev, sc->initial_aperture);
265133852Sobrien	agp_free_gatt(sc->gatt);
266173203Sjhb	agp_free_res(dev);
267133852Sobrien
268163181Sjkim	return (0);
269133852Sobrien}
270133852Sobrien
271133852Sobrienstatic uint32_t agp_amd64_table[] = {
272133852Sobrien	0x02000000,	/*   32 MB */
273133852Sobrien	0x04000000,	/*   64 MB */
274133852Sobrien	0x08000000,	/*  128 MB */
275133852Sobrien	0x10000000,	/*  256 MB */
276133852Sobrien	0x20000000,	/*  512 MB */
277133852Sobrien	0x40000000,	/* 1024 MB */
278133852Sobrien	0x80000000,	/* 2048 MB */
279133852Sobrien};
280133852Sobrien
281133852Sobrien#define AGP_AMD64_TABLE_SIZE \
282133852Sobrien	(sizeof(agp_amd64_table) / sizeof(agp_amd64_table[0]))
283133852Sobrien
284133852Sobrienstatic uint32_t
285133852Sobrienagp_amd64_get_aperture(device_t dev)
286133852Sobrien{
287133852Sobrien	struct agp_amd64_softc *sc = device_get_softc(dev);
288133852Sobrien	uint32_t i;
289133852Sobrien
290133852Sobrien	i = (pci_cfgregread(0, sc->mctrl[0], 3, AGP_AMD64_APCTRL, 4) &
291133852Sobrien		AGP_AMD64_APCTRL_SIZE_MASK) >> 1;
292133852Sobrien
293133852Sobrien	if (i >= AGP_AMD64_TABLE_SIZE)
294163181Sjkim		return (0);
295133852Sobrien
296133852Sobrien	return (agp_amd64_table[i]);
297133852Sobrien}
298133852Sobrien
299133852Sobrienstatic int
300133852Sobrienagp_amd64_set_aperture(device_t dev, uint32_t aperture)
301133852Sobrien{
302133852Sobrien	struct agp_amd64_softc *sc = device_get_softc(dev);
303133852Sobrien	uint32_t i;
304133852Sobrien	int j;
305133852Sobrien
306133852Sobrien	for (i = 0; i < AGP_AMD64_TABLE_SIZE; i++)
307133852Sobrien		if (agp_amd64_table[i] == aperture)
308133852Sobrien			break;
309150645Sjkim	if (i >= AGP_AMD64_TABLE_SIZE)
310163181Sjkim		return (EINVAL);
311133852Sobrien
312133852Sobrien	for (j = 0; j < sc->n_mctrl; j++)
313133852Sobrien		pci_cfgregwrite(0, sc->mctrl[j], 3, AGP_AMD64_APCTRL,
314133852Sobrien		    (pci_cfgregread(0, sc->mctrl[j], 3, AGP_AMD64_APCTRL, 4) &
315133852Sobrien		    ~(AGP_AMD64_APCTRL_SIZE_MASK)) | (i << 1), 4);
316133852Sobrien
317150645Sjkim	switch (pci_get_vendor(dev)) {
318150645Sjkim	case 0x10b9:	/* ULi */
319150645Sjkim		return (agp_amd64_uli_set_aperture(dev, aperture));
320150645Sjkim		break;
321150645Sjkim
322150645Sjkim	case 0x10de:	/* nVidia */
323150645Sjkim		return (agp_amd64_nvidia_set_aperture(dev, aperture));
324150645Sjkim		break;
325152435Sjkim
326152435Sjkim	case 0x1106:	/* VIA */
327152435Sjkim		if (sc->via_agp)
328152435Sjkim			return (agp_amd64_via_set_aperture(dev, aperture));
329152435Sjkim		break;
330150645Sjkim	}
331150645Sjkim
332163181Sjkim	return (0);
333133852Sobrien}
334133852Sobrien
335133852Sobrienstatic int
336189578Simpagp_amd64_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical)
337133852Sobrien{
338133852Sobrien	struct agp_amd64_softc *sc = device_get_softc(dev);
339133852Sobrien
340190169Srnoland	if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
341163181Sjkim		return (EINVAL);
342133852Sobrien
343163180Sjkim	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] =
344163180Sjkim	    (physical & 0xfffff000) | ((physical >> 28) & 0x00000ff0) | 3;
345163180Sjkim
346163181Sjkim	return (0);
347133852Sobrien}
348133852Sobrien
349133852Sobrienstatic int
350189578Simpagp_amd64_unbind_page(device_t dev, vm_offset_t offset)
351133852Sobrien{
352133852Sobrien	struct agp_amd64_softc *sc = device_get_softc(dev);
353133852Sobrien
354190169Srnoland	if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
355163181Sjkim		return (EINVAL);
356133852Sobrien
357133852Sobrien	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
358163181Sjkim
359163181Sjkim	return (0);
360133852Sobrien}
361133852Sobrien
362133852Sobrienstatic void
363133852Sobrienagp_amd64_flush_tlb(device_t dev)
364133852Sobrien{
365133852Sobrien	struct agp_amd64_softc *sc = device_get_softc(dev);
366133852Sobrien	int i;
367133852Sobrien
368133852Sobrien	for (i = 0; i < sc->n_mctrl; i++)
369133852Sobrien		pci_cfgregwrite(0, sc->mctrl[i], 3, AGP_AMD64_CACHECTRL,
370133852Sobrien		    pci_cfgregread(0, sc->mctrl[i], 3, AGP_AMD64_CACHECTRL, 4) |
371133852Sobrien		    AGP_AMD64_CACHECTRL_INVGART, 4);
372133852Sobrien}
373133852Sobrien
374150645Sjkimstatic void
375150645Sjkimagp_amd64_apbase_fixup(device_t dev)
376150645Sjkim{
377150645Sjkim	struct agp_amd64_softc *sc = device_get_softc(dev);
378150645Sjkim	uint32_t apbase;
379150645Sjkim	int i;
380150645Sjkim
381161518Sjkim	sc->apbase = rman_get_start(sc->agp.as_aperture);
382161518Sjkim	apbase = (sc->apbase >> 25) & AGP_AMD64_APBASE_MASK;
383150645Sjkim	for (i = 0; i < sc->n_mctrl; i++)
384161518Sjkim		pci_cfgregwrite(0, sc->mctrl[i], 3,
385161518Sjkim		    AGP_AMD64_APBASE, apbase, 4);
386150645Sjkim}
387150645Sjkim
388150645Sjkimstatic void
389150645Sjkimagp_amd64_uli_init(device_t dev)
390150645Sjkim{
391150645Sjkim	struct agp_amd64_softc *sc = device_get_softc(dev);
392150645Sjkim
393150645Sjkim	agp_amd64_apbase_fixup(dev);
394150645Sjkim	pci_write_config(dev, AGP_AMD64_ULI_APBASE,
395150645Sjkim	    (pci_read_config(dev, AGP_AMD64_ULI_APBASE, 4) & 0x0000000f) |
396150645Sjkim	    sc->apbase, 4);
397150645Sjkim	pci_write_config(dev, AGP_AMD64_ULI_HTT_FEATURE, sc->apbase, 4);
398150645Sjkim}
399150645Sjkim
400150645Sjkimstatic int
401150645Sjkimagp_amd64_uli_set_aperture(device_t dev, uint32_t aperture)
402150645Sjkim{
403150645Sjkim	struct agp_amd64_softc *sc = device_get_softc(dev);
404150645Sjkim
405150645Sjkim	switch (aperture) {
406150645Sjkim	case 0x02000000:	/*  32 MB */
407150645Sjkim	case 0x04000000:	/*  64 MB */
408150645Sjkim	case 0x08000000:	/* 128 MB */
409150645Sjkim	case 0x10000000:	/* 256 MB */
410150645Sjkim		break;
411150645Sjkim	default:
412163181Sjkim		return (EINVAL);
413150645Sjkim	}
414150645Sjkim
415150645Sjkim	pci_write_config(dev, AGP_AMD64_ULI_ENU_SCR,
416150645Sjkim	    sc->apbase + aperture - 1, 4);
417150645Sjkim
418163181Sjkim	return (0);
419150645Sjkim}
420150645Sjkim
421150645Sjkimstatic void
422150645Sjkimagp_amd64_nvidia_init(device_t dev)
423150645Sjkim{
424150645Sjkim	struct agp_amd64_softc *sc = device_get_softc(dev);
425150645Sjkim
426150645Sjkim	agp_amd64_apbase_fixup(dev);
427150645Sjkim	pci_write_config(dev, AGP_AMD64_NVIDIA_0_APBASE,
428150645Sjkim	    (pci_read_config(dev, AGP_AMD64_NVIDIA_0_APBASE, 4) & 0x0000000f) |
429150645Sjkim	    sc->apbase, 4);
430150645Sjkim	pci_cfgregwrite(0, 11, 0, AGP_AMD64_NVIDIA_1_APBASE1, sc->apbase, 4);
431150645Sjkim	pci_cfgregwrite(0, 11, 0, AGP_AMD64_NVIDIA_1_APBASE2, sc->apbase, 4);
432150645Sjkim}
433150645Sjkim
434150645Sjkimstatic int
435150645Sjkimagp_amd64_nvidia_set_aperture(device_t dev, uint32_t aperture)
436150645Sjkim{
437150645Sjkim	struct agp_amd64_softc *sc = device_get_softc(dev);
438150645Sjkim	uint32_t apsize;
439150645Sjkim
440150645Sjkim	switch (aperture) {
441150645Sjkim	case 0x02000000:	apsize = 0x0f;	break;	/*  32 MB */
442150645Sjkim	case 0x04000000:	apsize = 0x0e;	break;	/*  64 MB */
443150645Sjkim	case 0x08000000:	apsize = 0x0c;	break;	/* 128 MB */
444150645Sjkim	case 0x10000000:	apsize = 0x08;	break;	/* 256 MB */
445150645Sjkim	case 0x20000000:	apsize = 0x00;	break;	/* 512 MB */
446150645Sjkim	default:
447163181Sjkim		return (EINVAL);
448150645Sjkim	}
449150645Sjkim
450150645Sjkim	pci_cfgregwrite(0, 11, 0, AGP_AMD64_NVIDIA_1_APSIZE,
451150645Sjkim	    (pci_cfgregread(0, 11, 0, AGP_AMD64_NVIDIA_1_APSIZE, 4) &
452150645Sjkim	    0xfffffff0) | apsize, 4);
453150645Sjkim	pci_cfgregwrite(0, 11, 0, AGP_AMD64_NVIDIA_1_APLIMIT1,
454150645Sjkim	    sc->apbase + aperture - 1, 4);
455150645Sjkim	pci_cfgregwrite(0, 11, 0, AGP_AMD64_NVIDIA_1_APLIMIT2,
456150645Sjkim	    sc->apbase + aperture - 1, 4);
457150645Sjkim
458163181Sjkim	return (0);
459150645Sjkim}
460150645Sjkim
461152435Sjkimstatic void
462152435Sjkimagp_amd64_via_init(device_t dev)
463152435Sjkim{
464152435Sjkim	struct agp_amd64_softc *sc = device_get_softc(dev);
465152435Sjkim
466152435Sjkim	agp_amd64_apbase_fixup(dev);
467152435Sjkim	pci_cfgregwrite(0, 1, 0, AGP3_VIA_ATTBASE, sc->gatt->ag_physical, 4);
468152435Sjkim	pci_cfgregwrite(0, 1, 0, AGP3_VIA_GARTCTRL,
469152435Sjkim	    pci_cfgregread(0, 1, 0, AGP3_VIA_ATTBASE, 4) | 0x180, 4);
470152435Sjkim}
471152435Sjkim
472152435Sjkimstatic int
473152435Sjkimagp_amd64_via_set_aperture(device_t dev, uint32_t aperture)
474152435Sjkim{
475152435Sjkim	uint32_t apsize;
476152435Sjkim
477152435Sjkim	apsize = ((aperture - 1) >> 20) ^ 0xff;
478152435Sjkim	if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
479163181Sjkim		return (EINVAL);
480152435Sjkim	pci_cfgregwrite(0, 1, 0, AGP3_VIA_APSIZE, apsize, 1);
481152435Sjkim
482163181Sjkim	return (0);
483152435Sjkim}
484152435Sjkim
485133852Sobrienstatic device_method_t agp_amd64_methods[] = {
486133852Sobrien	/* Device interface */
487133852Sobrien	DEVMETHOD(device_probe,		agp_amd64_probe),
488133852Sobrien	DEVMETHOD(device_attach,	agp_amd64_attach),
489133852Sobrien	DEVMETHOD(device_detach,	agp_amd64_detach),
490133852Sobrien	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
491133852Sobrien	DEVMETHOD(device_suspend,	bus_generic_suspend),
492133852Sobrien	DEVMETHOD(device_resume,	bus_generic_resume),
493133852Sobrien
494133852Sobrien	/* AGP interface */
495133852Sobrien	DEVMETHOD(agp_get_aperture,	agp_amd64_get_aperture),
496133852Sobrien	DEVMETHOD(agp_set_aperture,	agp_amd64_set_aperture),
497133852Sobrien	DEVMETHOD(agp_bind_page,	agp_amd64_bind_page),
498133852Sobrien	DEVMETHOD(agp_unbind_page,	agp_amd64_unbind_page),
499133852Sobrien	DEVMETHOD(agp_flush_tlb,	agp_amd64_flush_tlb),
500133852Sobrien	DEVMETHOD(agp_enable,		agp_generic_enable),
501133852Sobrien	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
502133852Sobrien	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
503133852Sobrien	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
504133852Sobrien	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
505133852Sobrien
506133852Sobrien	{ 0, 0 }
507133852Sobrien};
508133852Sobrien
509133852Sobrienstatic driver_t agp_amd64_driver = {
510133852Sobrien	"agp",
511133852Sobrien	agp_amd64_methods,
512133852Sobrien	sizeof(struct agp_amd64_softc),
513133852Sobrien};
514133852Sobrien
515133852Sobrienstatic devclass_t agp_devclass;
516133852Sobrien
517153572SjhbDRIVER_MODULE(agp_amd64, hostb, agp_amd64_driver, agp_devclass, 0, 0);
518133852SobrienMODULE_DEPEND(agp_amd64, agp, 1, 1, 1);
519133852SobrienMODULE_DEPEND(agp_amd64, pci, 1, 1, 1);
520