xref: /openbsd/sys/dev/pci/agp.c (revision 09467b48)
1 /* $OpenBSD: agp.c,v 1.49 2015/12/22 21:05:37 kettenis Exp $ */
2 /*-
3  * Copyright (c) 2000 Doug Rabson
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *	$FreeBSD: src/sys/pci/agp.c,v 1.12 2001/05/19 01:28:07 alfred Exp $
28  */
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/malloc.h>
33 
34 #include <uvm/uvm_extern.h>
35 
36 #include <dev/pci/pcivar.h>
37 #include <dev/pci/pcidevs.h>
38 
39 #include <dev/ic/mc6845reg.h>
40 #include <dev/ic/pcdisplayvar.h>
41 #include <dev/ic/vgareg.h>
42 #include <dev/ic/vgavar.h>
43 
44 #include <dev/pci/agpvar.h>
45 #include <dev/pci/agpreg.h>
46 
47 void	agp_attach(struct device *, struct device *, void *);
48 int	agp_probe(struct device *, void *, void *);
49 
50 int	agpvga_match(struct pci_attach_args *);
51 
52 int
53 agpdev_print(void *aux, const char *pnp)
54 {
55 	if (pnp) {
56 		printf("agp at %s", pnp);
57 	}
58 	return (UNCONF);
59 }
60 
61 int
62 agpbus_probe(struct agp_attach_args *aa)
63 {
64 	struct pci_attach_args	*pa = aa->aa_pa;
65 
66 	if (strncmp(aa->aa_busname, "agp", 3) == 0 &&
67 	    PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
68 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
69 		return (1);
70 	return (0);
71 }
72 
73 /*
74  * Find the video card hanging off the agp bus XXX assumes only one bus
75  */
76 int
77 agpvga_match(struct pci_attach_args *pa)
78 {
79 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_DISPLAY &&
80 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_DISPLAY_VGA) {
81 		if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
82 		    NULL, NULL))
83 			return (1);
84 	}
85 	return (0);
86 }
87 
88 struct device *
89 agp_attach_bus(struct pci_attach_args *pa, const struct agp_methods *methods,
90     bus_addr_t apaddr, bus_size_t apsize, struct device *dev)
91 {
92 	struct agpbus_attach_args arg;
93 
94 	arg.aa_methods = methods;
95 	arg.aa_pa = pa;
96 	arg.aa_apaddr = apaddr;
97 	arg.aa_apsize = apsize;
98 
99 	printf("\n"); /* newline from the driver that called us */
100 	return (config_found(dev, &arg, agpdev_print));
101 }
102 
103 int
104 agp_probe(struct device *parent, void *match, void *aux)
105 {
106 	/*
107 	 * we don't do any checking here, driver we're attaching this
108 	 * interface to should have already done it.
109 	 */
110 	return (1);
111 }
112 
113 void
114 agp_attach(struct device *parent, struct device *self, void *aux)
115 {
116 	struct agpbus_attach_args *aa = aux;
117 	struct pci_attach_args *pa = aa->aa_pa;
118 	struct agp_softc *sc = (struct agp_softc *)self;
119 	u_int memsize;
120 	int i;
121 
122 	sc->sc_chipc = parent;
123 	sc->sc_methods = aa->aa_methods;
124 	sc->sc_apaddr = aa->aa_apaddr;
125 	sc->sc_apsize = aa->aa_apsize;
126 
127 	static const int agp_max[][2] = {
128 		{0,		0},
129 		{32,		4},
130 		{64,		28},
131 		{128,		96},
132 		{256,		204},
133 		{512,		440},
134 		{1024,		942},
135 		{2048,		1920},
136 		{4096,		3932}
137 	};
138 
139 	/*
140 	 * Work out an upper bound for agp memory allocation. This
141 	 * uses a heuristic table from the Linux driver.
142 	 */
143 	memsize = ptoa(physmem) >> 20;
144 
145 	for (i = 0; i < nitems(agp_max) && memsize > agp_max[i][0]; i++)
146 		;
147 	if (i == nitems(agp_max))
148 		i = nitems(agp_max) - 1;
149 	sc->sc_maxmem = agp_max[i][1] << 20;
150 
151 	sc->sc_pcitag = pa->pa_tag;
152 	sc->sc_pc = pa->pa_pc;
153 	sc->sc_id = pa->pa_id;
154 	sc->sc_dmat = pa->pa_dmat;
155 	sc->sc_memt = pa->pa_memt;
156 
157 	pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP,
158 	    &sc->sc_capoff, NULL);
159 
160 	printf(": aperture at 0x%lx, size 0x%lx\n", (u_long)sc->sc_apaddr,
161 	    (u_long)sc->sc_apsize);
162 }
163 
164 struct cfattach agp_ca = {
165 	sizeof(struct agp_softc), agp_probe, agp_attach,
166 	NULL, NULL
167 };
168 
169 struct cfdriver agp_cd = {
170 	NULL, "agp", DV_DULL
171 };
172 
173 struct agp_gatt *
174 agp_alloc_gatt(bus_dma_tag_t dmat, u_int32_t apsize)
175 {
176 	struct agp_gatt		*gatt;
177 	u_int32_t	 	 entries = apsize >> AGP_PAGE_SHIFT;
178 
179 	gatt = malloc(sizeof(*gatt), M_AGP, M_NOWAIT | M_ZERO);
180 	if (!gatt)
181 		return (NULL);
182 	gatt->ag_entries = entries;
183 	gatt->ag_size = entries * sizeof(u_int32_t);
184 
185 	if (agp_alloc_dmamem(dmat, gatt->ag_size, &gatt->ag_dmamap,
186 	    &gatt->ag_physical, &gatt->ag_dmaseg) != 0) {
187 		free(gatt, M_AGP, sizeof *gatt);
188 		return (NULL);
189 	}
190 
191 	if (bus_dmamem_map(dmat, &gatt->ag_dmaseg, 1, gatt->ag_size,
192 	    (caddr_t *)&gatt->ag_virtual, BUS_DMA_NOWAIT) != 0) {
193 		agp_free_dmamem(dmat, gatt->ag_size, gatt->ag_dmamap,
194 		    &gatt->ag_dmaseg);
195 		free(gatt, M_AGP, sizeof *gatt);
196 		return (NULL);
197 	}
198 
199 	agp_flush_cache();
200 
201 	return (gatt);
202 }
203 
204 void
205 agp_free_gatt(bus_dma_tag_t dmat, struct agp_gatt *gatt)
206 {
207 	bus_dmamem_unmap(dmat, (caddr_t)gatt->ag_virtual, gatt->ag_size);
208 	agp_free_dmamem(dmat, gatt->ag_size, gatt->ag_dmamap, &gatt->ag_dmaseg);
209 	free(gatt, M_AGP, sizeof *gatt);
210 }
211 
212 int
213 agp_generic_enable(struct agp_softc *sc, u_int32_t mode)
214 {
215 	struct pci_attach_args	pa;
216 	pcireg_t		tstatus, mstatus, command;
217 	int			rq, sba, fw, rate, capoff;
218 
219 	if (pci_find_device(&pa, agpvga_match) == 0 ||
220 	    pci_get_capability(pa.pa_pc, pa.pa_tag, PCI_CAP_AGP,
221 	    &capoff, NULL) == 0) {
222 		printf("agp_generic_enable: not an AGP capable device\n");
223 		return (-1);
224 	}
225 
226 	tstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
227 	    sc->sc_capoff + AGP_STATUS);
228 	/* display agp mode */
229 	mstatus = pci_conf_read(pa.pa_pc, pa.pa_tag,
230 	    capoff + AGP_STATUS);
231 
232 	/* Set RQ to the min of mode, tstatus and mstatus */
233 	rq = AGP_MODE_GET_RQ(mode);
234 	if (AGP_MODE_GET_RQ(tstatus) < rq)
235 		rq = AGP_MODE_GET_RQ(tstatus);
236 	if (AGP_MODE_GET_RQ(mstatus) < rq)
237 		rq = AGP_MODE_GET_RQ(mstatus);
238 
239 	/* Set SBA if all three can deal with SBA */
240 	sba = (AGP_MODE_GET_SBA(tstatus)
241 	    & AGP_MODE_GET_SBA(mstatus)
242 	    & AGP_MODE_GET_SBA(mode));
243 
244 	/* Similar for FW */
245 	fw = (AGP_MODE_GET_FW(tstatus)
246 	    & AGP_MODE_GET_FW(mstatus)
247 	    & AGP_MODE_GET_FW(mode));
248 
249 	/* Figure out the max rate */
250 	rate = (AGP_MODE_GET_RATE(tstatus)
251 	    & AGP_MODE_GET_RATE(mstatus)
252 	    & AGP_MODE_GET_RATE(mode));
253 	if (rate & AGP_MODE_RATE_4x)
254 		rate = AGP_MODE_RATE_4x;
255 	else if (rate & AGP_MODE_RATE_2x)
256 		rate = AGP_MODE_RATE_2x;
257 	else
258 		rate = AGP_MODE_RATE_1x;
259 
260 	/* Construct the new mode word and tell the hardware  */
261 	command = AGP_MODE_SET_RQ(0, rq);
262 	command = AGP_MODE_SET_SBA(command, sba);
263 	command = AGP_MODE_SET_FW(command, fw);
264 	command = AGP_MODE_SET_RATE(command, rate);
265 	command = AGP_MODE_SET_AGP(command, 1);
266 
267 	pci_conf_write(sc->sc_pc, sc->sc_pcitag,
268 	    sc->sc_capoff + AGP_COMMAND, command);
269 	pci_conf_write(pa.pa_pc, pa.pa_tag, capoff + AGP_COMMAND, command);
270 	return (0);
271 }
272 
273 /*
274  * Allocates a single-segment block of zeroed, wired dma memory.
275  */
276 int
277 agp_alloc_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t *mapp,
278     bus_addr_t *baddr, bus_dma_segment_t *seg)
279 {
280 	int error, level = 0, nseg;
281 
282 	if ((error = bus_dmamem_alloc(tag, size, PAGE_SIZE, 0,
283 	    seg, 1, &nseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO)) != 0)
284 		goto out;
285 	level++;
286 
287 	if ((error = bus_dmamap_create(tag, size, nseg, size, 0,
288 	    BUS_DMA_NOWAIT, mapp)) != 0)
289 		goto out;
290 	level++;
291 
292 	if ((error = bus_dmamap_load_raw(tag, *mapp, seg, nseg, size,
293 	    BUS_DMA_NOWAIT)) != 0)
294 		goto out;
295 
296 	*baddr = (*mapp)->dm_segs[0].ds_addr;
297 
298 	return (0);
299 out:
300 	switch (level) {
301 	case 2:
302 		bus_dmamap_destroy(tag, *mapp);
303 		/* FALLTHROUGH */
304 	case 1:
305 		bus_dmamem_free(tag, seg, nseg);
306 		break;
307 	default:
308 		break;
309 	}
310 
311 	return (error);
312 }
313 
314 void
315 agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map,
316     bus_dma_segment_t *seg)
317 {
318 	bus_dmamap_unload(tag, map);
319 	bus_dmamap_destroy(tag, map);
320 	bus_dmamem_free(tag, seg, 1);
321 }
322 
323 /* Implementation of the kernel api */
324 
325 void *
326 agp_find_device(int unit)
327 {
328 	if (unit >= agp_cd.cd_ndevs || unit < 0)
329 		return (NULL);
330 	return (agp_cd.cd_devs[unit]);
331 }
332 
333 enum agp_acquire_state
334 agp_state(void *dev)
335 {
336 	struct agp_softc *sc = (struct agp_softc *) dev;
337         return (sc->sc_state);
338 }
339 
340 void
341 agp_get_info(void *dev, struct agp_info *info)
342 {
343 	struct agp_softc *sc = (struct agp_softc *)dev;
344 
345 	if (sc->sc_capoff != 0)
346 		info->ai_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag,
347 		    AGP_STATUS + sc->sc_capoff);
348 	else
349 		info->ai_mode = 0; /* i810 doesn't have real AGP */
350 	info->ai_aperture_base = sc->sc_apaddr;
351 	info->ai_aperture_size = sc->sc_apsize;
352 	info->ai_memory_allowed = sc->sc_maxmem;
353 	info->ai_memory_used = sc->sc_allocated;
354 	info->ai_devid = sc->sc_id;
355 }
356 
357 int
358 agp_acquire(void *dev)
359 {
360 	struct agp_softc *sc = (struct agp_softc *)dev;
361 
362 	if (sc->sc_chipc == NULL)
363 		return (EINVAL);
364 
365 	if (sc->sc_state != AGP_ACQUIRE_FREE)
366 		return (EBUSY);
367 	sc->sc_state = AGP_ACQUIRE_KERNEL;
368 
369 	return (0);
370 }
371 
372 int
373 agp_release(void *dev)
374 {
375 	struct agp_softc *sc = (struct agp_softc *)dev;
376 
377 	if (sc->sc_state == AGP_ACQUIRE_FREE)
378 		return (0);
379 
380 	if (sc->sc_state != AGP_ACQUIRE_KERNEL)
381 		return (EBUSY);
382 
383 	sc->sc_state = AGP_ACQUIRE_FREE;
384 	return (0);
385 }
386 
387 int
388 agp_enable(void *dev, u_int32_t mode)
389 {
390 	struct agp_softc	*sc = dev;
391 	int			 ret;
392 
393 	if (sc->sc_methods->enable != NULL) {
394 		ret = sc->sc_methods->enable(sc->sc_chipc, mode);
395 	} else {
396 		ret = agp_generic_enable(sc, mode);
397 	}
398 	return (ret);
399 }
400 
401 paddr_t
402 agp_mmap(struct agp_softc *sc, off_t off, int prot)
403 {
404 	if (sc->sc_chipc == NULL)
405 		return (-1);
406 
407 	if (off >= sc->sc_apsize)
408 		return (-1);
409 
410 	if (sc->sc_apaddr == 0)
411 		return (-1);
412 
413 	return bus_space_mmap(sc->sc_memt, sc->sc_apaddr, off, prot, 0);
414 }
415