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