xref: /openbsd-src/sys/dev/pci/agp_ali.c (revision 898184e3e61f9129feb5978fad5a8c6865f00b92)
1 /*	$OpenBSD: agp_ali.c,v 1.12 2010/08/07 18:15:38 oga Exp $	*/
2 /*	$NetBSD: agp_ali.c,v 1.2 2001/09/15 00:25:00 thorpej Exp $	*/
3 
4 
5 /*-
6  * Copyright (c) 2000 Doug Rabson
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  *	$FreeBSD: src/sys/pci/agp_ali.c,v 1.3 2001/07/05 21:28:46 jhb Exp $
31  */
32 
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/malloc.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/device.h>
39 #include <sys/lock.h>
40 #include <sys/agpio.h>
41 
42 #include <dev/pci/pcivar.h>
43 #include <dev/pci/pcireg.h>
44 #include <dev/pci/pcidevs.h>
45 #include <dev/pci/vga_pcivar.h>
46 #include <dev/pci/agpvar.h>
47 #include <dev/pci/agpreg.h>
48 
49 #include <machine/bus.h>
50 
51 struct agp_ali_softc {
52 	struct device		 dev;
53 	struct agp_softc	*agpdev;
54 	struct agp_gatt		*gatt;
55 	pci_chipset_tag_t	 asc_pc;
56 	pcitag_t		 asc_tag;
57 	bus_addr_t		 asc_apaddr;
58 	bus_size_t		 asc_apsize;
59 	pcireg_t		 asc_attbase;
60 	pcireg_t		 asc_tlbctrl;
61 };
62 
63 void	agp_ali_attach(struct device *, struct device *, void *);
64 int	agp_ali_activate(struct device *, int);
65 void	agp_ali_save(struct agp_ali_softc *);
66 void	agp_ali_restore(struct agp_ali_softc *);
67 int	agp_ali_probe(struct device *, void *, void *);
68 bus_size_t agp_ali_get_aperture(void *);
69 int	agp_ali_set_aperture(void *sc, bus_size_t);
70 void	agp_ali_bind_page(void *, bus_addr_t, paddr_t, int);
71 void	agp_ali_unbind_page(void *, bus_addr_t);
72 void	agp_ali_flush_tlb(void *);
73 
74 struct cfattach aliagp_ca = {
75 	sizeof(struct agp_ali_softc), agp_ali_probe, agp_ali_attach,
76 	NULL, agp_ali_activate
77 };
78 
79 struct cfdriver aliagp_cd = {
80 	NULL, "aliagp", DV_DULL
81 };
82 
83 const struct agp_methods agp_ali_methods = {
84 	agp_ali_bind_page,
85 	agp_ali_unbind_page,
86 	agp_ali_flush_tlb,
87 };
88 
89 int
90 agp_ali_probe(struct device *parent, void *match, void *aux)
91 {
92 	struct agp_attach_args	*aa = aux;
93 	struct pci_attach_args	*pa = aa->aa_pa;
94 
95 	/* Must be a pchb, don't attach to iommu-style agp devs */
96 	if (agpbus_probe(aa) == 1 && PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI &&
97 	    PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_ALI_M1689)
98 		return (1);
99 	return (0);
100 }
101 
102 void
103 agp_ali_attach(struct device *parent, struct device *self, void *aux)
104 {
105 	struct agp_ali_softc	*asc = (struct agp_ali_softc *)self;
106 	struct agp_gatt		*gatt;
107 	struct agp_attach_args	*aa = aux;
108 	struct pci_attach_args	*pa = aa->aa_pa;
109 	pcireg_t		 reg;
110 
111 	asc->asc_tag = pa->pa_tag;
112 	asc->asc_pc = pa->pa_pc;
113 	asc->asc_apsize = agp_ali_get_aperture(asc);
114 
115 	if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE,
116 	    PCI_MAPREG_TYPE_MEM, &asc->asc_apaddr, NULL, NULL) != 0) {
117 		printf(": can't get aperture info\n");
118 		return;
119 	}
120 
121 	for (;;) {
122 		gatt = agp_alloc_gatt(pa->pa_dmat, asc->asc_apsize);
123 		if (gatt != NULL)
124 			break;
125 		/*
126 		 * almost certainly error allocating contigious dma memory
127 		 * so reduce aperture so that the gatt size reduces.
128 		 */
129 		asc->asc_apsize /= 2;
130 		if (agp_ali_set_aperture(asc, asc->asc_apsize)) {
131 			printf("failed to set aperture\n");
132 			return;
133 		}
134 	}
135 	asc->gatt = gatt;
136 
137 	/* Install the gatt. */
138 	reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE);
139 	reg = (reg & 0xff) | gatt->ag_physical;
140 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE, reg);
141 
142 	/* Enable the TLB. */
143 	reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL);
144 	reg = (reg & ~0xff) | 0x10;
145 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL, reg);
146 
147 	asc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_ali_methods,
148 	    asc->asc_apaddr, asc->asc_apsize, &asc->dev);
149 	return;
150 }
151 
152 #if 0
153 int
154 agp_ali_detach(struct agp_softc *sc)
155 {
156 	int error;
157 	pcireg_t reg;
158 	struct agp_ali_softc *asc = sc->sc_chipc;
159 
160 	error = agp_generic_detach(sc);
161 	if (error)
162 		return (error);
163 
164 	/* Disable the TLB.. */
165 	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL);
166 	reg &= ~0xff;
167 	reg |= 0x90;
168 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL, reg);
169 
170 	/* Put the aperture back the way it started. */
171 	AGP_SET_APERTURE(sc, asc->initial_aperture);
172 	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE);
173 	reg &= 0xff;
174 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE, reg);
175 
176 	agp_free_gatt(sc, asc->gatt);
177 	return (0);
178 }
179 #endif
180 
181 int
182 agp_ali_activate(struct device *arg, int act)
183 {
184 	struct agp_ali_softc *asc = (struct agp_ali_softc *)arg;
185 
186 	switch (act) {
187 	case DVACT_SUSPEND:
188 		agp_ali_save(asc);
189 		break;
190 	case DVACT_RESUME:
191 		agp_ali_restore(asc);
192 		break;
193 	}
194 
195 	return (0);
196 }
197 
198 void
199 agp_ali_save(struct agp_ali_softc *asc)
200 {
201 	asc->asc_attbase = pci_conf_read(asc->asc_pc, asc->asc_tag,
202 	    AGP_ALI_ATTBASE);
203 	asc->asc_tlbctrl = pci_conf_read(asc->asc_pc, asc->asc_tag,
204 	    AGP_ALI_TLBCTRL);
205 }
206 
207 void
208 agp_ali_restore(struct agp_ali_softc *asc)
209 {
210 
211 	/* Install the gatt and aperture size. */
212 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE,
213 	    asc->asc_attbase);
214 
215 	/* Enable the TLB. */
216 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL,
217 	    asc->asc_tlbctrl);
218 }
219 
220 #define M 1024*1024
221 
222 static const u_int32_t agp_ali_table[] = {
223 	0,			/* 0 - invalid */
224 	1,			/* 1 - invalid */
225 	2,			/* 2 - invalid */
226 	4*M,			/* 3 - invalid */
227 	8*M,			/* 4 - invalid */
228 	0,			/* 5 - invalid */
229 	16*M,			/* 6 - invalid */
230 	32*M,			/* 7 - invalid */
231 	64*M,			/* 8 - invalid */
232 	128*M,			/* 9 - invalid */
233 	256*M,			/* 10 - invalid */
234 };
235 #define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0]))
236 
237 bus_size_t
238 agp_ali_get_aperture(void *sc)
239 {
240 	struct agp_ali_softc	*asc = sc;
241 	int			 i;
242 
243 	/*
244 	 * The aperture size is derived from the low bits of attbase.
245 	 * I'm not sure this is correct..
246 	 */
247 	i = (int)pci_conf_read(asc->asc_pc, asc->asc_tag,
248 	    AGP_ALI_ATTBASE) & 0xff;
249 	if (i >= agp_ali_table_size)
250 		return (0);
251 	return (agp_ali_table[i]);
252 }
253 
254 int
255 agp_ali_set_aperture(void *sc, bus_size_t aperture)
256 {
257 	struct agp_ali_softc	*asc = sc;
258 	int			 i;
259 	pcireg_t		 reg;
260 
261 	for (i = 0; i < agp_ali_table_size; i++)
262 		if (agp_ali_table[i] == aperture)
263 			break;
264 	if (i == agp_ali_table_size)
265 		return (EINVAL);
266 
267 	reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE);
268 	reg &= ~0xff;
269 	reg |= i;
270 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE, reg);
271 	return (0);
272 }
273 
274 void
275 agp_ali_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags)
276 {
277 	struct agp_ali_softc *asc = sc;
278 
279 	asc->gatt->ag_virtual[(offset - asc->asc_apaddr) >> AGP_PAGE_SHIFT] =
280 	    physical;
281 }
282 
283 void
284 agp_ali_unbind_page(void *sc, bus_size_t offset)
285 {
286 	struct agp_ali_softc *asc = sc;
287 
288 	asc->gatt->ag_virtual[(offset - asc->asc_apaddr) >> AGP_PAGE_SHIFT] = 0;
289 }
290 
291 void
292 agp_ali_flush_tlb(void *sc)
293 {
294 	struct agp_ali_softc	*asc = sc;
295 	pcireg_t		reg;
296 
297 	reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL);
298 	reg &= ~0xff;
299 	reg |= 0x90;
300 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL, reg);
301 	reg &= ~0xff;
302 	reg |= 0x10;
303 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL, reg);
304 }
305 
306