agp_i810.c revision 1.8.2.6 1 1.8.2.6 thorpej /* $NetBSD: agp_i810.c,v 1.8.2.6 2002/12/19 00:48:09 thorpej Exp $ */
2 1.8.2.2 nathanw
3 1.8.2.2 nathanw /*-
4 1.8.2.2 nathanw * Copyright (c) 2000 Doug Rabson
5 1.8.2.2 nathanw * Copyright (c) 2000 Ruslan Ermilov
6 1.8.2.2 nathanw * All rights reserved.
7 1.8.2.2 nathanw *
8 1.8.2.2 nathanw * Redistribution and use in source and binary forms, with or without
9 1.8.2.2 nathanw * modification, are permitted provided that the following conditions
10 1.8.2.2 nathanw * are met:
11 1.8.2.2 nathanw * 1. Redistributions of source code must retain the above copyright
12 1.8.2.2 nathanw * notice, this list of conditions and the following disclaimer.
13 1.8.2.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
14 1.8.2.2 nathanw * notice, this list of conditions and the following disclaimer in the
15 1.8.2.2 nathanw * documentation and/or other materials provided with the distribution.
16 1.8.2.2 nathanw *
17 1.8.2.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 1.8.2.2 nathanw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 1.8.2.2 nathanw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 1.8.2.2 nathanw * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 1.8.2.2 nathanw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 1.8.2.2 nathanw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 1.8.2.2 nathanw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 1.8.2.2 nathanw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 1.8.2.2 nathanw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 1.8.2.2 nathanw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 1.8.2.2 nathanw * SUCH DAMAGE.
28 1.8.2.2 nathanw *
29 1.8.2.2 nathanw * $FreeBSD: src/sys/pci/agp_i810.c,v 1.4 2001/07/05 21:28:47 jhb Exp $
30 1.8.2.2 nathanw */
31 1.8.2.2 nathanw
32 1.8.2.3 nathanw #include <sys/cdefs.h>
33 1.8.2.6 thorpej __KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v 1.8.2.6 2002/12/19 00:48:09 thorpej Exp $");
34 1.8.2.3 nathanw
35 1.8.2.2 nathanw #include <sys/param.h>
36 1.8.2.2 nathanw #include <sys/systm.h>
37 1.8.2.2 nathanw #include <sys/malloc.h>
38 1.8.2.2 nathanw #include <sys/kernel.h>
39 1.8.2.2 nathanw #include <sys/lock.h>
40 1.8.2.2 nathanw #include <sys/proc.h>
41 1.8.2.2 nathanw #include <sys/device.h>
42 1.8.2.2 nathanw #include <sys/conf.h>
43 1.8.2.2 nathanw
44 1.8.2.2 nathanw #include <uvm/uvm_extern.h>
45 1.8.2.2 nathanw
46 1.8.2.2 nathanw #include <dev/pci/pcivar.h>
47 1.8.2.2 nathanw #include <dev/pci/pcireg.h>
48 1.8.2.2 nathanw #include <dev/pci/pcidevs.h>
49 1.8.2.2 nathanw #include <dev/pci/agpvar.h>
50 1.8.2.2 nathanw #include <dev/pci/agpreg.h>
51 1.8.2.2 nathanw
52 1.8.2.2 nathanw #include <sys/agpio.h>
53 1.8.2.2 nathanw
54 1.8.2.2 nathanw #include <machine/bus.h>
55 1.8.2.2 nathanw
56 1.8.2.2 nathanw #define READ1(off) bus_space_read_1(isc->bst, isc->bsh, off)
57 1.8.2.6 thorpej #define READ4(off) bus_space_read_4(isc->bst, isc->bsh, off)
58 1.8.2.2 nathanw #define WRITE4(off,v) bus_space_write_4(isc->bst, isc->bsh, off, v)
59 1.8.2.2 nathanw
60 1.8.2.6 thorpej #define CHIP_I810 0 /* i810/i815 */
61 1.8.2.6 thorpej #define CHIP_I830 1 /* i830/i845 */
62 1.8.2.6 thorpej
63 1.8.2.2 nathanw struct agp_i810_softc {
64 1.8.2.2 nathanw u_int32_t initial_aperture; /* aperture size at startup */
65 1.8.2.2 nathanw struct agp_gatt *gatt;
66 1.8.2.6 thorpej int chiptype; /* i810-like or i830 */
67 1.8.2.6 thorpej u_int32_t dcache_size; /* i810 only */
68 1.8.2.6 thorpej u_int32_t stolen; /* number of i830/845 gtt entries
69 1.8.2.6 thorpej for stolen memory */
70 1.8.2.2 nathanw bus_space_tag_t bst; /* bus_space tag */
71 1.8.2.2 nathanw bus_space_handle_t bsh; /* bus_space handle */
72 1.8.2.2 nathanw struct pci_attach_args vga_pa;
73 1.8.2.2 nathanw };
74 1.8.2.2 nathanw
75 1.8.2.2 nathanw static u_int32_t agp_i810_get_aperture(struct agp_softc *);
76 1.8.2.2 nathanw static int agp_i810_set_aperture(struct agp_softc *, u_int32_t);
77 1.8.2.2 nathanw static int agp_i810_bind_page(struct agp_softc *, off_t, bus_addr_t);
78 1.8.2.2 nathanw static int agp_i810_unbind_page(struct agp_softc *, off_t);
79 1.8.2.2 nathanw static void agp_i810_flush_tlb(struct agp_softc *);
80 1.8.2.2 nathanw static int agp_i810_enable(struct agp_softc *, u_int32_t mode);
81 1.8.2.2 nathanw static struct agp_memory *agp_i810_alloc_memory(struct agp_softc *, int,
82 1.8.2.2 nathanw vsize_t);
83 1.8.2.2 nathanw static int agp_i810_free_memory(struct agp_softc *, struct agp_memory *);
84 1.8.2.2 nathanw static int agp_i810_bind_memory(struct agp_softc *, struct agp_memory *, off_t);
85 1.8.2.2 nathanw static int agp_i810_unbind_memory(struct agp_softc *, struct agp_memory *);
86 1.8.2.2 nathanw
87 1.8.2.2 nathanw struct agp_methods agp_i810_methods = {
88 1.8.2.2 nathanw agp_i810_get_aperture,
89 1.8.2.2 nathanw agp_i810_set_aperture,
90 1.8.2.2 nathanw agp_i810_bind_page,
91 1.8.2.2 nathanw agp_i810_unbind_page,
92 1.8.2.2 nathanw agp_i810_flush_tlb,
93 1.8.2.2 nathanw agp_i810_enable,
94 1.8.2.2 nathanw agp_i810_alloc_memory,
95 1.8.2.2 nathanw agp_i810_free_memory,
96 1.8.2.2 nathanw agp_i810_bind_memory,
97 1.8.2.2 nathanw agp_i810_unbind_memory,
98 1.8.2.2 nathanw };
99 1.8.2.2 nathanw
100 1.8.2.2 nathanw /* XXXthorpej -- duplicated code (see arch/i386/pci/pchb.c) */
101 1.8.2.2 nathanw static int
102 1.8.2.2 nathanw agp_i810_vgamatch(struct pci_attach_args *pa)
103 1.8.2.2 nathanw {
104 1.8.2.2 nathanw
105 1.8.2.2 nathanw if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY ||
106 1.8.2.2 nathanw PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA)
107 1.8.2.2 nathanw return (0);
108 1.8.2.2 nathanw
109 1.8.2.2 nathanw switch (PCI_PRODUCT(pa->pa_id)) {
110 1.8.2.2 nathanw case PCI_PRODUCT_INTEL_82810_GC:
111 1.8.2.2 nathanw case PCI_PRODUCT_INTEL_82810_DC100_GC:
112 1.8.2.2 nathanw case PCI_PRODUCT_INTEL_82810E_GC:
113 1.8.2.2 nathanw case PCI_PRODUCT_INTEL_82815_FULL_GRAPH:
114 1.8.2.6 thorpej case PCI_PRODUCT_INTEL_82830MP_IV:
115 1.8.2.6 thorpej case PCI_PRODUCT_INTEL_82845G_IGD:
116 1.8.2.2 nathanw return (1);
117 1.8.2.2 nathanw }
118 1.8.2.2 nathanw
119 1.8.2.2 nathanw return (0);
120 1.8.2.2 nathanw }
121 1.8.2.2 nathanw
122 1.8.2.2 nathanw int
123 1.8.2.2 nathanw agp_i810_attach(struct device *parent, struct device *self, void *aux)
124 1.8.2.2 nathanw {
125 1.8.2.2 nathanw struct agp_softc *sc = (void *)self;
126 1.8.2.2 nathanw struct agp_i810_softc *isc;
127 1.8.2.2 nathanw struct agp_gatt *gatt;
128 1.8.2.2 nathanw int error;
129 1.8.2.2 nathanw
130 1.8.2.4 nathanw isc = malloc(sizeof *isc, M_AGP, M_NOWAIT|M_ZERO);
131 1.8.2.2 nathanw if (isc == NULL) {
132 1.8.2.2 nathanw printf(": can't allocate chipset-specific softc\n");
133 1.8.2.2 nathanw return ENOMEM;
134 1.8.2.2 nathanw }
135 1.8.2.2 nathanw sc->as_chipc = isc;
136 1.8.2.2 nathanw sc->as_methods = &agp_i810_methods;
137 1.8.2.2 nathanw
138 1.8.2.2 nathanw if (pci_find_device(&isc->vga_pa, agp_i810_vgamatch) == 0) {
139 1.8.2.2 nathanw printf(": can't find internal VGA device config space\n");
140 1.8.2.2 nathanw free(isc, M_AGP);
141 1.8.2.2 nathanw return ENOENT;
142 1.8.2.2 nathanw }
143 1.8.2.2 nathanw
144 1.8.2.2 nathanw /* XXXfvdl */
145 1.8.2.2 nathanw sc->as_dmat = isc->vga_pa.pa_dmat;
146 1.8.2.2 nathanw
147 1.8.2.2 nathanw error = agp_map_aperture(&isc->vga_pa, sc);
148 1.8.2.2 nathanw if (error != 0) {
149 1.8.2.2 nathanw printf(": can't map aperture\n");
150 1.8.2.2 nathanw free(isc, M_AGP);
151 1.8.2.2 nathanw return error;
152 1.8.2.2 nathanw }
153 1.8.2.2 nathanw
154 1.8.2.6 thorpej switch (PCI_PRODUCT(isc->vga_pa.pa_id)) {
155 1.8.2.6 thorpej case PCI_PRODUCT_INTEL_82810_GC:
156 1.8.2.6 thorpej case PCI_PRODUCT_INTEL_82810_DC100_GC:
157 1.8.2.6 thorpej case PCI_PRODUCT_INTEL_82810E_GC:
158 1.8.2.6 thorpej case PCI_PRODUCT_INTEL_82815_FULL_GRAPH:
159 1.8.2.6 thorpej isc->chiptype = CHIP_I810;
160 1.8.2.6 thorpej break;
161 1.8.2.6 thorpej case PCI_PRODUCT_INTEL_82830MP_IV:
162 1.8.2.6 thorpej case PCI_PRODUCT_INTEL_82845G_IGD:
163 1.8.2.6 thorpej isc->chiptype = CHIP_I830;
164 1.8.2.6 thorpej break;
165 1.8.2.6 thorpej }
166 1.8.2.6 thorpej
167 1.8.2.2 nathanw error = pci_mapreg_map(&isc->vga_pa, AGP_I810_MMADR,
168 1.8.2.2 nathanw PCI_MAPREG_TYPE_MEM, 0, &isc->bst, &isc->bsh, NULL, NULL);
169 1.8.2.2 nathanw if (error != 0) {
170 1.8.2.2 nathanw printf(": can't map mmadr registers\n");
171 1.8.2.2 nathanw return error;
172 1.8.2.2 nathanw }
173 1.8.2.2 nathanw
174 1.8.2.2 nathanw isc->initial_aperture = AGP_GET_APERTURE(sc);
175 1.8.2.2 nathanw
176 1.8.2.6 thorpej gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT);
177 1.8.2.6 thorpej if (!gatt) {
178 1.8.2.6 thorpej agp_generic_detach(sc);
179 1.8.2.6 thorpej return ENOMEM;
180 1.8.2.6 thorpej }
181 1.8.2.6 thorpej isc->gatt = gatt;
182 1.8.2.2 nathanw
183 1.8.2.6 thorpej gatt->ag_entries = AGP_GET_APERTURE(sc) >> AGP_PAGE_SHIFT;
184 1.8.2.6 thorpej
185 1.8.2.6 thorpej if (isc->chiptype == CHIP_I810) {
186 1.8.2.6 thorpej int dummyseg;
187 1.8.2.6 thorpej /* Some i810s have on-chip memory called dcache */
188 1.8.2.6 thorpej if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED)
189 1.8.2.6 thorpej isc->dcache_size = 4 * 1024 * 1024;
190 1.8.2.6 thorpej else
191 1.8.2.6 thorpej isc->dcache_size = 0;
192 1.8.2.6 thorpej
193 1.8.2.6 thorpej /* According to the specs the gatt on the i810 must be 64k */
194 1.8.2.6 thorpej if (agp_alloc_dmamem(sc->as_dmat, 64 * 1024,
195 1.8.2.6 thorpej 0, &gatt->ag_dmamap, (caddr_t *)&gatt->ag_virtual,
196 1.8.2.6 thorpej &gatt->ag_physical, &gatt->ag_dmaseg, 1, &dummyseg) != 0) {
197 1.8.2.6 thorpej free(gatt, M_AGP);
198 1.8.2.2 nathanw agp_generic_detach(sc);
199 1.8.2.2 nathanw return ENOMEM;
200 1.8.2.2 nathanw }
201 1.8.2.2 nathanw
202 1.8.2.6 thorpej gatt->ag_size = gatt->ag_entries * sizeof(u_int32_t);
203 1.8.2.6 thorpej memset(gatt->ag_virtual, 0, gatt->ag_size);
204 1.8.2.6 thorpej
205 1.8.2.6 thorpej agp_flush_cache();
206 1.8.2.6 thorpej /* Install the GATT. */
207 1.8.2.6 thorpej WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1);
208 1.8.2.6 thorpej } else {
209 1.8.2.6 thorpej /* The i830 automatically initializes the 128k gatt on boot. */
210 1.8.2.6 thorpej pcireg_t reg;
211 1.8.2.6 thorpej u_int32_t pgtblctl;
212 1.8.2.6 thorpej u_int16_t gcc1;
213 1.8.2.6 thorpej
214 1.8.2.6 thorpej reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0);
215 1.8.2.6 thorpej gcc1 = (u_int16_t)(reg >> 16);
216 1.8.2.6 thorpej switch (gcc1 & AGP_I830_GCC1_GMS) {
217 1.8.2.6 thorpej case AGP_I830_GCC1_GMS_STOLEN_512:
218 1.8.2.6 thorpej isc->stolen = (512 - 132) * 1024 / 4096;
219 1.8.2.6 thorpej break;
220 1.8.2.6 thorpej case AGP_I830_GCC1_GMS_STOLEN_1024:
221 1.8.2.6 thorpej isc->stolen = (1024 - 132) * 1024 / 4096;
222 1.8.2.6 thorpej break;
223 1.8.2.6 thorpej case AGP_I830_GCC1_GMS_STOLEN_8192:
224 1.8.2.6 thorpej isc->stolen = (8192 - 132) * 1024 / 4096;
225 1.8.2.6 thorpej break;
226 1.8.2.6 thorpej default:
227 1.8.2.6 thorpej isc->stolen = 0;
228 1.8.2.6 thorpej printf(": unknown memory configuration, disabling\n");
229 1.8.2.6 thorpej agp_generic_detach(sc);
230 1.8.2.6 thorpej return EINVAL;
231 1.8.2.6 thorpej }
232 1.8.2.6 thorpej if (isc->stolen > 0) {
233 1.8.2.6 thorpej printf(": detected %dk stolen memory\n",
234 1.8.2.6 thorpej isc->stolen * 4);
235 1.8.2.6 thorpej }
236 1.8.2.6 thorpej printf("%s: aperture size is %dM\n", sc->as_dev.dv_xname,
237 1.8.2.6 thorpej isc->initial_aperture / 1024 / 1024);
238 1.8.2.6 thorpej
239 1.8.2.6 thorpej /* GATT address is already in there, make sure it's enabled */
240 1.8.2.6 thorpej pgtblctl = READ4(AGP_I810_PGTBL_CTL);
241 1.8.2.6 thorpej pgtblctl |= 1;
242 1.8.2.6 thorpej WRITE4(AGP_I810_PGTBL_CTL, pgtblctl);
243 1.8.2.6 thorpej
244 1.8.2.6 thorpej gatt->ag_physical = pgtblctl & ~1;
245 1.8.2.6 thorpej }
246 1.8.2.2 nathanw
247 1.8.2.2 nathanw /*
248 1.8.2.2 nathanw * Make sure the chipset can see everything.
249 1.8.2.2 nathanw */
250 1.8.2.2 nathanw agp_flush_cache();
251 1.8.2.2 nathanw
252 1.8.2.6 thorpej printf("%s", sc->as_dev.dv_xname);
253 1.8.2.6 thorpej
254 1.8.2.2 nathanw return 0;
255 1.8.2.2 nathanw }
256 1.8.2.2 nathanw
257 1.8.2.2 nathanw #if 0
258 1.8.2.2 nathanw static int
259 1.8.2.2 nathanw agp_i810_detach(struct agp_softc *sc)
260 1.8.2.2 nathanw {
261 1.8.2.2 nathanw int error;
262 1.8.2.2 nathanw struct agp_i810_softc *isc = sc->as_chipc;
263 1.8.2.2 nathanw
264 1.8.2.2 nathanw error = agp_generic_detach(sc);
265 1.8.2.2 nathanw if (error)
266 1.8.2.2 nathanw return error;
267 1.8.2.2 nathanw
268 1.8.2.2 nathanw /* Clear the GATT base. */
269 1.8.2.6 thorpej if (sc->chiptype == CHIP_I810) {
270 1.8.2.6 thorpej WRITE4(AGP_I810_PGTBL_CTL, 0);
271 1.8.2.6 thorpej } else {
272 1.8.2.6 thorpej unsigned int pgtblctl;
273 1.8.2.6 thorpej pgtblctl = READ4(AGP_I810_PGTBL_CTL);
274 1.8.2.6 thorpej pgtblctl &= ~1;
275 1.8.2.6 thorpej WRITE4(AGP_I810_PGTBL_CTL, pgtblctl);
276 1.8.2.6 thorpej }
277 1.8.2.2 nathanw
278 1.8.2.2 nathanw /* Put the aperture back the way it started. */
279 1.8.2.2 nathanw AGP_SET_APERTURE(sc, isc->initial_aperture);
280 1.8.2.2 nathanw
281 1.8.2.6 thorpej if (sc->chiptype == CHIP_I810) {
282 1.8.2.6 thorpej agp_free_dmamem(sc->as_dmat, gatt->ag_size, gatt->ag_dmamap,
283 1.8.2.6 thorpej (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1);
284 1.8.2.6 thorpej }
285 1.8.2.6 thorpej free(sc->gatt, M_AGP);
286 1.8.2.2 nathanw
287 1.8.2.2 nathanw return 0;
288 1.8.2.2 nathanw }
289 1.8.2.2 nathanw #endif
290 1.8.2.2 nathanw
291 1.8.2.2 nathanw static u_int32_t
292 1.8.2.2 nathanw agp_i810_get_aperture(struct agp_softc *sc)
293 1.8.2.2 nathanw {
294 1.8.2.6 thorpej struct agp_i810_softc *isc = sc->as_chipc;
295 1.8.2.6 thorpej pcireg_t reg;
296 1.8.2.6 thorpej
297 1.8.2.6 thorpej if (isc->chiptype == CHIP_I810) {
298 1.8.2.6 thorpej u_int16_t miscc;
299 1.8.2.2 nathanw
300 1.8.2.6 thorpej reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I810_SMRAM);
301 1.8.2.6 thorpej miscc = (u_int16_t)(reg >> 16);
302 1.8.2.6 thorpej if ((miscc & AGP_I810_MISCC_WINSIZE) ==
303 1.8.2.6 thorpej AGP_I810_MISCC_WINSIZE_32)
304 1.8.2.6 thorpej return 32 * 1024 * 1024;
305 1.8.2.6 thorpej else
306 1.8.2.6 thorpej return 64 * 1024 * 1024;
307 1.8.2.6 thorpej } else { /* I830 */
308 1.8.2.6 thorpej u_int16_t gcc1;
309 1.8.2.6 thorpej
310 1.8.2.6 thorpej reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0);
311 1.8.2.6 thorpej gcc1 = (u_int16_t)(reg >> 16);
312 1.8.2.6 thorpej if ((gcc1 & AGP_I830_GCC1_GMASIZE) == AGP_I830_GCC1_GMASIZE_64)
313 1.8.2.6 thorpej return 64 * 1024 * 1024;
314 1.8.2.6 thorpej else
315 1.8.2.6 thorpej return 128 * 1024 * 1024;
316 1.8.2.6 thorpej }
317 1.8.2.2 nathanw }
318 1.8.2.2 nathanw
319 1.8.2.2 nathanw static int
320 1.8.2.2 nathanw agp_i810_set_aperture(struct agp_softc *sc, u_int32_t aperture)
321 1.8.2.2 nathanw {
322 1.8.2.6 thorpej struct agp_i810_softc *isc = sc->as_chipc;
323 1.8.2.6 thorpej pcireg_t reg;
324 1.8.2.2 nathanw
325 1.8.2.6 thorpej if (isc->chiptype == CHIP_I810) {
326 1.8.2.6 thorpej u_int16_t miscc;
327 1.8.2.6 thorpej
328 1.8.2.6 thorpej /*
329 1.8.2.6 thorpej * Double check for sanity.
330 1.8.2.6 thorpej */
331 1.8.2.6 thorpej if (aperture != (32 * 1024 * 1024) &&
332 1.8.2.6 thorpej aperture != (64 * 1024 * 1024)) {
333 1.8.2.6 thorpej printf("%s: bad aperture size %d\n",
334 1.8.2.6 thorpej sc->as_dev.dv_xname, aperture);
335 1.8.2.6 thorpej return EINVAL;
336 1.8.2.6 thorpej }
337 1.8.2.2 nathanw
338 1.8.2.6 thorpej reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I810_SMRAM);
339 1.8.2.6 thorpej miscc = (u_int16_t)(reg >> 16);
340 1.8.2.6 thorpej miscc &= ~AGP_I810_MISCC_WINSIZE;
341 1.8.2.6 thorpej if (aperture == 32 * 1024 * 1024)
342 1.8.2.6 thorpej miscc |= AGP_I810_MISCC_WINSIZE_32;
343 1.8.2.6 thorpej else
344 1.8.2.6 thorpej miscc |= AGP_I810_MISCC_WINSIZE_64;
345 1.8.2.6 thorpej
346 1.8.2.6 thorpej reg &= 0x0000ffff;
347 1.8.2.6 thorpej reg |= ((pcireg_t)miscc) << 16;
348 1.8.2.6 thorpej pci_conf_write(sc->as_pc, sc->as_tag, AGP_I810_SMRAM, reg);
349 1.8.2.6 thorpej } else { /* I830 */
350 1.8.2.6 thorpej u_int16_t gcc1;
351 1.8.2.6 thorpej
352 1.8.2.6 thorpej if (aperture != (64 * 1024 * 1024) &&
353 1.8.2.6 thorpej aperture != (128 * 1024 * 1024)) {
354 1.8.2.6 thorpej printf("%s: bad aperture size %d\n",
355 1.8.2.6 thorpej sc->as_dev.dv_xname, aperture);
356 1.8.2.6 thorpej return EINVAL;
357 1.8.2.6 thorpej }
358 1.8.2.6 thorpej reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0);
359 1.8.2.6 thorpej gcc1 = (u_int16_t)(reg >> 16);
360 1.8.2.6 thorpej gcc1 &= ~AGP_I830_GCC1_GMASIZE;
361 1.8.2.6 thorpej if (aperture == 64 * 1024 * 1024)
362 1.8.2.6 thorpej gcc1 |= AGP_I830_GCC1_GMASIZE_64;
363 1.8.2.6 thorpej else
364 1.8.2.6 thorpej gcc1 |= AGP_I830_GCC1_GMASIZE_128;
365 1.8.2.6 thorpej
366 1.8.2.6 thorpej reg &= 0x0000ffff;
367 1.8.2.6 thorpej reg |= ((pcireg_t)gcc1) << 16;
368 1.8.2.6 thorpej pci_conf_write(sc->as_pc, sc->as_tag, AGP_I830_GCC0, reg);
369 1.8.2.6 thorpej }
370 1.8.2.2 nathanw
371 1.8.2.2 nathanw return 0;
372 1.8.2.2 nathanw }
373 1.8.2.2 nathanw
374 1.8.2.2 nathanw static int
375 1.8.2.2 nathanw agp_i810_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical)
376 1.8.2.2 nathanw {
377 1.8.2.2 nathanw struct agp_i810_softc *isc = sc->as_chipc;
378 1.8.2.2 nathanw
379 1.8.2.6 thorpej if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) {
380 1.8.2.6 thorpej #ifdef DEBUG
381 1.8.2.6 thorpej printf("%s: failed: offset 0x%08x, shift %d, entries %d\n",
382 1.8.2.6 thorpej sc->as_dev.dv_xname, (int)offset, AGP_PAGE_SHIFT,
383 1.8.2.6 thorpej isc->gatt->ag_entries);
384 1.8.2.6 thorpej #endif
385 1.8.2.2 nathanw return EINVAL;
386 1.8.2.6 thorpej }
387 1.8.2.6 thorpej
388 1.8.2.6 thorpej if (isc->chiptype == CHIP_I810) {
389 1.8.2.6 thorpej if ((offset >> AGP_PAGE_SHIFT) < isc->stolen) {
390 1.8.2.6 thorpej #ifdef DEBUG
391 1.8.2.6 thorpej printf("%s: trying to bind into stolen memory",
392 1.8.2.6 thorpej sc->as_dev.dv_xname);
393 1.8.2.6 thorpej #endif
394 1.8.2.6 thorpej return EINVAL;
395 1.8.2.6 thorpej }
396 1.8.2.6 thorpej }
397 1.8.2.2 nathanw
398 1.8.2.2 nathanw WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4,
399 1.8.2.2 nathanw physical | 1);
400 1.8.2.2 nathanw return 0;
401 1.8.2.2 nathanw }
402 1.8.2.2 nathanw
403 1.8.2.2 nathanw static int
404 1.8.2.2 nathanw agp_i810_unbind_page(struct agp_softc *sc, off_t offset)
405 1.8.2.2 nathanw {
406 1.8.2.2 nathanw struct agp_i810_softc *isc = sc->as_chipc;
407 1.8.2.2 nathanw
408 1.8.2.2 nathanw if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT))
409 1.8.2.2 nathanw return EINVAL;
410 1.8.2.2 nathanw
411 1.8.2.6 thorpej if (isc->chiptype == CHIP_I830 ) {
412 1.8.2.6 thorpej if ((offset >> AGP_PAGE_SHIFT) < isc->stolen) {
413 1.8.2.6 thorpej #ifdef DEBUG
414 1.8.2.6 thorpej printf("%s: trying to unbind from stolen memory",
415 1.8.2.6 thorpej sc->as_dev.dv_xname);
416 1.8.2.6 thorpej #endif
417 1.8.2.6 thorpej return EINVAL;
418 1.8.2.6 thorpej }
419 1.8.2.6 thorpej }
420 1.8.2.6 thorpej
421 1.8.2.2 nathanw WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, 0);
422 1.8.2.2 nathanw return 0;
423 1.8.2.2 nathanw }
424 1.8.2.2 nathanw
425 1.8.2.2 nathanw /*
426 1.8.2.2 nathanw * Writing via memory mapped registers already flushes all TLBs.
427 1.8.2.2 nathanw */
428 1.8.2.2 nathanw static void
429 1.8.2.2 nathanw agp_i810_flush_tlb(struct agp_softc *sc)
430 1.8.2.2 nathanw {
431 1.8.2.2 nathanw }
432 1.8.2.2 nathanw
433 1.8.2.2 nathanw static int
434 1.8.2.2 nathanw agp_i810_enable(struct agp_softc *sc, u_int32_t mode)
435 1.8.2.2 nathanw {
436 1.8.2.2 nathanw
437 1.8.2.2 nathanw return 0;
438 1.8.2.2 nathanw }
439 1.8.2.2 nathanw
440 1.8.2.2 nathanw static struct agp_memory *
441 1.8.2.2 nathanw agp_i810_alloc_memory(struct agp_softc *sc, int type, vsize_t size)
442 1.8.2.2 nathanw {
443 1.8.2.2 nathanw struct agp_i810_softc *isc = sc->as_chipc;
444 1.8.2.2 nathanw struct agp_memory *mem;
445 1.8.2.2 nathanw
446 1.8.2.2 nathanw if ((size & (AGP_PAGE_SIZE - 1)) != 0)
447 1.8.2.2 nathanw return 0;
448 1.8.2.2 nathanw
449 1.8.2.2 nathanw if (sc->as_allocated + size > sc->as_maxmem)
450 1.8.2.2 nathanw return 0;
451 1.8.2.2 nathanw
452 1.8.2.2 nathanw if (type == 1) {
453 1.8.2.2 nathanw /*
454 1.8.2.2 nathanw * Mapping local DRAM into GATT.
455 1.8.2.2 nathanw */
456 1.8.2.6 thorpej if (isc->chiptype == CHIP_I830 )
457 1.8.2.6 thorpej return 0;
458 1.8.2.2 nathanw if (size != isc->dcache_size)
459 1.8.2.2 nathanw return 0;
460 1.8.2.2 nathanw } else if (type == 2) {
461 1.8.2.2 nathanw /*
462 1.8.2.2 nathanw * Bogus mapping of a single page for the hardware cursor.
463 1.8.2.2 nathanw */
464 1.8.2.2 nathanw if (size != AGP_PAGE_SIZE)
465 1.8.2.2 nathanw return 0;
466 1.8.2.2 nathanw }
467 1.8.2.2 nathanw
468 1.8.2.4 nathanw mem = malloc(sizeof *mem, M_AGP, M_WAITOK|M_ZERO);
469 1.8.2.2 nathanw if (mem == NULL)
470 1.8.2.2 nathanw return NULL;
471 1.8.2.2 nathanw mem->am_id = sc->as_nextid++;
472 1.8.2.2 nathanw mem->am_size = size;
473 1.8.2.2 nathanw mem->am_type = type;
474 1.8.2.2 nathanw
475 1.8.2.2 nathanw if (type == 2) {
476 1.8.2.2 nathanw /*
477 1.8.2.2 nathanw * Allocate and wire down the page now so that we can
478 1.8.2.2 nathanw * get its physical address.
479 1.8.2.2 nathanw */
480 1.8.2.2 nathanw mem->am_dmaseg = malloc(sizeof *mem->am_dmaseg, M_AGP,
481 1.8.2.2 nathanw M_WAITOK);
482 1.8.2.2 nathanw if (mem->am_dmaseg == NULL) {
483 1.8.2.2 nathanw free(mem, M_AGP);
484 1.8.2.2 nathanw return NULL;
485 1.8.2.2 nathanw }
486 1.8.2.2 nathanw if (agp_alloc_dmamem(sc->as_dmat, size, 0,
487 1.8.2.2 nathanw &mem->am_dmamap, &mem->am_virtual, &mem->am_physical,
488 1.8.2.2 nathanw mem->am_dmaseg, 1, &mem->am_nseg) != 0) {
489 1.8.2.2 nathanw free(mem->am_dmaseg, M_AGP);
490 1.8.2.2 nathanw free(mem, M_AGP);
491 1.8.2.2 nathanw return NULL;
492 1.8.2.2 nathanw }
493 1.8.2.2 nathanw } else if (type != 1) {
494 1.8.2.2 nathanw if (bus_dmamap_create(sc->as_dmat, size, size / PAGE_SIZE + 1,
495 1.8.2.2 nathanw size, 0, BUS_DMA_NOWAIT,
496 1.8.2.2 nathanw &mem->am_dmamap) != 0) {
497 1.8.2.2 nathanw free(mem, M_AGP);
498 1.8.2.2 nathanw return NULL;
499 1.8.2.2 nathanw }
500 1.8.2.2 nathanw }
501 1.8.2.2 nathanw
502 1.8.2.2 nathanw TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link);
503 1.8.2.2 nathanw sc->as_allocated += size;
504 1.8.2.2 nathanw
505 1.8.2.2 nathanw return mem;
506 1.8.2.2 nathanw }
507 1.8.2.2 nathanw
508 1.8.2.2 nathanw static int
509 1.8.2.2 nathanw agp_i810_free_memory(struct agp_softc *sc, struct agp_memory *mem)
510 1.8.2.2 nathanw {
511 1.8.2.2 nathanw if (mem->am_is_bound)
512 1.8.2.2 nathanw return EBUSY;
513 1.8.2.2 nathanw
514 1.8.2.2 nathanw if (mem->am_type == 2) {
515 1.8.2.2 nathanw agp_free_dmamem(sc->as_dmat, mem->am_size, mem->am_dmamap,
516 1.8.2.2 nathanw mem->am_virtual, mem->am_dmaseg, mem->am_nseg);
517 1.8.2.2 nathanw free(mem->am_dmaseg, M_AGP);
518 1.8.2.2 nathanw }
519 1.8.2.2 nathanw
520 1.8.2.2 nathanw sc->as_allocated -= mem->am_size;
521 1.8.2.2 nathanw TAILQ_REMOVE(&sc->as_memory, mem, am_link);
522 1.8.2.2 nathanw free(mem, M_AGP);
523 1.8.2.2 nathanw return 0;
524 1.8.2.2 nathanw }
525 1.8.2.2 nathanw
526 1.8.2.2 nathanw static int
527 1.8.2.2 nathanw agp_i810_bind_memory(struct agp_softc *sc, struct agp_memory *mem,
528 1.8.2.2 nathanw off_t offset)
529 1.8.2.2 nathanw {
530 1.8.2.2 nathanw struct agp_i810_softc *isc = sc->as_chipc;
531 1.8.2.2 nathanw u_int32_t regval, i;
532 1.8.2.2 nathanw
533 1.8.2.2 nathanw /*
534 1.8.2.2 nathanw * XXX evil hack: the PGTBL_CTL appearently gets overwritten by the
535 1.8.2.2 nathanw * X server for mysterious reasons which leads to crashes if we write
536 1.8.2.2 nathanw * to the GTT through the MMIO window.
537 1.8.2.2 nathanw * Until the issue is solved, simply restore it.
538 1.8.2.2 nathanw */
539 1.8.2.2 nathanw regval = bus_space_read_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL);
540 1.8.2.2 nathanw if (regval != (isc->gatt->ag_physical | 1)) {
541 1.8.2.2 nathanw printf("agp_i810_bind_memory: PGTBL_CTL is 0x%x - fixing\n",
542 1.8.2.2 nathanw regval);
543 1.8.2.2 nathanw bus_space_write_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL,
544 1.8.2.2 nathanw isc->gatt->ag_physical | 1);
545 1.8.2.2 nathanw }
546 1.8.2.2 nathanw
547 1.8.2.2 nathanw if (mem->am_type == 2) {
548 1.8.2.2 nathanw WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4,
549 1.8.2.2 nathanw mem->am_physical | 1);
550 1.8.2.2 nathanw mem->am_offset = offset;
551 1.8.2.2 nathanw mem->am_is_bound = 1;
552 1.8.2.2 nathanw return 0;
553 1.8.2.2 nathanw }
554 1.8.2.2 nathanw
555 1.8.2.2 nathanw if (mem->am_type != 1)
556 1.8.2.2 nathanw return agp_generic_bind_memory(sc, mem, offset);
557 1.8.2.2 nathanw
558 1.8.2.6 thorpej if (isc->chiptype == CHIP_I830)
559 1.8.2.6 thorpej return EINVAL;
560 1.8.2.6 thorpej
561 1.8.2.2 nathanw for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) {
562 1.8.2.2 nathanw WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4,
563 1.8.2.2 nathanw i | 3);
564 1.8.2.2 nathanw }
565 1.8.2.5 nathanw mem->am_is_bound = 1;
566 1.8.2.2 nathanw return 0;
567 1.8.2.2 nathanw }
568 1.8.2.2 nathanw
569 1.8.2.2 nathanw static int
570 1.8.2.2 nathanw agp_i810_unbind_memory(struct agp_softc *sc, struct agp_memory *mem)
571 1.8.2.2 nathanw {
572 1.8.2.2 nathanw struct agp_i810_softc *isc = sc->as_chipc;
573 1.8.2.2 nathanw u_int32_t i;
574 1.8.2.2 nathanw
575 1.8.2.2 nathanw if (mem->am_type == 2) {
576 1.8.2.2 nathanw WRITE4(AGP_I810_GTT +
577 1.8.2.2 nathanw (u_int32_t)(mem->am_offset >> AGP_PAGE_SHIFT) * 4,
578 1.8.2.2 nathanw 0);
579 1.8.2.2 nathanw mem->am_offset = 0;
580 1.8.2.2 nathanw mem->am_is_bound = 0;
581 1.8.2.2 nathanw return 0;
582 1.8.2.2 nathanw }
583 1.8.2.2 nathanw
584 1.8.2.2 nathanw if (mem->am_type != 1)
585 1.8.2.2 nathanw return agp_generic_unbind_memory(sc, mem);
586 1.8.2.2 nathanw
587 1.8.2.6 thorpej if (isc->chiptype == CHIP_I830)
588 1.8.2.6 thorpej return EINVAL;
589 1.8.2.6 thorpej
590 1.8.2.2 nathanw for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE)
591 1.8.2.2 nathanw WRITE4(AGP_I810_GTT + (i >> AGP_PAGE_SHIFT) * 4, 0);
592 1.8.2.5 nathanw mem->am_is_bound = 0;
593 1.8.2.2 nathanw return 0;
594 1.8.2.2 nathanw }
595