xref: /openbsd-src/sys/dev/pci/agp_ali.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: agp_ali.c,v 1.7 2008/11/09 22:47:54 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/proc.h>
38 #include <sys/conf.h>
39 #include <sys/device.h>
40 #include <sys/lock.h>
41 #include <sys/agpio.h>
42 
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcireg.h>
45 #include <dev/pci/pcidevs.h>
46 #include <dev/pci/vga_pcivar.h>
47 #include <dev/pci/agpvar.h>
48 #include <dev/pci/agpreg.h>
49 
50 #include <machine/bus.h>
51 
52 struct agp_ali_softc {
53 	struct device		 dev;
54 	struct agp_softc	*agpdev;
55 	struct agp_gatt		*gatt;
56 	pci_chipset_tag_t	 asc_pc;
57 	pcitag_t		 asc_tag;
58 	bus_size_t		 initial_aperture;
59 };
60 
61 void	agp_ali_attach(struct device *, struct device *, void *);
62 int	agp_ali_probe(struct device *, void *, void *);
63 bus_size_t agp_ali_get_aperture(void *);
64 int	agp_ali_set_aperture(void *sc, bus_size_t);
65 int	agp_ali_bind_page(void *, off_t, bus_addr_t);
66 int	agp_ali_unbind_page(void *, off_t);
67 void	agp_ali_flush_tlb(void *);
68 
69 struct cfattach aliagp_ca = {
70         sizeof(struct agp_ali_softc), agp_ali_probe, agp_ali_attach
71 };
72 
73 struct cfdriver aliagp_cd = {
74 	NULL, "aliagp", DV_DULL
75 };
76 
77 const struct agp_methods agp_ali_methods = {
78 	agp_ali_get_aperture,
79 	agp_ali_bind_page,
80 	agp_ali_unbind_page,
81 	agp_ali_flush_tlb,
82 };
83 
84 int
85 agp_ali_probe(struct device *parent, void *match, void *aux)
86 {
87 	struct agp_attach_args	*aa = aux;
88 	struct pci_attach_args	*pa = aa->aa_pa;
89 
90 	/* Must be a pchb, don't attach to iommu-style agp devs */
91 	if (agpbus_probe(aa) == 1 && PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI &&
92 	    PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_ALI_M1689)
93 		return (1);
94 	return (0);
95 }
96 
97 void
98 agp_ali_attach(struct device *parent, struct device *self, void *aux)
99 {
100 	struct agp_ali_softc	*asc = (struct agp_ali_softc *)self;
101 	struct agp_gatt		*gatt;
102 	struct agp_attach_args	*aa = aux;
103 	struct pci_attach_args	*pa = aa->aa_pa;
104 	pcireg_t		 reg;
105 
106 	asc->asc_tag = pa->pa_tag;
107 	asc->asc_pc = pa->pa_pc;
108 	asc->initial_aperture = agp_ali_get_aperture(asc);
109 
110 	for (;;) {
111 		bus_size_t size = agp_ali_get_aperture(asc);
112 		gatt = agp_alloc_gatt(pa->pa_dmat, size);
113 		if (gatt != NULL)
114 			break;
115 		/*
116 		 * almost certainly error allocating contigious dma memory
117 		 * so reduce aperture so that the gatt size reduces.
118 		 */
119 		if (agp_ali_set_aperture(asc, size / 2)) {
120 			printf("failed to set aperture\n");
121 			return;
122 		}
123 	}
124 	asc->gatt = gatt;
125 
126 	/* Install the gatt. */
127 	reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE);
128 	reg = (reg & 0xff) | gatt->ag_physical;
129 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE, reg);
130 
131 	/* Enable the TLB. */
132 	reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL);
133 	reg = (reg & ~0xff) | 0x10;
134 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL, reg);
135 
136 	asc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_ali_methods,
137 	    AGP_APBASE, PCI_MAPREG_TYPE_MEM, &asc->dev);
138 	return;
139 }
140 
141 #if 0
142 int
143 agp_ali_detach(struct agp_softc *sc)
144 {
145 	int error;
146 	pcireg_t reg;
147 	struct agp_ali_softc *asc = sc->sc_chipc;
148 
149 	error = agp_generic_detach(sc);
150 	if (error)
151 		return (error);
152 
153 	/* Disable the TLB.. */
154 	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL);
155 	reg &= ~0xff;
156 	reg |= 0x90;
157 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL, reg);
158 
159 	/* Put the aperture back the way it started. */
160 	AGP_SET_APERTURE(sc, asc->initial_aperture);
161 	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE);
162 	reg &= 0xff;
163 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE, reg);
164 
165 	agp_free_gatt(sc, asc->gatt);
166 	return (0);
167 }
168 #endif
169 
170 #define M 1024*1024
171 
172 static const u_int32_t agp_ali_table[] = {
173 	0,			/* 0 - invalid */
174 	1,			/* 1 - invalid */
175 	2,			/* 2 - invalid */
176 	4*M,			/* 3 - invalid */
177 	8*M,			/* 4 - invalid */
178 	0,			/* 5 - invalid */
179 	16*M,			/* 6 - invalid */
180 	32*M,			/* 7 - invalid */
181 	64*M,			/* 8 - invalid */
182 	128*M,			/* 9 - invalid */
183 	256*M,			/* 10 - invalid */
184 };
185 #define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0]))
186 
187 bus_size_t
188 agp_ali_get_aperture(void *sc)
189 {
190 	struct agp_ali_softc	*asc = sc;
191 	int			 i;
192 
193 	/*
194 	 * The aperture size is derived from the low bits of attbase.
195 	 * I'm not sure this is correct..
196 	 */
197 	i = (int)pci_conf_read(asc->asc_pc, asc->asc_tag,
198 	    AGP_ALI_ATTBASE) & 0xff;
199 	if (i >= agp_ali_table_size)
200 		return (0);
201 	return (agp_ali_table[i]);
202 }
203 
204 int
205 agp_ali_set_aperture(void *sc, bus_size_t aperture)
206 {
207 	struct agp_ali_softc	*asc = sc;
208 	int			 i;
209 	pcireg_t		 reg;
210 
211 	for (i = 0; i < agp_ali_table_size; i++)
212 		if (agp_ali_table[i] == aperture)
213 			break;
214 	if (i == agp_ali_table_size)
215 		return (EINVAL);
216 
217 	reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE);
218 	reg &= ~0xff;
219 	reg |= i;
220 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_ATTBASE, reg);
221 	return (0);
222 }
223 
224 int
225 agp_ali_bind_page(void *sc, off_t offset, bus_addr_t physical)
226 {
227 	struct agp_ali_softc *asc = sc;
228 
229 	if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT))
230 		return (EINVAL);
231 
232 	asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
233 	return (0);
234 }
235 
236 int
237 agp_ali_unbind_page(void *sc, off_t offset)
238 {
239 	struct agp_ali_softc *asc = sc;
240 
241 	if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT))
242 		return (EINVAL);
243 
244 	asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
245 	return (0);
246 }
247 
248 void
249 agp_ali_flush_tlb(void *sc)
250 {
251 	struct agp_ali_softc	*asc = sc;
252 	pcireg_t		reg;
253 
254 	reg = pci_conf_read(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL);
255 	reg &= ~0xff;
256 	reg |= 0x90;
257 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL, reg);
258 	reg &= ~0xff;
259 	reg |= 0x10;
260 	pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_ALI_TLBCTRL, reg);
261 }
262 
263