xref: /openbsd-src/sys/dev/pci/agp_via.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: agp_via.c,v 1.2 2002/07/25 23:31:04 fgsch 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 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/malloc.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/proc.h>
39 #include <sys/conf.h>
40 #include <sys/device.h>
41 #include <sys/agpio.h>
42 
43 #include <dev/pci/pcivar.h>
44 #include <dev/pci/pcireg.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 static u_int32_t agp_via_get_aperture(struct vga_pci_softc *);
52 static int agp_via_set_aperture(struct vga_pci_softc *, u_int32_t);
53 static int agp_via_bind_page(struct vga_pci_softc *, off_t, bus_addr_t);
54 static int agp_via_unbind_page(struct vga_pci_softc *, off_t);
55 static void agp_via_flush_tlb(struct vga_pci_softc *);
56 
57 struct agp_methods agp_via_methods = {
58 	agp_via_get_aperture,
59 	agp_via_set_aperture,
60 	agp_via_bind_page,
61 	agp_via_unbind_page,
62 	agp_via_flush_tlb,
63 	agp_generic_enable,
64 	agp_generic_alloc_memory,
65 	agp_generic_free_memory,
66 	agp_generic_bind_memory,
67 	agp_generic_unbind_memory,
68 };
69 
70 struct agp_via_softc {
71 	u_int32_t	initial_aperture; /* aperture size at startup */
72 	struct agp_gatt *gatt;
73 };
74 
75 
76 int
77 agp_via_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa,
78 	       struct pci_attach_args *pchb_pa)
79 {
80 	struct agp_via_softc *asc;
81 	struct agp_gatt *gatt;
82 
83 	asc = malloc(sizeof *asc, M_DEVBUF, M_NOWAIT);
84 	if (asc == NULL) {
85 		printf(": can't allocate chipset-specific softc\n");
86 		return (ENOMEM);
87 	}
88 	memset(asc, 0, sizeof *asc);
89 	sc->sc_chipc = asc;
90 	sc->sc_methods = &agp_via_methods;
91 
92 	if (agp_map_aperture(sc) != 0) {
93 		printf(": can't map aperture\n");
94 		free(asc, M_DEVBUF);
95 		return (ENXIO);
96 	}
97 
98 	asc->initial_aperture = AGP_GET_APERTURE(sc);
99 
100 	for (;;) {
101 		gatt = agp_alloc_gatt(sc);
102 		if (gatt)
103 			break;
104 
105 		/*
106 		 * Probably contigmalloc failure. Try reducing the
107 		 * aperture so that the gatt size reduces.
108 		 */
109 		if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) {
110 			agp_generic_detach(sc);
111 			printf(": can't set aperture size\n");
112 			return (ENOMEM);
113 		}
114 	}
115 	asc->gatt = gatt;
116 
117 	/* Install the gatt. */
118 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_ATTBASE,
119 	    gatt->ag_physical | 3);
120 
121 	/* Enable the aperture. */
122 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_GARTCTRL, 0x0000000f);
123 
124 	return (0);
125 }
126 
127 #if 0
128 static int
129 agp_via_detach(struct vga_pci_softc *sc)
130 {
131 	struct agp_via_softc *asc = sc->sc_chipc;
132 	int error;
133 
134 	error = agp_generic_detach(sc);
135 	if (error)
136 		return (error);
137 
138 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_GARTCTRL, 0);
139 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_ATTBASE, 0);
140 	AGP_SET_APERTURE(sc, asc->initial_aperture);
141 	agp_free_gatt(sc, asc->gatt);
142 
143 	return (0);
144 }
145 #endif
146 
147 static u_int32_t
148 agp_via_get_aperture(struct vga_pci_softc *sc)
149 {
150 	u_int32_t apsize;
151 
152 	apsize = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
153 	    AGP_VIA_APSIZE) & 0x1f;
154 
155 	/*
156 	 * The size is determined by the number of low bits of
157 	 * register APBASE which are forced to zero. The low 20 bits
158 	 * are always forced to zero and each zero bit in the apsize
159 	 * field just read forces the corresponding bit in the 27:20
160 	 * to be zero. We calculate the aperture size accordingly.
161 	 */
162 	return ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1);
163 }
164 
165 static int
166 agp_via_set_aperture(struct vga_pci_softc *sc, u_int32_t aperture)
167 {
168 	u_int32_t apsize;
169 	pcireg_t reg;
170 
171 	/*
172 	 * Reverse the magic from get_aperture.
173 	 */
174 	apsize = ((aperture - 1) >> 20) ^ 0xff;
175 
176 	/*
177 	 * Double check for sanity.
178 	 */
179 	if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture)
180 		return (EINVAL);
181 
182 	reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_VIA_APSIZE);
183 	reg &= ~0xff;
184 	reg |= apsize;
185 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_APSIZE, reg);
186 
187 	return (0);
188 }
189 
190 static int
191 agp_via_bind_page(struct vga_pci_softc *sc, off_t offset, bus_addr_t physical)
192 {
193 	struct agp_via_softc *asc = sc->sc_chipc;
194 
195 	if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT))
196 		return (EINVAL);
197 
198 	asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
199 	return (0);
200 }
201 
202 static int
203 agp_via_unbind_page(struct vga_pci_softc *sc, off_t offset)
204 {
205 	struct agp_via_softc *asc = sc->sc_chipc;
206 
207 	if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT))
208 		return (EINVAL);
209 
210 	asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
211 	return (0);
212 }
213 
214 static void
215 agp_via_flush_tlb(struct vga_pci_softc *sc)
216 {
217 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_GARTCTRL, 0x8f);
218 	pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_GARTCTRL, 0x0f);
219 }
220