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: releng/10.2/sys/powerpc/powermac/uninorthpci.c 266160 2014-05-15 17:30:16Z ian $");
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);
101266160SianDRIVER_MODULE(uninorth, ofwbus, 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;
137266019Sian	uint32_t	reg[3];
138266019Sian	uint64_t	regbase;
139266019Sian	cell_t		acells;
140208149Snwhitehorn
141208149Snwhitehorn	node = ofw_bus_get_node(dev);
142208149Snwhitehorn	sc = device_get_softc(dev);
143208149Snwhitehorn
144208149Snwhitehorn	if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
145208149Snwhitehorn		return (ENXIO);
146208149Snwhitehorn
147208149Snwhitehorn	sc->sc_ver = 0;
148208149Snwhitehorn	compatible = ofw_bus_get_compat(dev);
149208149Snwhitehorn	if (strcmp(compatible, "u3-agp") == 0)
150208149Snwhitehorn		sc->sc_ver = 3;
151208149Snwhitehorn	if (strcmp(compatible, "u4-pcie") == 0)
152208149Snwhitehorn		sc->sc_ver = 4;
153208149Snwhitehorn
154266019Sian	acells = 1;
155266019Sian	OF_getprop(OF_parent(node), "#address-cells", &acells, sizeof(acells));
156266019Sian
157266019Sian	regbase = reg[0];
158266019Sian	if (acells == 2) {
159266019Sian		regbase <<= 32;
160266019Sian		regbase |= reg[1];
161208149Snwhitehorn	}
162208149Snwhitehorn
163266019Sian	sc->sc_addr = (vm_offset_t)pmap_mapdev(regbase + 0x800000, PAGE_SIZE);
164266019Sian	sc->sc_data = (vm_offset_t)pmap_mapdev(regbase + 0xc00000, PAGE_SIZE);
165266019Sian
166230993Snwhitehorn	return (ofw_pci_attach(dev));
167208149Snwhitehorn}
168208149Snwhitehorn
169208149Snwhitehornstatic u_int32_t
170208149Snwhitehornuninorth_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
171208149Snwhitehorn    int width)
172208149Snwhitehorn{
173208149Snwhitehorn	struct		uninorth_softc *sc;
174208149Snwhitehorn	vm_offset_t	caoff;
175208149Snwhitehorn
176208149Snwhitehorn	sc = device_get_softc(dev);
177208149Snwhitehorn	caoff = sc->sc_data + (reg & 0x07);
178208149Snwhitehorn
179208149Snwhitehorn	if (uninorth_enable_config(sc, bus, slot, func, reg) != 0) {
180208149Snwhitehorn		switch (width) {
181208149Snwhitehorn		case 1:
182208149Snwhitehorn			return (in8rb(caoff));
183208149Snwhitehorn			break;
184208149Snwhitehorn		case 2:
185208149Snwhitehorn			return (in16rb(caoff));
186208149Snwhitehorn			break;
187208149Snwhitehorn		case 4:
188208149Snwhitehorn			return (in32rb(caoff));
189208149Snwhitehorn			break;
190208149Snwhitehorn		}
191208149Snwhitehorn	}
192208149Snwhitehorn
193208149Snwhitehorn	return (0xffffffff);
194208149Snwhitehorn}
195208149Snwhitehorn
196208149Snwhitehornstatic void
197208149Snwhitehornuninorth_write_config(device_t dev, u_int bus, u_int slot, u_int func,
198208149Snwhitehorn    u_int reg, u_int32_t val, int width)
199208149Snwhitehorn{
200208149Snwhitehorn	struct		uninorth_softc *sc;
201208149Snwhitehorn	vm_offset_t	caoff;
202208149Snwhitehorn
203208149Snwhitehorn	sc = device_get_softc(dev);
204208149Snwhitehorn	caoff = sc->sc_data + (reg & 0x07);
205208149Snwhitehorn
206208149Snwhitehorn	if (uninorth_enable_config(sc, bus, slot, func, reg)) {
207208149Snwhitehorn		switch (width) {
208208149Snwhitehorn		case 1:
209208149Snwhitehorn			out8rb(caoff, val);
210208149Snwhitehorn			break;
211208149Snwhitehorn		case 2:
212208149Snwhitehorn			out16rb(caoff, val);
213208149Snwhitehorn			break;
214208149Snwhitehorn		case 4:
215208149Snwhitehorn			out32rb(caoff, val);
216208149Snwhitehorn			break;
217208149Snwhitehorn		}
218208149Snwhitehorn	}
219208149Snwhitehorn}
220208149Snwhitehorn
221208149Snwhitehornstatic int
222208149Snwhitehornuninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot,
223208149Snwhitehorn    u_int func, u_int reg)
224208149Snwhitehorn{
225208149Snwhitehorn	uint32_t	cfgval;
226208149Snwhitehorn	uint32_t	pass;
227208149Snwhitehorn
228230993Snwhitehorn	if (resource_int_value(device_get_name(sc->pci_sc.sc_dev),
229230993Snwhitehorn	        device_get_unit(sc->pci_sc.sc_dev), "skipslot", &pass) == 0) {
230208149Snwhitehorn		if (pass == slot)
231208149Snwhitehorn			return (0);
232208149Snwhitehorn	}
233208149Snwhitehorn
234208149Snwhitehorn	/*
235208149Snwhitehorn	 * Issue type 0 configuration space accesses for the root bus.
236208149Snwhitehorn	 *
237208149Snwhitehorn	 * NOTE: On U4, issue only type 1 accesses. There is a secret
238208149Snwhitehorn	 * PCI Express <-> PCI Express bridge not present in the device tree,
239208149Snwhitehorn	 * and we need to route all of our configuration space through it.
240208149Snwhitehorn	 */
241230993Snwhitehorn	if (sc->pci_sc.sc_bus == bus && sc->sc_ver < 4) {
242208149Snwhitehorn		/*
243208149Snwhitehorn		 * No slots less than 11 on the primary bus on U3 and lower
244208149Snwhitehorn		 */
245208149Snwhitehorn		if (slot < 11)
246208149Snwhitehorn			return (0);
247208149Snwhitehorn
248208149Snwhitehorn		cfgval = (1 << slot) | (func << 8) | (reg & 0xfc);
249208149Snwhitehorn	} else {
250208149Snwhitehorn		cfgval = (bus << 16) | (slot << 11) | (func << 8) |
251208149Snwhitehorn		    (reg & 0xfc) | 1;
252208149Snwhitehorn	}
253208149Snwhitehorn
254208149Snwhitehorn	/* Set extended register bits on U4 */
255208149Snwhitehorn	if (sc->sc_ver == 4)
256208149Snwhitehorn		cfgval |= (reg >> 8) << 28;
257208149Snwhitehorn
258208149Snwhitehorn	do {
259208149Snwhitehorn		out32rb(sc->sc_addr, cfgval);
260208149Snwhitehorn	} while (in32rb(sc->sc_addr) != cfgval);
261208149Snwhitehorn
262208149Snwhitehorn	return (1);
263208149Snwhitehorn}
264208149Snwhitehorn
265