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