agp_ali.c revision 244926
1204076Spjd/*-
2217964Spjd * Copyright (c) 2000 Doug Rabson
3217964Spjd * All rights reserved.
4204076Spjd *
5204076Spjd * Redistribution and use in source and binary forms, with or without
6204076Spjd * modification, are permitted provided that the following conditions
7204076Spjd * are met:
8204076Spjd * 1. Redistributions of source code must retain the above copyright
9204076Spjd *    notice, this list of conditions and the following disclaimer.
10204076Spjd * 2. Redistributions in binary form must reproduce the above copyright
11204076Spjd *    notice, this list of conditions and the following disclaimer in the
12204076Spjd *    documentation and/or other materials provided with the distribution.
13204076Spjd *
14204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17204076Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24204076Spjd * SUCH DAMAGE.
25204076Spjd */
26204076Spjd
27204076Spjd#include <sys/cdefs.h>
28204076Spjd__FBSDID("$FreeBSD: head/sys/dev/agp/agp_ali.c 244926 2013-01-01 18:16:49Z antoine $");
29204076Spjd
30204076Spjd#include <sys/param.h>
31204076Spjd#include <sys/systm.h>
32204076Spjd#include <sys/malloc.h>
33204076Spjd#include <sys/kernel.h>
34219370Spjd#include <sys/module.h>
35219370Spjd#include <sys/bus.h>
36219370Spjd#include <sys/lock.h>
37204076Spjd#include <sys/mutex.h>
38204076Spjd#include <sys/proc.h>
39219370Spjd
40219370Spjd#include <dev/agp/agppriv.h>
41204076Spjd#include <dev/agp/agpreg.h>
42219370Spjd#include <dev/pci/pcivar.h>
43204076Spjd#include <dev/pci/pcireg.h>
44204076Spjd
45204076Spjd#include <vm/vm.h>
46204076Spjd#include <vm/vm_object.h>
47204076Spjd#include <vm/pmap.h>
48204076Spjd
49204076Spjdstruct agp_ali_softc {
50219369Spjd	struct agp_softc agp;
51219369Spjd	u_int32_t	initial_aperture; /* aperture size at startup */
52219369Spjd	struct agp_gatt *gatt;
53219369Spjd};
54219369Spjd
55218040Spjdstatic const char*
56204076Spjdagp_ali_match(device_t dev)
57204076Spjd{
58219370Spjd	if (pci_get_class(dev) != PCIC_BRIDGE
59219370Spjd	    || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
60219370Spjd		return NULL;
61219370Spjd
62219370Spjd	if (agp_find_caps(dev) == 0)
63219370Spjd		return NULL;
64219370Spjd
65219370Spjd	switch (pci_get_devid(dev)) {
66219370Spjd	case 0x167110b9:
67219370Spjd		return ("Ali M1671 host to AGP bridge");
68219370Spjd	case 0x154110b9:
69219370Spjd		return ("Ali M1541 host to AGP bridge");
70219370Spjd	case 0x162110b9:
71219370Spjd		return ("Ali M1621 host to AGP bridge");
72219370Spjd	}
73219370Spjd
74219370Spjd	return NULL;
75219370Spjd}
76219370Spjd
77219370Spjdstatic int
78219370Spjdagp_ali_probe(device_t dev)
79219370Spjd{
80219370Spjd	const char *desc;
81219370Spjd
82219370Spjd	if (resource_disabled("agp", device_get_unit(dev)))
83219370Spjd		return (ENXIO);
84219370Spjd	desc = agp_ali_match(dev);
85219370Spjd	if (desc) {
86219370Spjd		device_set_desc(dev, desc);
87219370Spjd		return BUS_PROBE_DEFAULT;
88219370Spjd	}
89219370Spjd
90219370Spjd	return ENXIO;
91219370Spjd}
92219370Spjd
93219370Spjdstatic int
94219370Spjdagp_ali_attach(device_t dev)
95219370Spjd{
96219370Spjd	struct agp_ali_softc *sc = device_get_softc(dev);
97219370Spjd	struct agp_gatt *gatt;
98219385Spjd	int error;
99219370Spjd	u_int32_t attbase;
100219370Spjd
101219370Spjd	error = agp_generic_attach(dev);
102219385Spjd	if (error)
103219385Spjd		return error;
104219370Spjd
105219370Spjd	sc->initial_aperture = AGP_GET_APERTURE(dev);
106219370Spjd	if (sc->initial_aperture == 0) {
107219370Spjd		device_printf(dev, "bad initial aperture size, disabling\n");
108219370Spjd		return ENXIO;
109219370Spjd	}
110219385Spjd
111219370Spjd	for (;;) {
112219370Spjd		gatt = agp_alloc_gatt(dev);
113219370Spjd		if (gatt)
114219370Spjd			break;
115219370Spjd
116219370Spjd		/*
117219370Spjd		 * Probably contigmalloc failure. Try reducing the
118219370Spjd		 * aperture so that the gatt size reduces.
119219370Spjd		 */
120219370Spjd		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) {
121219385Spjd			agp_generic_detach(dev);
122219370Spjd			return ENOMEM;
123219370Spjd		}
124219370Spjd	}
125219370Spjd	sc->gatt = gatt;
126219370Spjd
127219370Spjd	/* Install the gatt. */
128219370Spjd	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
129217965Spjd	pci_write_config(dev, AGP_ALI_ATTBASE, gatt->ag_physical |
130217965Spjd	    (attbase & 0xfff), 4);
131217965Spjd
132217965Spjd	/* Enable the TLB. */
133219369Spjd	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
134219369Spjd
135217965Spjd	return 0;
136217965Spjd}
137219370Spjd
138219370Spjdstatic int
139219370Spjdagp_ali_detach(device_t dev)
140219370Spjd{
141219370Spjd	struct agp_ali_softc *sc = device_get_softc(dev);
142219370Spjd	u_int32_t attbase;
143219370Spjd
144219370Spjd	agp_free_cdev(dev);
145219370Spjd
146219370Spjd	/* Disable the TLB.. */
147219370Spjd	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
148217965Spjd
149217965Spjd	/* Put the aperture back the way it started. */
150217965Spjd	AGP_SET_APERTURE(dev, sc->initial_aperture);
151218040Spjd	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
152218040Spjd	pci_write_config(dev, AGP_ALI_ATTBASE, attbase & 0xfff, 4);
153217965Spjd
154219369Spjd	agp_free_gatt(sc->gatt);
155217965Spjd	agp_free_res(dev);
156217965Spjd	return 0;
157217965Spjd}
158217965Spjd
159217965Spjd#define M 1024*1024
160217965Spjd
161219369Spjdstatic u_int32_t agp_ali_table[] = {
162217965Spjd	0,			/* 0 - invalid */
163217965Spjd	1,			/* 1 - invalid */
164217965Spjd	2,			/* 2 - invalid */
165217965Spjd	4*M,			/* 3 - invalid */
166219369Spjd	8*M,			/* 4 - invalid */
167217965Spjd	0,			/* 5 - invalid */
168217965Spjd	16*M,			/* 6 - invalid */
169204076Spjd	32*M,			/* 7 - invalid */
170204076Spjd	64*M,			/* 8 - invalid */
171204076Spjd	128*M,			/* 9 - invalid */
172204076Spjd	256*M,			/* 10 - invalid */
173204076Spjd};
174204076Spjd#define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0]))
175204076Spjd
176204076Spjdstatic u_int32_t
177204076Spjdagp_ali_get_aperture(device_t dev)
178204076Spjd{
179219369Spjd	/*
180204076Spjd	 * The aperture size is derived from the low bits of attbase.
181204076Spjd	 * I'm not sure this is correct..
182217965Spjd	 */
183217965Spjd	int i = pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xf;
184212052Spjd	if (i >= agp_ali_table_size)
185212052Spjd		return 0;
186217962Spjd	return agp_ali_table[i];
187217965Spjd}
188217965Spjd
189217965Spjdstatic int
190217965Spjdagp_ali_set_aperture(device_t dev, u_int32_t aperture)
191204076Spjd{
192204076Spjd	int i;
193204076Spjd	u_int32_t attbase;
194204076Spjd
195204076Spjd	for (i = 0; i < agp_ali_table_size; i++)
196204076Spjd		if (agp_ali_table[i] == aperture)
197204076Spjd			break;
198204076Spjd	if (i == agp_ali_table_size)
199204076Spjd		return EINVAL;
200219369Spjd
201217965Spjd	attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4);
202204076Spjd	pci_write_config(dev, AGP_ALI_ATTBASE, (attbase & ~0xf) | i, 4);
203204076Spjd	return 0;
204204076Spjd}
205204076Spjd
206204076Spjdstatic int
207204076Spjdagp_ali_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical)
208204076Spjd{
209204076Spjd	struct agp_ali_softc *sc = device_get_softc(dev);
210204076Spjd
211204076Spjd	if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
212204076Spjd		return EINVAL;
213219369Spjd
214204076Spjd	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
215204076Spjd	return 0;
216204076Spjd}
217204076Spjd
218204076Spjdstatic int
219204076Spjdagp_ali_unbind_page(device_t dev, vm_offset_t offset)
220204076Spjd{
221204076Spjd	struct agp_ali_softc *sc = device_get_softc(dev);
222204076Spjd
223204076Spjd	if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
224204076Spjd		return EINVAL;
225204076Spjd
226219369Spjd	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
227217965Spjd	return 0;
228204076Spjd}
229204076Spjd
230204076Spjdstatic void
231204076Spjdagp_ali_flush_tlb(device_t dev)
232204076Spjd{
233204076Spjd	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1);
234204076Spjd	pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1);
235204076Spjd}
236204076Spjd
237204076Spjdstatic device_method_t agp_ali_methods[] = {
238204076Spjd	/* Device interface */
239204076Spjd	DEVMETHOD(device_probe,		agp_ali_probe),
240219369Spjd	DEVMETHOD(device_attach,	agp_ali_attach),
241217965Spjd	DEVMETHOD(device_detach,	agp_ali_detach),
242204076Spjd	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
243217731Spjd	DEVMETHOD(device_suspend,	bus_generic_suspend),
244204076Spjd	DEVMETHOD(device_resume,	bus_generic_resume),
245204076Spjd
246204076Spjd	/* AGP interface */
247204076Spjd	DEVMETHOD(agp_get_aperture,	agp_ali_get_aperture),
248204076Spjd	DEVMETHOD(agp_set_aperture,	agp_ali_set_aperture),
249204076Spjd	DEVMETHOD(agp_bind_page,	agp_ali_bind_page),
250204076Spjd	DEVMETHOD(agp_unbind_page,	agp_ali_unbind_page),
251204076Spjd	DEVMETHOD(agp_flush_tlb,	agp_ali_flush_tlb),
252217731Spjd	DEVMETHOD(agp_enable,		agp_generic_enable),
253204076Spjd	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
254204076Spjd	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
255219369Spjd	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
256204076Spjd	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
257204076Spjd
258204076Spjd	{ 0, 0 }
259204076Spjd};
260204076Spjd
261204076Spjdstatic driver_t agp_ali_driver = {
262204076Spjd	"agp",
263204076Spjd	agp_ali_methods,
264204076Spjd	sizeof(struct agp_ali_softc),
265204076Spjd};
266204076Spjd
267204076Spjdstatic devclass_t agp_devclass;
268204076Spjd
269204076SpjdDRIVER_MODULE(agp_ali, hostb, agp_ali_driver, agp_devclass, 0, 0);
270204076SpjdMODULE_DEPEND(agp_ali, agp, 1, 1, 1);
271204076SpjdMODULE_DEPEND(agp_ali, pci, 1, 1, 1);
272204076Spjd