xref: /openbsd/sys/dev/pci/agp_via.c (revision d415bd75)
1 /*	$OpenBSD: agp_via.c,v 1.22 2022/03/11 18:00:45 mpi Exp $	*/
2 /*	$NetBSD: agp_via.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_via.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/device.h>
36 #include <sys/rwlock.h>
37 
38 #include <dev/pci/pcivar.h>
39 #include <dev/pci/pcireg.h>
40 #include <dev/pci/pcidevs.h>
41 #include <dev/pci/vga_pcivar.h>
42 #include <dev/pci/agpvar.h>
43 #include <dev/pci/agpreg.h>
44 
45 #include <machine/bus.h>
46 
47 struct agp_via_softc {
48 	struct device		 dev;
49 	struct agp_softc	*agpdev;
50 	struct agp_gatt		*gatt;
51 	int			*regs;
52 	pci_chipset_tag_t	 vsc_pc;
53 	pcitag_t		 vsc_tag;
54 	bus_addr_t		 vsc_apaddr;
55 	bus_size_t		 vsc_apsize;
56 	pcireg_t		 vsc_regapsize;
57 	pcireg_t		 vsc_regattbase;
58 	pcireg_t                 vsc_reggartctl;
59 };
60 
61 void	agp_via_attach(struct device *, struct device *, void *);
62 int	agp_via_activate(struct device *, int);
63 void	agp_via_save(struct agp_via_softc *);
64 void	agp_via_restore(struct agp_via_softc *);
65 int	agp_via_probe(struct device *, void *, void *);
66 bus_size_t agp_via_get_aperture(void *);
67 int	agp_via_set_aperture(void *, bus_size_t);
68 void	agp_via_bind_page(void *, bus_addr_t, paddr_t, int);
69 void	agp_via_unbind_page(void *, bus_addr_t);
70 void	agp_via_flush_tlb(void *);
71 
72 const struct agp_methods agp_via_methods = {
73 	agp_via_bind_page,
74 	agp_via_unbind_page,
75 	agp_via_flush_tlb,
76 };
77 
78 const struct cfattach viaagp_ca = {
79 	sizeof(struct agp_via_softc), agp_via_probe, agp_via_attach,
80 	NULL, agp_via_activate
81 };
82 
83 struct cfdriver viaagp_cd = {
84 	NULL, "viaagp", DV_DULL
85 };
86 
87 #define REG_GARTCTRL	0
88 #define REG_APSIZE	1
89 #define REG_ATTBASE	2
90 
91 int via_v2_regs[] =
92 	{ AGP_VIA_GARTCTRL, AGP_VIA_APSIZE, AGP_VIA_ATTBASE };
93 int via_v3_regs[] =
94 	{ AGP3_VIA_GARTCTRL, AGP3_VIA_APSIZE, AGP3_VIA_ATTBASE };
95 
96 int
97 agp_via_probe(struct device *parent, void *match, void *aux)
98 {
99 	struct agp_attach_args	*aa = aux;
100 	struct pci_attach_args	*pa = aa->aa_pa;
101 
102 	/* Must be a pchb don't attach to iommu-style agp devs */
103 	if (agpbus_probe(aa) == 1 &&
104 	    PCI_VENDOR(pa->pa_id) == PCI_VENDOR_VIATECH &&
105 	    PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_VIATECH_K8M800_0 &&
106 	    PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_VIATECH_K8T890_0 &&
107 	    PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_VIATECH_K8HTB_0 &&
108 	    PCI_PRODUCT(pa->pa_id) != PCI_PRODUCT_VIATECH_K8HTB)
109 		return (1);
110 	return (0);
111 }
112 
113 void
114 agp_via_attach(struct device *parent, struct device *self, void *aux)
115 {
116 	struct agp_via_softc	*vsc = (struct agp_via_softc *)self;
117 	struct agp_attach_args	*aa = aux;
118 	struct pci_attach_args	*pa = aa->aa_pa;
119 	struct agp_gatt		*gatt;
120 	pcireg_t		 agpsel, capval;
121 
122 	vsc->vsc_pc = pa->pa_pc;
123 	vsc->vsc_tag = pa->pa_tag;
124 	pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP, NULL, &capval);
125 
126 	if (pci_mapreg_info(pa->pa_pc, pa->pa_tag, AGP_APBASE,
127 	    PCI_MAPREG_TYPE_MEM, &vsc->vsc_apaddr, NULL, NULL) != 0) {
128 		printf(": can't get aperture info\n");
129 		return;
130 	}
131 
132 	if (AGP_CAPID_GET_MAJOR(capval) >= 3) {
133 		agpsel = pci_conf_read(pa->pa_pc, pa->pa_tag,
134 				AGP_VIA_AGPSEL_REG);
135 		if ((agpsel & (1 << 9)) == 0) {
136 			vsc->regs = via_v3_regs;
137 			printf(": v3");
138 		} else {
139 			vsc->regs = via_v2_regs;
140 			printf(": v2 compat mode");
141 		}
142 	} else {
143 		vsc->regs = via_v2_regs;
144 		printf(": v2");
145 	}
146 
147 
148 	vsc->vsc_apsize = agp_via_get_aperture(vsc);
149 
150 	for (;;) {
151 		gatt = agp_alloc_gatt(pa->pa_dmat, vsc->vsc_apsize);
152 		if (gatt != NULL)
153 			break;
154 
155 		/*
156 		 * Probably failed to alloc contiguous memory. Try reducing the
157 		 * aperture so that the gatt size reduces.
158 		 */
159 		vsc->vsc_apsize /= 2;
160 		if (agp_via_set_aperture(vsc, vsc->vsc_apsize)) {
161 			printf(", can't set aperture size\n");
162 			return;
163 		}
164 	}
165 	vsc->gatt = gatt;
166 
167 	if (vsc->regs == via_v2_regs) {
168 		/* Install the gatt. */
169 		pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_ATTBASE],
170 		    gatt->ag_physical | 3);
171 		/* Enable the aperture. */
172 		pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_GARTCTRL],
173 		    0x0000000f);
174 	} else {
175 		pcireg_t gartctrl;
176 		/* Install the gatt. */
177 		pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_ATTBASE],
178 		    gatt->ag_physical);
179 		/* Enable the aperture. */
180 		gartctrl = pci_conf_read(pa->pa_pc, pa->pa_tag,
181 		    vsc->regs[REG_ATTBASE]);
182 		pci_conf_write(pa->pa_pc, pa->pa_tag, vsc->regs[REG_GARTCTRL],
183 		    gartctrl | (3 << 7));
184 	}
185 	vsc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_via_methods,
186 	    vsc->vsc_apaddr, vsc->vsc_apsize, &vsc->dev);
187 
188 	return;
189 }
190 
191 int
192 agp_via_activate(struct device *arg, int act)
193 {
194 	struct agp_via_softc *vsc = (struct agp_via_softc *)arg;
195 
196 	switch (act) {
197 	case DVACT_SUSPEND:
198 		agp_via_save(vsc);
199 		break;
200 	case DVACT_RESUME:
201 		agp_via_restore(vsc);
202 		break;
203 	}
204 
205 	return (0);
206 }
207 
208 void
209 agp_via_save(struct agp_via_softc *vsc)
210 {
211 	vsc->vsc_regapsize = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag,
212 	    vsc->regs[REG_APSIZE]);
213 	vsc->vsc_regattbase = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag,
214 	    vsc->regs[REG_ATTBASE]);
215 	vsc->vsc_reggartctl = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag,
216 	    vsc->regs[REG_GARTCTRL]);
217 }
218 void
219 agp_via_restore(struct agp_via_softc *vsc)
220 {
221 
222 	/* aperture size */
223 	pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE],
224 	    vsc->vsc_regapsize);
225 	/* GATT address and enable */
226 	pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_ATTBASE],
227 	    vsc->vsc_regattbase);
228 	/* Turn it all back on. */
229 	pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_GARTCTRL],
230 	    vsc->vsc_reggartctl);
231 	/* flush the tlb, just in case */
232 	agp_via_flush_tlb(vsc);
233 }
234 
235 bus_size_t
236 agp_via_get_aperture(void *sc)
237 {
238 	struct agp_via_softc	*vsc = sc;
239 	bus_size_t		 apsize;
240 
241 	apsize = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag,
242 	    vsc->regs[REG_APSIZE]) & 0x1f;
243 
244 	/*
245 	 * The size is determined by the number of low bits of
246 	 * register APBASE which are forced to zero. The low 20 bits
247 	 * are always forced to zero and each zero bit in the apsize
248 	 * field just read forces the corresponding bit in the 27:20
249 	 * to be zero. We calculate the aperture size accordingly.
250 	 */
251 	return ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1);
252 }
253 
254 int
255 agp_via_set_aperture(void *sc, bus_size_t aperture)
256 {
257 	struct agp_via_softc	*vsc = sc;
258 	bus_size_t		 apsize;
259 	pcireg_t		 reg;
260 
261 	/*
262 	 * Reverse the magic from get_aperture.
263 	 */
264 	apsize = ((aperture - 1) >> 20) ^ 0xff;
265 
266 	/*
267 	 * Double check for sanity.
268 	 */
269 	if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
270 		return (EINVAL);
271 
272 	reg = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE]);
273 	reg &= ~0xff;
274 	reg |= apsize;
275 	pci_conf_write(vsc->vsc_pc, vsc->vsc_tag, vsc->regs[REG_APSIZE], reg);
276 
277 	return (0);
278 }
279 
280 void
281 agp_via_bind_page(void *sc, bus_addr_t offset, paddr_t physical, int flags)
282 {
283 	struct agp_via_softc *vsc = sc;
284 
285 	vsc->gatt->ag_virtual[(offset - vsc->vsc_apaddr) >> AGP_PAGE_SHIFT] =
286 	    physical;
287 }
288 
289 void
290 agp_via_unbind_page(void *sc, bus_addr_t offset)
291 {
292 	struct agp_via_softc *vsc = sc;
293 
294 	vsc->gatt->ag_virtual[(offset - vsc->vsc_apaddr) >> AGP_PAGE_SHIFT] = 0;
295 }
296 
297 void
298 agp_via_flush_tlb(void *sc)
299 {
300 	struct agp_via_softc *vsc = sc;
301 	pcireg_t gartctrl;
302 
303 	if (vsc->regs == via_v2_regs) {
304 		pci_conf_write(vsc->vsc_pc, vsc->vsc_tag,
305 		    vsc->regs[REG_GARTCTRL], 0x8f);
306 		pci_conf_write(vsc->vsc_pc, vsc->vsc_tag,
307 		    vsc->regs[REG_GARTCTRL], 0x0f);
308 	} else {
309 		gartctrl = pci_conf_read(vsc->vsc_pc, vsc->vsc_tag,
310 		    vsc->regs[REG_GARTCTRL]);
311 		pci_conf_write(vsc->vsc_pc, vsc->vsc_tag,
312 		    vsc->regs[REG_GARTCTRL], gartctrl & ~(1 << 7));
313 		pci_conf_write(vsc->vsc_pc, vsc->vsc_tag,
314 		    vsc->regs[REG_GARTCTRL], gartctrl);
315 	}
316 }
317