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: releng/10.2/sys/dev/agp/agp_ati.c 275406 2014-12-02 13:46:13Z tijl $");
31150236Sanholt
32150236Sanholt#include <sys/param.h>
33150236Sanholt#include <sys/systm.h>
34150236Sanholt#include <sys/malloc.h>
35150236Sanholt#include <sys/kernel.h>
36150236Sanholt#include <sys/module.h>
37150236Sanholt#include <sys/bus.h>
38150236Sanholt#include <sys/lock.h>
39150236Sanholt#include <sys/mutex.h>
40150236Sanholt#include <sys/proc.h>
41150236Sanholt
42173573Sjhb#include <dev/agp/agppriv.h>
43173573Sjhb#include <dev/agp/agpreg.h>
44150236Sanholt#include <dev/pci/pcivar.h>
45150236Sanholt#include <dev/pci/pcireg.h>
46150236Sanholt
47150236Sanholt#include <vm/vm.h>
48275406Stijl#include <vm/vm_extern.h>
49275406Stijl#include <vm/vm_kern.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");
104244926Santoine	}
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;
134275406Stijl	sc->ag_virtual = (void *)kmem_alloc_attr(kernel_arena,
135275406Stijl	    entries * sizeof(u_int32_t), M_NOWAIT | M_ZERO, 0, ~0,
136275406Stijl	    VM_MEMATTR_WRITE_COMBINING);
137150236Sanholt	if (sc->ag_virtual == NULL) {
138150236Sanholt		if (bootverbose)
139275406Stijl			device_printf(dev, "GATT allocation failed\n");
140150236Sanholt		return ENOMEM;
141150236Sanholt	}
142150236Sanholt
143150236Sanholt	/* Alloc the page directory -- pointers to each page of the GATT */
144275406Stijl	sc->ag_vdir = (void *)kmem_alloc_attr(kernel_arena, AGP_PAGE_SIZE,
145275406Stijl	    M_NOWAIT | M_ZERO, 0, ~0, VM_MEMATTR_WRITE_COMBINING);
146150236Sanholt	if (sc->ag_vdir == NULL) {
147150236Sanholt		if (bootverbose)
148150236Sanholt			device_printf(dev, "pagedir allocation failed\n");
149275406Stijl		kmem_free(kernel_arena, (vm_offset_t)sc->ag_virtual,
150275406Stijl		    entries * sizeof(u_int32_t));
151150236Sanholt		return ENOMEM;
152150236Sanholt	}
153150236Sanholt	sc->ag_pdir = vtophys((vm_offset_t)sc->ag_vdir);
154150236Sanholt
155150236Sanholt	apbase_offset = pci_read_config(dev, AGP_APBASE, 4) >> 22;
156150236Sanholt	/* Fill in the pagedir's pointers to GATT pages */
157150236Sanholt	for (i = 0; i < sc->ag_entries / 1024; i++) {
158150236Sanholt		vm_offset_t va;
159150236Sanholt		vm_offset_t pa;
160150236Sanholt
161150236Sanholt		va = ((vm_offset_t)sc->ag_virtual) + i * AGP_PAGE_SIZE;
162150236Sanholt		pa = vtophys(va);
163150236Sanholt		sc->ag_vdir[apbase_offset + i] = pa | 1;
164150236Sanholt	}
165150236Sanholt
166150236Sanholt	return 0;
167150236Sanholt}
168150236Sanholt
169150236Sanholt
170150236Sanholtstatic int
171150236Sanholtagp_ati_attach(device_t dev)
172150236Sanholt{
173150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
174150236Sanholt	int error, rid;
175150236Sanholt	u_int32_t temp;
176150236Sanholt	u_int32_t apsize_reg, agpmode_reg;
177150236Sanholt
178150236Sanholt	error = agp_generic_attach(dev);
179150236Sanholt	if (error)
180150236Sanholt		return error;
181150236Sanholt
182150236Sanholt	switch (pci_get_devid(dev)) {
183150236Sanholt	case 0xcab01002: /* ATI RS100 AGP bridge */
184161788Sanholt	case 0xcab21002: /* ATI RS200 AGP bridge */
185161788Sanholt	case 0xcbb21002: /* ATI RS200M AGP bridge */
186150236Sanholt	case 0xcab31002: /* ATI RS250 AGP bridge */
187150236Sanholt		sc->is_rs300 = 0;
188150236Sanholt		apsize_reg = ATI_RS100_APSIZE;
189150236Sanholt		agpmode_reg = ATI_RS100_IG_AGPMODE;
190150236Sanholt		break;
191150236Sanholt	case 0x58301002: /* ATI RS300_100 AGP bridge */
192150236Sanholt	case 0x58311002: /* ATI RS300_133 AGP bridge */
193150236Sanholt	case 0x58321002: /* ATI RS300_166 AGP bridge */
194150236Sanholt	case 0x58331002: /* ATI RS300_200 AGP bridge */
195150236Sanholt		sc->is_rs300 = 1;
196150236Sanholt		apsize_reg = ATI_RS300_APSIZE;
197150236Sanholt		agpmode_reg = ATI_RS300_IG_AGPMODE;
198150236Sanholt		break;
199150236Sanholt	default:
200150236Sanholt		/* Unknown chipset */
201150236Sanholt		return EINVAL;
202244926Santoine	}
203150236Sanholt
204150236Sanholt	rid = ATI_GART_MMADDR;
205150236Sanholt	sc->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
206150236Sanholt	if (!sc->regs) {
207150236Sanholt		agp_generic_detach(dev);
208150236Sanholt		return ENOMEM;
209150236Sanholt	}
210150236Sanholt
211150236Sanholt	sc->bst = rman_get_bustag(sc->regs);
212150236Sanholt	sc->bsh = rman_get_bushandle(sc->regs);
213150236Sanholt
214150236Sanholt	sc->initial_aperture = AGP_GET_APERTURE(dev);
215150236Sanholt
216150236Sanholt	for (;;) {
217150236Sanholt		if (agp_ati_alloc_gatt(dev) == 0)
218150236Sanholt			break;
219150236Sanholt
220150236Sanholt		/*
221150236Sanholt		 * Probably contigmalloc failure. Try reducing the
222150236Sanholt		 * aperture so that the gatt size reduces.
223150236Sanholt		 */
224150236Sanholt		if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2))
225150236Sanholt			return ENOMEM;
226150236Sanholt	}
227150236Sanholt
228150236Sanholt	temp = pci_read_config(dev, apsize_reg, 4);
229150236Sanholt	pci_write_config(dev, apsize_reg, temp | 1, 4);
230150236Sanholt
231150236Sanholt	pci_write_config(dev, agpmode_reg, 0x20000, 4);
232150236Sanholt
233150236Sanholt	WRITE4(ATI_GART_FEATURE_ID, 0x00060000);
234150236Sanholt
235150236Sanholt	temp = pci_read_config(dev, 4, 4);	/* XXX: Magic reg# */
236150236Sanholt	pci_write_config(dev, 4, temp | (1 << 14), 4);
237150236Sanholt
238150236Sanholt	WRITE4(ATI_GART_BASE, sc->ag_pdir);
239150236Sanholt
240150236Sanholt	AGP_FLUSH_TLB(dev);
241150236Sanholt
242150236Sanholt	return 0;
243150236Sanholt}
244150236Sanholt
245150236Sanholtstatic int
246150236Sanholtagp_ati_detach(device_t dev)
247150236Sanholt{
248150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
249150236Sanholt	u_int32_t apsize_reg, temp;
250150236Sanholt
251173203Sjhb	agp_free_cdev(dev);
252173203Sjhb
253150236Sanholt	if (sc->is_rs300)
254150236Sanholt		apsize_reg = ATI_RS300_APSIZE;
255150236Sanholt	else
256150236Sanholt		apsize_reg = ATI_RS100_APSIZE;
257150236Sanholt
258150236Sanholt	/* Clear the GATT base */
259150236Sanholt	WRITE4(ATI_GART_BASE, 0);
260150236Sanholt
261150236Sanholt	/* Put the aperture back the way it started. */
262150236Sanholt	AGP_SET_APERTURE(dev, sc->initial_aperture);
263150236Sanholt
264150236Sanholt	temp = pci_read_config(dev, apsize_reg, 4);
265150236Sanholt	pci_write_config(dev, apsize_reg, temp & ~1, 4);
266150236Sanholt
267275406Stijl	kmem_free(kernel_arena, (vm_offset_t)sc->ag_vdir, AGP_PAGE_SIZE);
268275406Stijl	kmem_free(kernel_arena, (vm_offset_t)sc->ag_virtual,
269275406Stijl	    sc->ag_entries * sizeof(u_int32_t));
270150236Sanholt
271150236Sanholt	bus_release_resource(dev, SYS_RES_MEMORY, ATI_GART_MMADDR, sc->regs);
272173203Sjhb	agp_free_res(dev);
273150236Sanholt
274150236Sanholt	return 0;
275150236Sanholt}
276150236Sanholt
277150236Sanholtstatic u_int32_t
278150236Sanholtagp_ati_get_aperture(device_t dev)
279150236Sanholt{
280150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
281150236Sanholt	int size_value;
282150236Sanholt
283150236Sanholt	if (sc->is_rs300)
284150236Sanholt		size_value = pci_read_config(dev, ATI_RS300_APSIZE, 4);
285150236Sanholt	else
286150236Sanholt		size_value = pci_read_config(dev, ATI_RS100_APSIZE, 4);
287150236Sanholt
288150236Sanholt	size_value = (size_value & 0x0000000e) >> 1;
289150236Sanholt	size_value = (32 * 1024 * 1024) << size_value;
290150236Sanholt
291150236Sanholt	return size_value;
292150236Sanholt}
293150236Sanholt
294150236Sanholtstatic int
295150236Sanholtagp_ati_set_aperture(device_t dev, u_int32_t aperture)
296150236Sanholt{
297150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
298150236Sanholt	int size_value;
299150236Sanholt	u_int32_t apsize_reg;
300150236Sanholt
301150236Sanholt	if (sc->is_rs300)
302150236Sanholt		apsize_reg = ATI_RS300_APSIZE;
303150236Sanholt	else
304150236Sanholt		apsize_reg = ATI_RS100_APSIZE;
305150236Sanholt
306150236Sanholt	size_value = pci_read_config(dev, apsize_reg, 4);
307150236Sanholt
308150236Sanholt	size_value &= ~0x0000000e;
309150236Sanholt	size_value |= (ffs(aperture / (32 * 1024 * 1024)) - 1) << 1;
310150236Sanholt
311150236Sanholt	pci_write_config(dev, apsize_reg, size_value, 4);
312150236Sanholt
313150236Sanholt	return 0;
314150236Sanholt}
315150236Sanholt
316150236Sanholtstatic int
317194017Savgagp_ati_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical)
318150236Sanholt{
319150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
320150236Sanholt
321194017Savg	if (offset >= (sc->ag_entries << AGP_PAGE_SHIFT))
322150236Sanholt		return EINVAL;
323150236Sanholt
324150236Sanholt	sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1;
325150236Sanholt
326150236Sanholt	return 0;
327150236Sanholt}
328150236Sanholt
329150236Sanholtstatic int
330194017Savgagp_ati_unbind_page(device_t dev, vm_offset_t offset)
331150236Sanholt{
332150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
333150236Sanholt
334194017Savg	if (offset >= (sc->ag_entries << AGP_PAGE_SHIFT))
335150236Sanholt		return EINVAL;
336150236Sanholt
337150236Sanholt	sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
338150236Sanholt	return 0;
339150236Sanholt}
340150236Sanholt
341150236Sanholtstatic void
342150236Sanholtagp_ati_flush_tlb(device_t dev)
343150236Sanholt{
344150236Sanholt	struct agp_ati_softc *sc = device_get_softc(dev);
345150236Sanholt
346150236Sanholt	/* Set the cache invalidate bit and wait for the chipset to clear */
347150236Sanholt	WRITE4(ATI_GART_CACHE_CNTRL, 1);
348150236Sanholt	(void)READ4(ATI_GART_CACHE_CNTRL);
349150236Sanholt}
350150236Sanholt
351150236Sanholtstatic device_method_t agp_ati_methods[] = {
352150236Sanholt	/* Device interface */
353150236Sanholt	DEVMETHOD(device_probe,		agp_ati_probe),
354150236Sanholt	DEVMETHOD(device_attach,	agp_ati_attach),
355150236Sanholt	DEVMETHOD(device_detach,	agp_ati_detach),
356150236Sanholt	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
357150236Sanholt	DEVMETHOD(device_suspend,	bus_generic_suspend),
358150236Sanholt	DEVMETHOD(device_resume,	bus_generic_resume),
359150236Sanholt
360150236Sanholt	/* AGP interface */
361150236Sanholt	DEVMETHOD(agp_get_aperture,	agp_ati_get_aperture),
362150236Sanholt	DEVMETHOD(agp_set_aperture,	agp_ati_set_aperture),
363150236Sanholt	DEVMETHOD(agp_bind_page,	agp_ati_bind_page),
364150236Sanholt	DEVMETHOD(agp_unbind_page,	agp_ati_unbind_page),
365150236Sanholt	DEVMETHOD(agp_flush_tlb,	agp_ati_flush_tlb),
366150236Sanholt	DEVMETHOD(agp_enable,		agp_generic_enable),
367150236Sanholt	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
368150236Sanholt	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
369150236Sanholt	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
370150236Sanholt	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
371150236Sanholt
372150236Sanholt	{ 0, 0 }
373150236Sanholt};
374150236Sanholt
375150236Sanholtstatic driver_t agp_ati_driver = {
376150236Sanholt	"agp",
377150236Sanholt	agp_ati_methods,
378150236Sanholt	sizeof(struct agp_ati_softc),
379150236Sanholt};
380150236Sanholt
381150236Sanholtstatic devclass_t agp_devclass;
382150236Sanholt
383153572SjhbDRIVER_MODULE(agp_ati, hostb, agp_ati_driver, agp_devclass, 0, 0);
384150236SanholtMODULE_DEPEND(agp_ati, agp, 1, 1, 1);
385150236SanholtMODULE_DEPEND(agp_ati, pci, 1, 1, 1);
386