1150236Sanholt/*-
2150236Sanholt * Copyright (c) 2005 Eric Anholt
3150236Sanholt * All rights reserved.
4150236Sanholt *
5150236Sanholt * Redistribution and use in source and binary forms, with or without
6150236Sanholt * modification, are permitted provided that the following conditions
7150236Sanholt * are met:
8150236Sanholt * 1. Redistributions of source code must retain the above copyright
9150236Sanholt *    notice, this list of conditions and the following disclaimer.
10150236Sanholt * 2. Redistributions in binary form must reproduce the above copyright
11150236Sanholt *    notice, this list of conditions and the following disclaimer in the
12150236Sanholt *    documentation and/or other materials provided with the distribution.
13150236Sanholt *
14150236Sanholt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15150236Sanholt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16150236Sanholt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17150236Sanholt * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18150236Sanholt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19150236Sanholt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20150236Sanholt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21150236Sanholt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22150236Sanholt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23150236Sanholt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24150236Sanholt * SUCH DAMAGE.
25150236Sanholt *
26150236Sanholt * Based on reading the Linux 2.6.8.1 driver by Dave Jones.
27150236Sanholt */
28150236Sanholt
29150236Sanholt#include <sys/cdefs.h>
30150236Sanholt__FBSDID("$FreeBSD$");
31150236Sanholt
32150236Sanholt#include "opt_bus.h"
33150236Sanholt
34150236Sanholt#include <sys/param.h>
35150236Sanholt#include <sys/systm.h>
36150236Sanholt#include <sys/malloc.h>
37150236Sanholt#include <sys/kernel.h>
38150236Sanholt#include <sys/module.h>
39150236Sanholt#include <sys/bus.h>
40150236Sanholt#include <sys/lock.h>
41150236Sanholt#include <sys/mutex.h>
42150236Sanholt#include <sys/proc.h>
43150236Sanholt
44173573Sjhb#include <dev/agp/agppriv.h>
45173573Sjhb#include <dev/agp/agpreg.h>
46150236Sanholt#include <dev/pci/pcivar.h>
47150236Sanholt#include <dev/pci/pcireg.h>
48150236Sanholt
49150236Sanholt#include <vm/vm.h>
50150236Sanholt#include <vm/vm_object.h>
51150236Sanholt#include <vm/pmap.h>
52150236Sanholt#include <machine/bus.h>
53150236Sanholt#include <machine/resource.h>
54150236Sanholt#include <sys/rman.h>
55150236Sanholt
56150236SanholtMALLOC_DECLARE(M_AGP);
57150236Sanholt
58150236Sanholt#define READ4(off)	bus_space_read_4(sc->bst, sc->bsh, off)
59150236Sanholt#define WRITE4(off,v)	bus_space_write_4(sc->bst, sc->bsh, off, v)
60150236Sanholt
61150236Sanholtstruct agp_ati_softc {
62150236Sanholt	struct agp_softc agp;
63150236Sanholt	struct resource *regs;	/* memory mapped control registers */
64150236Sanholt	bus_space_tag_t bst;	/* bus_space tag */
65150236Sanholt	bus_space_handle_t bsh;	/* bus_space handle */
66150236Sanholt	u_int32_t	initial_aperture; /* aperture size at startup */
67150236Sanholt	char		is_rs300;
68150236Sanholt
69150236Sanholt	/* The GATT */
70150236Sanholt	u_int32_t	ag_entries;
71150236Sanholt	u_int32_t      *ag_virtual;	/* virtual address of gatt */
72150236Sanholt	u_int32_t      *ag_vdir;	/* virtual address of page dir */
73150236Sanholt	vm_offset_t	ag_pdir;	/* physical address of page dir */
74150236Sanholt};
75150236Sanholt
76150236Sanholt
77150236Sanholtstatic const char*
78150236Sanholtagp_ati_match(device_t dev)
79150236Sanholt{
80150236Sanholt	if (pci_get_class(dev) != PCIC_BRIDGE ||
81150236Sanholt	    pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
82150236Sanholt		return NULL;
83150236Sanholt
84150236Sanholt	if (agp_find_caps(dev) == 0)
85150236Sanholt		return NULL;
86150236Sanholt
87150236Sanholt	switch (pci_get_devid(dev)) {
88150236Sanholt	case 0xcab01002:
89150236Sanholt		return ("ATI RS100 AGP bridge");
90150236Sanholt	case 0xcab21002:
91150236Sanholt		return ("ATI RS200 AGP bridge");
92161788Sanholt	case 0xcbb21002:
93161788Sanholt		return ("ATI RS200M AGP bridge");
94150236Sanholt	case 0xcab31002:
95150236Sanholt		return ("ATI RS250 AGP bridge");
96150236Sanholt	case 0x58301002:
97150236Sanholt		return ("ATI RS300_100 AGP bridge");
98150236Sanholt	case 0x58311002:
99150236Sanholt		return ("ATI RS300_133 AGP bridge");
100150236Sanholt	case 0x58321002:
101150236Sanholt		return ("ATI RS300_166 AGP bridge");
102150236Sanholt	case 0x58331002:
103150236Sanholt		return ("ATI RS300_200 AGP bridge");
104150236Sanholt	};
105150236Sanholt
106150236Sanholt	return NULL;
107150236Sanholt}
108150236Sanholt
109150236Sanholtstatic int
110150236Sanholtagp_ati_probe(device_t dev)
111150236Sanholt{
112150236Sanholt	const char *desc;
113150236Sanholt
114150236Sanholt	desc = agp_ati_match(dev);
115150236Sanholt	if (desc) {
116150236Sanholt		device_set_desc(dev, desc);
117150236Sanholt		return 0;
118150236Sanholt	}
119150236Sanholt
120150236Sanholt	return ENXIO;
121150236Sanholt}
122150236Sanholt
123150236Sanholtstatic int
124150236Sanholtagp_ati_alloc_gatt(device_t dev)
125150236Sanholt{
126150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
127150236Sanholt	u_int32_t apsize = AGP_GET_APERTURE(dev);
128150236Sanholt	u_int32_t entries = apsize >> AGP_PAGE_SHIFT;
129150236Sanholt	u_int32_t apbase_offset;
130150236Sanholt	int i;
131150236Sanholt
132150236Sanholt	/* Alloc the GATT -- pointers to pages of AGP memory */
133150236Sanholt	sc->ag_entries = entries;
134150236Sanholt	sc->ag_virtual = malloc(entries * sizeof(u_int32_t), M_AGP,
135150236Sanholt	    M_NOWAIT | M_ZERO);
136150236Sanholt	if (sc->ag_virtual == NULL) {
137150236Sanholt		if (bootverbose)
138150236Sanholt			device_printf(dev, "aperture allocation failed\n");
139150236Sanholt		return ENOMEM;
140150236Sanholt	}
141150236Sanholt
142150236Sanholt	/* Alloc the page directory -- pointers to each page of the GATT */
143150236Sanholt	sc->ag_vdir = malloc(AGP_PAGE_SIZE, M_AGP, M_NOWAIT | M_ZERO);
144150236Sanholt	if (sc->ag_vdir == NULL) {
145150236Sanholt		if (bootverbose)
146150236Sanholt			device_printf(dev, "pagedir allocation failed\n");
147150236Sanholt		free(sc->ag_virtual, M_AGP);
148150236Sanholt		return ENOMEM;
149150236Sanholt	}
150150236Sanholt	sc->ag_pdir = vtophys((vm_offset_t)sc->ag_vdir);
151150236Sanholt
152150236Sanholt	apbase_offset = pci_read_config(dev, AGP_APBASE, 4) >> 22;
153150236Sanholt	/* Fill in the pagedir's pointers to GATT pages */
154150236Sanholt	for (i = 0; i < sc->ag_entries / 1024; i++) {
155150236Sanholt		vm_offset_t va;
156150236Sanholt		vm_offset_t pa;
157150236Sanholt
158150236Sanholt		va = ((vm_offset_t)sc->ag_virtual) + i * AGP_PAGE_SIZE;
159150236Sanholt		pa = vtophys(va);
160150236Sanholt		sc->ag_vdir[apbase_offset + i] = pa | 1;
161150236Sanholt	}
162150236Sanholt
163150236Sanholt	/*
164150236Sanholt	 * Make sure the chipset can see everything.
165150236Sanholt	 */
166150236Sanholt	agp_flush_cache();
167150236Sanholt
168150236Sanholt	return 0;
169150236Sanholt}
170150236Sanholt
171150236Sanholt
172150236Sanholtstatic int
173150236Sanholtagp_ati_attach(device_t dev)
174150236Sanholt{
175150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
176150236Sanholt	int error, rid;
177150236Sanholt	u_int32_t temp;
178150236Sanholt	u_int32_t apsize_reg, agpmode_reg;
179150236Sanholt
180150236Sanholt	error = agp_generic_attach(dev);
181150236Sanholt	if (error)
182150236Sanholt		return error;
183150236Sanholt
184150236Sanholt	switch (pci_get_devid(dev)) {
185150236Sanholt	case 0xcab01002: /* ATI RS100 AGP bridge */
186161788Sanholt	case 0xcab21002: /* ATI RS200 AGP bridge */
187161788Sanholt	case 0xcbb21002: /* ATI RS200M AGP bridge */
188150236Sanholt	case 0xcab31002: /* ATI RS250 AGP bridge */
189150236Sanholt		sc->is_rs300 = 0;
190150236Sanholt		apsize_reg = ATI_RS100_APSIZE;
191150236Sanholt		agpmode_reg = ATI_RS100_IG_AGPMODE;
192150236Sanholt		break;
193150236Sanholt	case 0x58301002: /* ATI RS300_100 AGP bridge */
194150236Sanholt	case 0x58311002: /* ATI RS300_133 AGP bridge */
195150236Sanholt	case 0x58321002: /* ATI RS300_166 AGP bridge */
196150236Sanholt	case 0x58331002: /* ATI RS300_200 AGP bridge */
197150236Sanholt		sc->is_rs300 = 1;
198150236Sanholt		apsize_reg = ATI_RS300_APSIZE;
199150236Sanholt		agpmode_reg = ATI_RS300_IG_AGPMODE;
200150236Sanholt		break;
201150236Sanholt	default:
202150236Sanholt		/* Unknown chipset */
203150236Sanholt		return EINVAL;
204150236Sanholt	};
205150236Sanholt
206150236Sanholt	rid = ATI_GART_MMADDR;
207150236Sanholt	sc->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
208150236Sanholt	if (!sc->regs) {
209150236Sanholt		agp_generic_detach(dev);
210150236Sanholt		return ENOMEM;
211150236Sanholt	}
212150236Sanholt
213150236Sanholt	sc->bst = rman_get_bustag(sc->regs);
214150236Sanholt	sc->bsh = rman_get_bushandle(sc->regs);
215150236Sanholt
216150236Sanholt	sc->initial_aperture = AGP_GET_APERTURE(dev);
217150236Sanholt
218150236Sanholt	for (;;) {
219150236Sanholt		if (agp_ati_alloc_gatt(dev) == 0)
220150236Sanholt			break;
221150236Sanholt
222150236Sanholt		/*
223150236Sanholt		 * Probably contigmalloc failure. Try reducing the
224150236Sanholt		 * aperture so that the gatt size reduces.
225150236Sanholt		 */
226150236Sanholt		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2))
227150236Sanholt			return ENOMEM;
228150236Sanholt	}
229150236Sanholt
230150236Sanholt	temp = pci_read_config(dev, apsize_reg, 4);
231150236Sanholt	pci_write_config(dev, apsize_reg, temp | 1, 4);
232150236Sanholt
233150236Sanholt	pci_write_config(dev, agpmode_reg, 0x20000, 4);
234150236Sanholt
235150236Sanholt	WRITE4(ATI_GART_FEATURE_ID, 0x00060000);
236150236Sanholt
237150236Sanholt	temp = pci_read_config(dev, 4, 4);	/* XXX: Magic reg# */
238150236Sanholt	pci_write_config(dev, 4, temp | (1 << 14), 4);
239150236Sanholt
240150236Sanholt	WRITE4(ATI_GART_BASE, sc->ag_pdir);
241150236Sanholt
242150236Sanholt	AGP_FLUSH_TLB(dev);
243150236Sanholt
244150236Sanholt	return 0;
245150236Sanholt}
246150236Sanholt
247150236Sanholtstatic int
248150236Sanholtagp_ati_detach(device_t dev)
249150236Sanholt{
250150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
251150236Sanholt	u_int32_t apsize_reg, temp;
252150236Sanholt
253173203Sjhb	agp_free_cdev(dev);
254173203Sjhb
255150236Sanholt	if (sc->is_rs300)
256150236Sanholt		apsize_reg = ATI_RS300_APSIZE;
257150236Sanholt	else
258150236Sanholt		apsize_reg = ATI_RS100_APSIZE;
259150236Sanholt
260150236Sanholt	/* Clear the GATT base */
261150236Sanholt	WRITE4(ATI_GART_BASE, 0);
262150236Sanholt
263150236Sanholt	/* Put the aperture back the way it started. */
264150236Sanholt	AGP_SET_APERTURE(dev, sc->initial_aperture);
265150236Sanholt
266150236Sanholt	temp = pci_read_config(dev, apsize_reg, 4);
267150236Sanholt	pci_write_config(dev, apsize_reg, temp & ~1, 4);
268150236Sanholt
269150236Sanholt	free(sc->ag_vdir, M_AGP);
270150236Sanholt	free(sc->ag_virtual, M_AGP);
271150236Sanholt
272150236Sanholt	bus_release_resource(dev, SYS_RES_MEMORY, ATI_GART_MMADDR, sc->regs);
273173203Sjhb	agp_free_res(dev);
274150236Sanholt
275150236Sanholt	return 0;
276150236Sanholt}
277150236Sanholt
278150236Sanholtstatic u_int32_t
279150236Sanholtagp_ati_get_aperture(device_t dev)
280150236Sanholt{
281150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
282150236Sanholt	int size_value;
283150236Sanholt
284150236Sanholt	if (sc->is_rs300)
285150236Sanholt		size_value = pci_read_config(dev, ATI_RS300_APSIZE, 4);
286150236Sanholt	else
287150236Sanholt		size_value = pci_read_config(dev, ATI_RS100_APSIZE, 4);
288150236Sanholt
289150236Sanholt	size_value = (size_value & 0x0000000e) >> 1;
290150236Sanholt	size_value = (32 * 1024 * 1024) << size_value;
291150236Sanholt
292150236Sanholt	return size_value;
293150236Sanholt}
294150236Sanholt
295150236Sanholtstatic int
296150236Sanholtagp_ati_set_aperture(device_t dev, u_int32_t aperture)
297150236Sanholt{
298150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
299150236Sanholt	int size_value;
300150236Sanholt	u_int32_t apsize_reg;
301150236Sanholt
302150236Sanholt	if (sc->is_rs300)
303150236Sanholt		apsize_reg = ATI_RS300_APSIZE;
304150236Sanholt	else
305150236Sanholt		apsize_reg = ATI_RS100_APSIZE;
306150236Sanholt
307150236Sanholt	size_value = pci_read_config(dev, apsize_reg, 4);
308150236Sanholt
309150236Sanholt	size_value &= ~0x0000000e;
310150236Sanholt	size_value |= (ffs(aperture / (32 * 1024 * 1024)) - 1) << 1;
311150236Sanholt
312150236Sanholt	pci_write_config(dev, apsize_reg, size_value, 4);
313150236Sanholt
314150236Sanholt	return 0;
315150236Sanholt}
316150236Sanholt
317150236Sanholtstatic int
318194017Savgagp_ati_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical)
319150236Sanholt{
320150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
321150236Sanholt
322194017Savg	if (offset >= (sc->ag_entries << AGP_PAGE_SHIFT))
323150236Sanholt		return EINVAL;
324150236Sanholt
325150236Sanholt	sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1;
326150236Sanholt
327150236Sanholt	return 0;
328150236Sanholt}
329150236Sanholt
330150236Sanholtstatic int
331194017Savgagp_ati_unbind_page(device_t dev, vm_offset_t offset)
332150236Sanholt{
333150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
334150236Sanholt
335194017Savg	if (offset >= (sc->ag_entries << AGP_PAGE_SHIFT))
336150236Sanholt		return EINVAL;
337150236Sanholt
338150236Sanholt	sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
339150236Sanholt	return 0;
340150236Sanholt}
341150236Sanholt
342150236Sanholtstatic void
343150236Sanholtagp_ati_flush_tlb(device_t dev)
344150236Sanholt{
345150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
346150236Sanholt
347150236Sanholt	/* Set the cache invalidate bit and wait for the chipset to clear */
348150236Sanholt	WRITE4(ATI_GART_CACHE_CNTRL, 1);
349150236Sanholt	(void)READ4(ATI_GART_CACHE_CNTRL);
350150236Sanholt}
351150236Sanholt
352150236Sanholtstatic device_method_t agp_ati_methods[] = {
353150236Sanholt	/* Device interface */
354150236Sanholt	DEVMETHOD(device_probe,		agp_ati_probe),
355150236Sanholt	DEVMETHOD(device_attach,	agp_ati_attach),
356150236Sanholt	DEVMETHOD(device_detach,	agp_ati_detach),
357150236Sanholt	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
358150236Sanholt	DEVMETHOD(device_suspend,	bus_generic_suspend),
359150236Sanholt	DEVMETHOD(device_resume,	bus_generic_resume),
360150236Sanholt
361150236Sanholt	/* AGP interface */
362150236Sanholt	DEVMETHOD(agp_get_aperture,	agp_ati_get_aperture),
363150236Sanholt	DEVMETHOD(agp_set_aperture,	agp_ati_set_aperture),
364150236Sanholt	DEVMETHOD(agp_bind_page,	agp_ati_bind_page),
365150236Sanholt	DEVMETHOD(agp_unbind_page,	agp_ati_unbind_page),
366150236Sanholt	DEVMETHOD(agp_flush_tlb,	agp_ati_flush_tlb),
367150236Sanholt	DEVMETHOD(agp_enable,		agp_generic_enable),
368150236Sanholt	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
369150236Sanholt	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
370150236Sanholt	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
371150236Sanholt	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
372150236Sanholt
373150236Sanholt	{ 0, 0 }
374150236Sanholt};
375150236Sanholt
376150236Sanholtstatic driver_t agp_ati_driver = {
377150236Sanholt	"agp",
378150236Sanholt	agp_ati_methods,
379150236Sanholt	sizeof(struct agp_ati_softc),
380150236Sanholt};
381150236Sanholt
382150236Sanholtstatic devclass_t agp_devclass;
383150236Sanholt
384153572SjhbDRIVER_MODULE(agp_ati, hostb, agp_ati_driver, agp_devclass, 0, 0);
385150236SanholtMODULE_DEPEND(agp_ati, agp, 1, 1, 1);
386150236SanholtMODULE_DEPEND(agp_ati, pci, 1, 1, 1);
387