1208149Snwhitehorn/*-
2208149Snwhitehorn * Copyright (C) 2002 Benno Rice.
3208149Snwhitehorn * All rights reserved.
4208149Snwhitehorn *
5208149Snwhitehorn * Redistribution and use in source and binary forms, with or without
6208149Snwhitehorn * modification, are permitted provided that the following conditions
7208149Snwhitehorn * are met:
8208149Snwhitehorn * 1. Redistributions of source code must retain the above copyright
9208149Snwhitehorn *    notice, this list of conditions and the following disclaimer.
10208149Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
11208149Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
12208149Snwhitehorn *    documentation and/or other materials provided with the distribution.
13208149Snwhitehorn *
14208149Snwhitehorn * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15208149Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16208149Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17208149Snwhitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18208149Snwhitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19208149Snwhitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20208149Snwhitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21208149Snwhitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22208149Snwhitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23208149Snwhitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24208149Snwhitehorn */
25208149Snwhitehorn
26227843Smarius#include <sys/cdefs.h>
27227843Smarius__FBSDID("$FreeBSD$");
28227843Smarius
29208149Snwhitehorn#include <sys/param.h>
30208149Snwhitehorn#include <sys/systm.h>
31208149Snwhitehorn#include <sys/module.h>
32208149Snwhitehorn#include <sys/bus.h>
33208149Snwhitehorn#include <sys/conf.h>
34208149Snwhitehorn#include <sys/kernel.h>
35208149Snwhitehorn
36208149Snwhitehorn#include <dev/ofw/openfirm.h>
37208149Snwhitehorn#include <dev/ofw/ofw_pci.h>
38208149Snwhitehorn#include <dev/ofw/ofw_bus.h>
39208149Snwhitehorn#include <dev/ofw/ofw_bus_subr.h>
40208149Snwhitehorn
41208149Snwhitehorn#include <dev/pci/pcivar.h>
42208149Snwhitehorn#include <dev/pci/pcireg.h>
43208149Snwhitehorn
44208149Snwhitehorn#include <machine/bus.h>
45208149Snwhitehorn#include <machine/intr_machdep.h>
46208149Snwhitehorn#include <machine/md_var.h>
47208149Snwhitehorn#include <machine/pio.h>
48208149Snwhitehorn#include <machine/resource.h>
49208149Snwhitehorn
50208149Snwhitehorn#include <sys/rman.h>
51208149Snwhitehorn
52230993Snwhitehorn#include <powerpc/ofw/ofw_pci.h>
53208149Snwhitehorn#include <powerpc/powermac/uninorthvar.h>
54208149Snwhitehorn
55208149Snwhitehorn#include <vm/vm.h>
56208149Snwhitehorn#include <vm/pmap.h>
57208149Snwhitehorn
58208149Snwhitehorn#include "pcib_if.h"
59208149Snwhitehorn
60208149Snwhitehorn#define	UNINORTH_DEBUG	0
61208149Snwhitehorn
62208149Snwhitehorn/*
63208149Snwhitehorn * Device interface.
64208149Snwhitehorn */
65208149Snwhitehornstatic int		uninorth_probe(device_t);
66208149Snwhitehornstatic int		uninorth_attach(device_t);
67208149Snwhitehorn
68208149Snwhitehorn/*
69208149Snwhitehorn * pcib interface.
70208149Snwhitehorn */
71208149Snwhitehornstatic u_int32_t	uninorth_read_config(device_t, u_int, u_int, u_int,
72208149Snwhitehorn			    u_int, int);
73208149Snwhitehornstatic void		uninorth_write_config(device_t, u_int, u_int, u_int,
74208149Snwhitehorn			    u_int, u_int32_t, int);
75208149Snwhitehorn
76208149Snwhitehorn/*
77208149Snwhitehorn * Local routines.
78208149Snwhitehorn */
79208149Snwhitehornstatic int		uninorth_enable_config(struct uninorth_softc *, u_int,
80208149Snwhitehorn			    u_int, u_int, u_int);
81208149Snwhitehorn
82208149Snwhitehorn/*
83208149Snwhitehorn * Driver methods.
84208149Snwhitehorn */
85208149Snwhitehornstatic device_method_t	uninorth_methods[] = {
86208149Snwhitehorn	/* Device interface */
87208149Snwhitehorn	DEVMETHOD(device_probe,		uninorth_probe),
88208149Snwhitehorn	DEVMETHOD(device_attach,	uninorth_attach),
89208149Snwhitehorn
90208149Snwhitehorn	/* pcib interface */
91208149Snwhitehorn	DEVMETHOD(pcib_read_config,	uninorth_read_config),
92208149Snwhitehorn	DEVMETHOD(pcib_write_config,	uninorth_write_config),
93208149Snwhitehorn
94227843Smarius	DEVMETHOD_END
95208149Snwhitehorn};
96208149Snwhitehorn
97208149Snwhitehornstatic devclass_t	uninorth_devclass;
98208149Snwhitehorn
99230993SnwhitehornDEFINE_CLASS_1(pcib, uninorth_driver, uninorth_methods,
100230993Snwhitehorn    sizeof(struct uninorth_softc), ofw_pci_driver);
101208149SnwhitehornDRIVER_MODULE(uninorth, nexus, uninorth_driver, uninorth_devclass, 0, 0);
102208149Snwhitehorn
103208149Snwhitehornstatic int
104208149Snwhitehornuninorth_probe(device_t dev)
105208149Snwhitehorn{
106208149Snwhitehorn	const char	*type, *compatible;
107208149Snwhitehorn
108208149Snwhitehorn	type = ofw_bus_get_type(dev);
109208149Snwhitehorn	compatible = ofw_bus_get_compat(dev);
110208149Snwhitehorn
111208149Snwhitehorn	if (type == NULL || compatible == NULL)
112208149Snwhitehorn		return (ENXIO);
113208149Snwhitehorn
114208149Snwhitehorn	if (strcmp(type, "pci") != 0)
115208149Snwhitehorn		return (ENXIO);
116208149Snwhitehorn
117208149Snwhitehorn	if (strcmp(compatible, "uni-north") == 0) {
118208149Snwhitehorn		device_set_desc(dev, "Apple UniNorth Host-PCI bridge");
119208149Snwhitehorn		return (0);
120208149Snwhitehorn	} else if (strcmp(compatible, "u3-agp") == 0) {
121208149Snwhitehorn		device_set_desc(dev, "Apple U3 Host-AGP bridge");
122208149Snwhitehorn		return (0);
123208149Snwhitehorn	} else if (strcmp(compatible, "u4-pcie") == 0) {
124208149Snwhitehorn		device_set_desc(dev, "IBM CPC945 PCI Express Root");
125208149Snwhitehorn		return (0);
126208149Snwhitehorn	}
127208149Snwhitehorn
128208149Snwhitehorn	return (ENXIO);
129208149Snwhitehorn}
130208149Snwhitehorn
131208149Snwhitehornstatic int
132208149Snwhitehornuninorth_attach(device_t dev)
133208149Snwhitehorn{
134208149Snwhitehorn	struct		uninorth_softc *sc;
135208149Snwhitehorn	const char	*compatible;
136208149Snwhitehorn	phandle_t	node;
137230993Snwhitehorn	u_int32_t	reg[3];
138208149Snwhitehorn
139208149Snwhitehorn	node = ofw_bus_get_node(dev);
140208149Snwhitehorn	sc = device_get_softc(dev);
141208149Snwhitehorn
142208149Snwhitehorn	if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
143208149Snwhitehorn		return (ENXIO);
144208149Snwhitehorn
145208149Snwhitehorn	sc->sc_ver = 0;
146208149Snwhitehorn	compatible = ofw_bus_get_compat(dev);
147208149Snwhitehorn	if (strcmp(compatible, "u3-agp") == 0)
148208149Snwhitehorn		sc->sc_ver = 3;
149208149Snwhitehorn	if (strcmp(compatible, "u4-pcie") == 0)
150208149Snwhitehorn		sc->sc_ver = 4;
151208149Snwhitehorn
152208149Snwhitehorn	if (sc->sc_ver >= 3) {
153208149Snwhitehorn	   sc->sc_addr = (vm_offset_t)pmap_mapdev(reg[1] + 0x800000, PAGE_SIZE);
154208149Snwhitehorn	   sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1] + 0xc00000, PAGE_SIZE);
155208149Snwhitehorn	} else {
156208149Snwhitehorn	   sc->sc_addr = (vm_offset_t)pmap_mapdev(reg[0] + 0x800000, PAGE_SIZE);
157208149Snwhitehorn	   sc->sc_data = (vm_offset_t)pmap_mapdev(reg[0] + 0xc00000, PAGE_SIZE);
158208149Snwhitehorn	}
159208149Snwhitehorn
160230993Snwhitehorn	return (ofw_pci_attach(dev));
161208149Snwhitehorn}
162208149Snwhitehorn
163208149Snwhitehornstatic u_int32_t
164208149Snwhitehornuninorth_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
165208149Snwhitehorn    int width)
166208149Snwhitehorn{
167208149Snwhitehorn	struct		uninorth_softc *sc;
168208149Snwhitehorn	vm_offset_t	caoff;
169208149Snwhitehorn
170208149Snwhitehorn	sc = device_get_softc(dev);
171208149Snwhitehorn	caoff = sc->sc_data + (reg & 0x07);
172208149Snwhitehorn
173208149Snwhitehorn	if (uninorth_enable_config(sc, bus, slot, func, reg) != 0) {
174208149Snwhitehorn		switch (width) {
175208149Snwhitehorn		case 1:
176208149Snwhitehorn			return (in8rb(caoff));
177208149Snwhitehorn			break;
178208149Snwhitehorn		case 2:
179208149Snwhitehorn			return (in16rb(caoff));
180208149Snwhitehorn			break;
181208149Snwhitehorn		case 4:
182208149Snwhitehorn			return (in32rb(caoff));
183208149Snwhitehorn			break;
184208149Snwhitehorn		}
185208149Snwhitehorn	}
186208149Snwhitehorn
187208149Snwhitehorn	return (0xffffffff);
188208149Snwhitehorn}
189208149Snwhitehorn
190208149Snwhitehornstatic void
191208149Snwhitehornuninorth_write_config(device_t dev, u_int bus, u_int slot, u_int func,
192208149Snwhitehorn    u_int reg, u_int32_t val, int width)
193208149Snwhitehorn{
194208149Snwhitehorn	struct		uninorth_softc *sc;
195208149Snwhitehorn	vm_offset_t	caoff;
196208149Snwhitehorn
197208149Snwhitehorn	sc = device_get_softc(dev);
198208149Snwhitehorn	caoff = sc->sc_data + (reg & 0x07);
199208149Snwhitehorn
200208149Snwhitehorn	if (uninorth_enable_config(sc, bus, slot, func, reg)) {
201208149Snwhitehorn		switch (width) {
202208149Snwhitehorn		case 1:
203208149Snwhitehorn			out8rb(caoff, val);
204208149Snwhitehorn			break;
205208149Snwhitehorn		case 2:
206208149Snwhitehorn			out16rb(caoff, val);
207208149Snwhitehorn			break;
208208149Snwhitehorn		case 4:
209208149Snwhitehorn			out32rb(caoff, val);
210208149Snwhitehorn			break;
211208149Snwhitehorn		}
212208149Snwhitehorn	}
213208149Snwhitehorn}
214208149Snwhitehorn
215208149Snwhitehornstatic int
216208149Snwhitehornuninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot,
217208149Snwhitehorn    u_int func, u_int reg)
218208149Snwhitehorn{
219208149Snwhitehorn	uint32_t	cfgval;
220208149Snwhitehorn	uint32_t	pass;
221208149Snwhitehorn
222230993Snwhitehorn	if (resource_int_value(device_get_name(sc->pci_sc.sc_dev),
223230993Snwhitehorn	        device_get_unit(sc->pci_sc.sc_dev), "skipslot", &pass) == 0) {
224208149Snwhitehorn		if (pass == slot)
225208149Snwhitehorn			return (0);
226208149Snwhitehorn	}
227208149Snwhitehorn
228208149Snwhitehorn	/*
229208149Snwhitehorn	 * Issue type 0 configuration space accesses for the root bus.
230208149Snwhitehorn	 *
231208149Snwhitehorn	 * NOTE: On U4, issue only type 1 accesses. There is a secret
232208149Snwhitehorn	 * PCI Express <-> PCI Express bridge not present in the device tree,
233208149Snwhitehorn	 * and we need to route all of our configuration space through it.
234208149Snwhitehorn	 */
235230993Snwhitehorn	if (sc->pci_sc.sc_bus == bus && sc->sc_ver < 4) {
236208149Snwhitehorn		/*
237208149Snwhitehorn		 * No slots less than 11 on the primary bus on U3 and lower
238208149Snwhitehorn		 */
239208149Snwhitehorn		if (slot < 11)
240208149Snwhitehorn			return (0);
241208149Snwhitehorn
242208149Snwhitehorn		cfgval = (1 << slot) | (func << 8) | (reg & 0xfc);
243208149Snwhitehorn	} else {
244208149Snwhitehorn		cfgval = (bus << 16) | (slot << 11) | (func << 8) |
245208149Snwhitehorn		    (reg & 0xfc) | 1;
246208149Snwhitehorn	}
247208149Snwhitehorn
248208149Snwhitehorn	/* Set extended register bits on U4 */
249208149Snwhitehorn	if (sc->sc_ver == 4)
250208149Snwhitehorn		cfgval |= (reg >> 8) << 28;
251208149Snwhitehorn
252208149Snwhitehorn	do {
253208149Snwhitehorn		out32rb(sc->sc_addr, cfgval);
254208149Snwhitehorn	} while (in32rb(sc->sc_addr) != cfgval);
255208149Snwhitehorn
256208149Snwhitehorn	return (1);
257208149Snwhitehorn}
258208149Snwhitehorn
259