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