1214603Snwhitehorn/*-
2214603Snwhitehorn * Copyright (c) 2010 Nathan Whitehorn
3214603Snwhitehorn * All rights reserved.
4214603Snwhitehorn *
5214603Snwhitehorn * Redistribution and use in source and binary forms, with or without
6214603Snwhitehorn * modification, are permitted provided that the following conditions
7214603Snwhitehorn * are met:
8214603Snwhitehorn * 1. Redistributions of source code must retain the above copyright
9214603Snwhitehorn *    notice, this list of conditions and the following disclaimer.
10214603Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
11214603Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
12214603Snwhitehorn *    documentation and/or other materials provided with the distribution.
13214603Snwhitehorn *
14214603Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15214603Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16214603Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17214603Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18214603Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19214603Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20214603Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21214603Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22214603Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23214603Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24214603Snwhitehorn * SUCH DAMAGE.
25214603Snwhitehorn */
26214603Snwhitehorn
27214603Snwhitehorn#include <sys/cdefs.h>
28214603Snwhitehorn__FBSDID("$FreeBSD$");
29214603Snwhitehorn
30214603Snwhitehorn#include <sys/param.h>
31214603Snwhitehorn#include <sys/systm.h>
32214603Snwhitehorn#include <sys/malloc.h>
33214603Snwhitehorn#include <sys/kernel.h>
34214603Snwhitehorn#include <sys/module.h>
35214603Snwhitehorn#include <sys/bus.h>
36214603Snwhitehorn#include <sys/lock.h>
37214603Snwhitehorn#include <sys/mutex.h>
38214603Snwhitehorn#include <sys/proc.h>
39214603Snwhitehorn
40214603Snwhitehorn#include <machine/resource.h>
41214603Snwhitehorn
42214603Snwhitehorn#include <dev/agp/agppriv.h>
43214603Snwhitehorn#include <dev/agp/agpreg.h>
44214603Snwhitehorn#include <dev/pci/pcivar.h>
45214603Snwhitehorn#include <dev/pci/pcireg.h>
46214603Snwhitehorn
47214603Snwhitehorn#include <vm/vm.h>
48214603Snwhitehorn#include <vm/vm_object.h>
49214603Snwhitehorn#include <vm/pmap.h>
50214603Snwhitehorn
51214603Snwhitehorn#define UNIN_AGP_GART_BASE	0x8c
52214603Snwhitehorn#define UNIN_AGP_BASE_ADDR	0x90
53214603Snwhitehorn#define UNIN_AGP_GART_CONTROL	0x94
54214603Snwhitehorn
55214603Snwhitehorn#define UNIN_AGP_GART_INVAL	0x00000001
56214603Snwhitehorn#define UNIN_AGP_GART_ENABLE	0x00000100
57214603Snwhitehorn#define UNIN_AGP_GART_2XRESET	0x00010000
58214603Snwhitehorn#define UNIN_AGP_U3_GART_PERFRD	0x00080000
59214603Snwhitehorn
60214603Snwhitehornstruct agp_apple_softc {
61214603Snwhitehorn	struct agp_softc agp;
62214603Snwhitehorn	uint32_t	aperture;
63214603Snwhitehorn	struct agp_gatt *gatt;
64214603Snwhitehorn	int		u3;
65214603Snwhitehorn	int		needs_2x_reset;
66214603Snwhitehorn};
67214603Snwhitehorn
68214603Snwhitehornstatic int
69214603Snwhitehornagp_apple_probe(device_t dev)
70214603Snwhitehorn{
71214603Snwhitehorn
72241885Seadler	if (resource_disabled("agp", device_get_unit(dev)))
73241885Seadler		return (ENXIO);
74241885Seadler
75214603Snwhitehorn	if (pci_get_class(dev) != PCIC_BRIDGE
76214603Snwhitehorn	    || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
77214603Snwhitehorn		return (ENXIO);
78214603Snwhitehorn
79214603Snwhitehorn	if (agp_find_caps(dev) == 0)
80214603Snwhitehorn		return (ENXIO);
81214603Snwhitehorn
82214603Snwhitehorn	if (pci_get_class(dev) != PCIC_BRIDGE
83214603Snwhitehorn	    || pci_get_subclass(dev) != PCIS_BRIDGE_HOST)
84214603Snwhitehorn		return (ENXIO);
85214603Snwhitehorn
86214603Snwhitehorn	switch (pci_get_devid(dev)) {
87214603Snwhitehorn	case 0x0020106b:
88214603Snwhitehorn	case 0x0027106b:
89214603Snwhitehorn		device_set_desc(dev, "Apple UniNorth AGP Bridge");
90214603Snwhitehorn		return (BUS_PROBE_DEFAULT);
91214603Snwhitehorn	case 0x002d106b:
92214603Snwhitehorn		device_set_desc(dev, "Apple UniNorth 1.5 AGP Bridge");
93214603Snwhitehorn		return (BUS_PROBE_DEFAULT);
94214603Snwhitehorn	case 0x0034106b:
95214603Snwhitehorn		device_set_desc(dev, "Apple UniNorth 2 AGP Bridge");
96214603Snwhitehorn		return (BUS_PROBE_DEFAULT);
97214603Snwhitehorn	case 0x004b106b:
98214603Snwhitehorn	case 0x0058106b:
99214603Snwhitehorn	case 0x0059106b:
100214603Snwhitehorn		device_set_desc(dev, "Apple U3 AGP Bridge");
101214603Snwhitehorn		return (BUS_PROBE_DEFAULT);
102214603Snwhitehorn	case 0x0066106b:
103214603Snwhitehorn		device_set_desc(dev, "Apple Intrepid AGP Bridge");
104214603Snwhitehorn		return (BUS_PROBE_DEFAULT);
105214603Snwhitehorn	}
106214603Snwhitehorn
107214603Snwhitehorn	return (ENXIO);
108214603Snwhitehorn}
109214603Snwhitehorn
110214603Snwhitehornstatic int
111214603Snwhitehornagp_apple_attach(device_t dev)
112214603Snwhitehorn{
113214603Snwhitehorn	struct agp_apple_softc *sc = device_get_softc(dev);
114214603Snwhitehorn	int error;
115214603Snwhitehorn
116214603Snwhitehorn	/* Record quirks */
117214603Snwhitehorn	sc->needs_2x_reset = 0;
118214603Snwhitehorn	sc->u3 = 0;
119214603Snwhitehorn	switch (pci_get_devid(dev)) {
120214603Snwhitehorn	case 0x0020106b:
121214603Snwhitehorn	case 0x0027106b:
122214603Snwhitehorn		sc->needs_2x_reset = 1;
123214603Snwhitehorn		break;
124214603Snwhitehorn	case 0x004b106b:
125214603Snwhitehorn	case 0x0058106b:
126214603Snwhitehorn	case 0x0059106b:
127214603Snwhitehorn		sc->u3 = 1;
128214603Snwhitehorn		break;
129214603Snwhitehorn	}
130214603Snwhitehorn
131214603Snwhitehorn	/* Set the aperture bus address base (must be 0) */
132214603Snwhitehorn	pci_write_config(dev, UNIN_AGP_BASE_ADDR, 0, 4);
133214603Snwhitehorn	agp_set_aperture_resource(dev, -1);
134214603Snwhitehorn
135214603Snwhitehorn	error = agp_generic_attach(dev);
136214603Snwhitehorn	if (error)
137214603Snwhitehorn		return (error);
138214603Snwhitehorn
139214603Snwhitehorn	sc->aperture = 256*1024*1024;
140214603Snwhitehorn
141214603Snwhitehorn	for (sc->aperture = 256*1024*1024; sc->aperture >= 4*1024*1024;
142214603Snwhitehorn	    sc->aperture /= 2) {
143214603Snwhitehorn		sc->gatt = agp_alloc_gatt(dev);
144214603Snwhitehorn		if (sc->gatt)
145214603Snwhitehorn			break;
146214603Snwhitehorn	}
147214603Snwhitehorn	if (sc->aperture < 4*1024*1024) {
148214603Snwhitehorn		agp_generic_detach(dev);
149214603Snwhitehorn		return ENOMEM;
150214603Snwhitehorn	}
151214603Snwhitehorn
152214603Snwhitehorn	/* Install the gatt. */
153214603Snwhitehorn	AGP_SET_APERTURE(dev, sc->aperture);
154214603Snwhitehorn
155214603Snwhitehorn	/* XXX: U3 scratch page? */
156214603Snwhitehorn
157214603Snwhitehorn	/* Enable the aperture and TLB. */
158214603Snwhitehorn	AGP_FLUSH_TLB(dev);
159214603Snwhitehorn
160214603Snwhitehorn	return (0);
161214603Snwhitehorn}
162214603Snwhitehorn
163214603Snwhitehornstatic int
164214603Snwhitehornagp_apple_detach(device_t dev)
165214603Snwhitehorn{
166214603Snwhitehorn	struct agp_apple_softc *sc = device_get_softc(dev);
167214603Snwhitehorn
168214603Snwhitehorn	agp_free_cdev(dev);
169214603Snwhitehorn
170214603Snwhitehorn	/* Disable the aperture and TLB */
171214603Snwhitehorn	pci_write_config(dev, UNIN_AGP_GART_CONTROL, UNIN_AGP_GART_INVAL, 4);
172214603Snwhitehorn	pci_write_config(dev, UNIN_AGP_GART_CONTROL, 0, 4);
173214603Snwhitehorn
174214603Snwhitehorn	if (sc->needs_2x_reset) {
175214603Snwhitehorn		pci_write_config(dev, UNIN_AGP_GART_CONTROL,
176214603Snwhitehorn		    UNIN_AGP_GART_2XRESET, 4);
177214603Snwhitehorn		pci_write_config(dev, UNIN_AGP_GART_CONTROL, 0, 4);
178214603Snwhitehorn	}
179214603Snwhitehorn
180214603Snwhitehorn	AGP_SET_APERTURE(dev, 0);
181214603Snwhitehorn
182214603Snwhitehorn	agp_free_gatt(sc->gatt);
183214603Snwhitehorn	agp_free_res(dev);
184214603Snwhitehorn	return 0;
185214603Snwhitehorn}
186214603Snwhitehorn
187214603Snwhitehornstatic uint32_t
188214603Snwhitehornagp_apple_get_aperture(device_t dev)
189214603Snwhitehorn{
190214603Snwhitehorn	struct agp_apple_softc *sc = device_get_softc(dev);
191214603Snwhitehorn
192214603Snwhitehorn	return (sc->aperture);
193214603Snwhitehorn}
194214603Snwhitehorn
195214603Snwhitehornstatic int
196214603Snwhitehornagp_apple_set_aperture(device_t dev, uint32_t aperture)
197214603Snwhitehorn{
198214603Snwhitehorn	struct agp_apple_softc *sc = device_get_softc(dev);
199214603Snwhitehorn
200214603Snwhitehorn	/*
201214603Snwhitehorn	 * Check for a multiple of 4 MB and make sure it is within the
202214603Snwhitehorn	 * programmable range.
203214603Snwhitehorn	 */
204214603Snwhitehorn	if (aperture % (4*1024*1024)
205214603Snwhitehorn	    || aperture < 4*1024*1024
206214603Snwhitehorn	    || aperture > ((sc->u3) ? 512 : 256)*1024*1024)
207214603Snwhitehorn		return EINVAL;
208214603Snwhitehorn
209214603Snwhitehorn	/* The aperture value is a multiple of 4 MB */
210214603Snwhitehorn	aperture /= (4*1024*1024);
211214603Snwhitehorn
212214603Snwhitehorn	pci_write_config(dev, UNIN_AGP_GART_BASE,
213214603Snwhitehorn	    (sc->gatt->ag_physical & 0xfffff000) | aperture, 4);
214214603Snwhitehorn
215214603Snwhitehorn	return (0);
216214603Snwhitehorn}
217214603Snwhitehorn
218214603Snwhitehornstatic int
219214603Snwhitehornagp_apple_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical)
220214603Snwhitehorn{
221214603Snwhitehorn	struct agp_apple_softc *sc = device_get_softc(dev);
222214603Snwhitehorn
223214603Snwhitehorn	if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
224214603Snwhitehorn		return EINVAL;
225214603Snwhitehorn
226214603Snwhitehorn	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical;
227214603Snwhitehorn	__asm __volatile("dcbst 0,%0; sync" ::
228214603Snwhitehorn	    "r"(&sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT]) : "memory");
229214603Snwhitehorn	return (0);
230214603Snwhitehorn}
231214603Snwhitehorn
232214603Snwhitehornstatic int
233214603Snwhitehornagp_apple_unbind_page(device_t dev, vm_offset_t offset)
234214603Snwhitehorn{
235214603Snwhitehorn	struct agp_apple_softc *sc = device_get_softc(dev);
236214603Snwhitehorn
237214603Snwhitehorn	if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT))
238214603Snwhitehorn		return EINVAL;
239214603Snwhitehorn
240214603Snwhitehorn	sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0;
241214603Snwhitehorn	__asm __volatile("dcbst 0,%0; sync" ::
242214603Snwhitehorn	    "r"(&sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT]) : "memory");
243214603Snwhitehorn	return (0);
244214603Snwhitehorn}
245214603Snwhitehorn
246214603Snwhitehornstatic void
247214603Snwhitehornagp_apple_flush_tlb(device_t dev)
248214603Snwhitehorn{
249214603Snwhitehorn	struct agp_apple_softc *sc = device_get_softc(dev);
250214603Snwhitehorn	uint32_t cntrl = UNIN_AGP_GART_ENABLE;
251214603Snwhitehorn
252214603Snwhitehorn	if (sc->u3)
253214603Snwhitehorn		cntrl |= UNIN_AGP_U3_GART_PERFRD;
254214603Snwhitehorn
255214603Snwhitehorn	pci_write_config(dev, UNIN_AGP_GART_CONTROL,
256214603Snwhitehorn	    cntrl | UNIN_AGP_GART_INVAL, 4);
257214603Snwhitehorn	pci_write_config(dev, UNIN_AGP_GART_CONTROL, cntrl, 4);
258214603Snwhitehorn
259214603Snwhitehorn	if (sc->needs_2x_reset) {
260214603Snwhitehorn		pci_write_config(dev, UNIN_AGP_GART_CONTROL,
261214603Snwhitehorn		    cntrl | UNIN_AGP_GART_2XRESET, 4);
262214603Snwhitehorn		pci_write_config(dev, UNIN_AGP_GART_CONTROL, cntrl, 4);
263214603Snwhitehorn	}
264214603Snwhitehorn}
265214603Snwhitehorn
266214603Snwhitehornstatic device_method_t agp_apple_methods[] = {
267214603Snwhitehorn	/* Device interface */
268214603Snwhitehorn	DEVMETHOD(device_probe,		agp_apple_probe),
269214603Snwhitehorn	DEVMETHOD(device_attach,	agp_apple_attach),
270214603Snwhitehorn	DEVMETHOD(device_detach,	agp_apple_detach),
271214603Snwhitehorn	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
272214603Snwhitehorn	DEVMETHOD(device_suspend,	bus_generic_suspend),
273214603Snwhitehorn	DEVMETHOD(device_resume,	bus_generic_resume),
274214603Snwhitehorn
275214603Snwhitehorn	/* AGP interface */
276214603Snwhitehorn	DEVMETHOD(agp_get_aperture,	agp_apple_get_aperture),
277214603Snwhitehorn	DEVMETHOD(agp_set_aperture,	agp_apple_set_aperture),
278214603Snwhitehorn	DEVMETHOD(agp_bind_page,	agp_apple_bind_page),
279214603Snwhitehorn	DEVMETHOD(agp_unbind_page,	agp_apple_unbind_page),
280214603Snwhitehorn	DEVMETHOD(agp_flush_tlb,	agp_apple_flush_tlb),
281214603Snwhitehorn	DEVMETHOD(agp_enable,		agp_generic_enable),
282214603Snwhitehorn	DEVMETHOD(agp_alloc_memory,	agp_generic_alloc_memory),
283214603Snwhitehorn	DEVMETHOD(agp_free_memory,	agp_generic_free_memory),
284214603Snwhitehorn	DEVMETHOD(agp_bind_memory,	agp_generic_bind_memory),
285214603Snwhitehorn	DEVMETHOD(agp_unbind_memory,	agp_generic_unbind_memory),
286214603Snwhitehorn
287214603Snwhitehorn	{ 0, 0 }
288214603Snwhitehorn};
289214603Snwhitehorn
290214603Snwhitehornstatic driver_t agp_apple_driver = {
291214603Snwhitehorn	"agp",
292214603Snwhitehorn	agp_apple_methods,
293214603Snwhitehorn	sizeof(struct agp_apple_softc),
294214603Snwhitehorn};
295214603Snwhitehorn
296214603Snwhitehornstatic devclass_t agp_devclass;
297214603Snwhitehorn
298214603SnwhitehornDRIVER_MODULE(agp_apple, hostb, agp_apple_driver, agp_devclass, 0, 0);
299214603SnwhitehornMODULE_DEPEND(agp_apple, agp, 1, 1, 1);
300214603SnwhitehornMODULE_DEPEND(agp_apple, pci, 1, 1, 1);
301