apb.c revision 172394
186231Stmm/*-
286231Stmm * Copyright (c) 1994,1995 Stefan Esser, Wolfgang StanglMeier
386231Stmm * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
486231Stmm * Copyright (c) 2000 BSDi
5117119Stmm * Copyright (c) 2001, 2003 Thomas Moestl <tmm@FreeBSD.org>
686231Stmm * All rights reserved.
786231Stmm *
886231Stmm * Redistribution and use in source and binary forms, with or without
986231Stmm * modification, are permitted provided that the following conditions
1086231Stmm * are met:
1186231Stmm * 1. Redistributions of source code must retain the above copyright
1286231Stmm *    notice, this list of conditions and the following disclaimer.
1386231Stmm * 2. Redistributions in binary form must reproduce the above copyright
1486231Stmm *    notice, this list of conditions and the following disclaimer in the
1586231Stmm *    documentation and/or other materials provided with the distribution.
1686231Stmm * 3. The name of the author may not be used to endorse or promote products
1786231Stmm *    derived from this software without specific prior written permission.
1886231Stmm *
1986231Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2086231Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2186231Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2286231Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2386231Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2486231Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2586231Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2686231Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2786231Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2886231Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2986231Stmm * SUCH DAMAGE.
3086231Stmm *
3186231Stmm *	from: FreeBSD: src/sys/dev/pci/pci_pci.c,v 1.3 2000/12/13
3286231Stmm */
3386231Stmm
34153057Smarius#include <sys/cdefs.h>
35153057Smarius__FBSDID("$FreeBSD: head/sys/sparc64/pci/apb.c 172394 2007-09-30 11:05:18Z marius $");
36153057Smarius
3786231Stmm/*
3886231Stmm * Support for the Sun APB (Advanced PCI Bridge) PCI-PCI bridge.
3986231Stmm * This bridge does not fully comply to the PCI bridge specification, and is
4086231Stmm * therefore not supported by the generic driver.
41129051Smarius * We can use some of the pcib methods anyway.
4286231Stmm */
4386231Stmm
44117119Stmm#include "opt_ofw_pci.h"
45117119Stmm
4686231Stmm#include <sys/param.h>
4786231Stmm#include <sys/systm.h>
4886231Stmm#include <sys/kernel.h>
49130025Sphk#include <sys/module.h>
5086231Stmm#include <sys/bus.h>
5186231Stmm
52133589Smarius#include <dev/ofw/ofw_bus.h>
5393067Stmm#include <dev/ofw/openfirm.h>
5493067Stmm
55117119Stmm#include <machine/bus.h>
56117119Stmm#include <machine/ofw_bus.h>
5786231Stmm#include <machine/resource.h>
5886231Stmm
59119291Simp#include <dev/pci/pcireg.h>
60119291Simp#include <dev/pci/pcivar.h>
61119291Simp#include <dev/pci/pcib_private.h>
6286231Stmm
6386231Stmm#include "pcib_if.h"
6486231Stmm
65117119Stmm#include <sparc64/pci/ofw_pci.h>
66117119Stmm#include <sparc64/pci/ofw_pcib_subr.h>
67117119Stmm
6886231Stmm/*
6986231Stmm * Bridge-specific data.
7086231Stmm */
7186231Stmmstruct apb_softc {
72117119Stmm	struct ofw_pcib_gen_softc	sc_bsc;
73153057Smarius	uint8_t		sc_iomap;
74153057Smarius	uint8_t		sc_memmap;
7586231Stmm};
7686231Stmm
77117119Stmmstatic device_probe_t apb_probe;
78117119Stmmstatic device_attach_t apb_attach;
79117119Stmmstatic bus_alloc_resource_t apb_alloc_resource;
8086231Stmm
8186231Stmmstatic device_method_t apb_methods[] = {
8286231Stmm	/* Device interface */
8386231Stmm	DEVMETHOD(device_probe,		apb_probe),
8486231Stmm	DEVMETHOD(device_attach,	apb_attach),
8586231Stmm	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
8686231Stmm	DEVMETHOD(device_suspend,	bus_generic_suspend),
8786231Stmm	DEVMETHOD(device_resume,	bus_generic_resume),
8886231Stmm
8986231Stmm	/* Bus interface */
9086231Stmm	DEVMETHOD(bus_print_child,	bus_generic_print_child),
91117119Stmm	DEVMETHOD(bus_read_ivar,	pcib_read_ivar),
92117119Stmm	DEVMETHOD(bus_write_ivar,	pcib_write_ivar),
9386231Stmm	DEVMETHOD(bus_alloc_resource,	apb_alloc_resource),
9486231Stmm	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
9586231Stmm	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
9686231Stmm	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
9786231Stmm	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
9886231Stmm	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
9986231Stmm
10086231Stmm	/* pcib interface */
101117119Stmm	DEVMETHOD(pcib_maxslots,	pcib_maxslots),
102117119Stmm	DEVMETHOD(pcib_read_config,	pcib_read_config),
103117119Stmm	DEVMETHOD(pcib_write_config,	pcib_write_config),
104117119Stmm	DEVMETHOD(pcib_route_interrupt,	ofw_pcib_gen_route_interrupt),
10586231Stmm
106133589Smarius	/* ofw_bus interface */
107133589Smarius	DEVMETHOD(ofw_bus_get_node,	ofw_pcib_gen_get_node),
108133589Smarius
109117119Stmm	/* ofw_pci interface */
110117119Stmm	DEVMETHOD(ofw_pci_adjust_busrange,	ofw_pcib_gen_adjust_busrange),
111117119Stmm
11286231Stmm	{ 0, 0 }
11386231Stmm};
11486231Stmm
115154079Sjhbstatic devclass_t pcib_devclass;
11686231Stmm
117154079SjhbDEFINE_CLASS_0(pcib, apb_driver, apb_methods, sizeof(struct apb_softc));
118117119StmmDRIVER_MODULE(apb, pci, apb_driver, pcib_devclass, 0, 0);
11986231Stmm
12086231Stmm/* APB specific registers */
12186231Stmm#define	APBR_IOMAP	0xde
12286231Stmm#define	APBR_MEMMAP	0xdf
12386231Stmm
12486231Stmm/* Definitions for the mapping registers */
12586231Stmm#define	APB_IO_SCALE	0x200000
12686231Stmm#define	APB_MEM_SCALE	0x20000000
12786231Stmm
12886231Stmm/*
12986231Stmm * Generic device interface
13086231Stmm */
13186231Stmmstatic int
13286231Stmmapb_probe(device_t dev)
13386231Stmm{
13486231Stmm
13586231Stmm	if (pci_get_vendor(dev) == 0x108e &&	/* Sun */
13686231Stmm	    pci_get_device(dev) == 0x5000)  {	/* APB */
13786231Stmm		device_set_desc(dev, "APB PCI-PCI bridge");
13886231Stmm		return (0);
13986231Stmm	}
14086231Stmm	return (ENXIO);
14186231Stmm}
14286231Stmm
14386231Stmmstatic void
144153057Smariusapb_map_print(uint8_t map, u_long scale)
14586231Stmm{
14686231Stmm	int i, first;
14786231Stmm
14886231Stmm	for (first = 1, i = 0; i < 8; i++) {
14986231Stmm		if ((map & (1 << i)) != 0) {
15086231Stmm			printf("%s0x%lx-0x%lx", first ? "" : ", ",
15186231Stmm			    i * scale, (i + 1) * scale - 1);
15286231Stmm			first = 0;
15386231Stmm		}
15486231Stmm	}
15586231Stmm}
15686231Stmm
15786231Stmmstatic int
158153057Smariusapb_checkrange(uint8_t map, u_long scale, u_long start, u_long end)
15986231Stmm{
16086231Stmm	int i, ei;
16186231Stmm
16286231Stmm	i = start / scale;
16386231Stmm	ei = end / scale;
16486231Stmm	if (i > 7 || ei > 7)
16586231Stmm		return (0);
16686231Stmm	for (; i <= ei; i++)
16786231Stmm		if ((map & (1 << i)) == 0)
16886231Stmm			return (0);
16986231Stmm	return (1);
17086231Stmm}
17186231Stmm
17286231Stmmstatic int
17386231Stmmapb_attach(device_t dev)
17486231Stmm{
17588369Stmm	struct apb_softc *sc;
17686231Stmm
17786231Stmm	sc = device_get_softc(dev);
17886231Stmm
17986231Stmm	/*
18086231Stmm	 * Get current bridge configuration.
18186231Stmm	 */
182117119Stmm	sc->sc_iomap = pci_read_config(dev, APBR_IOMAP, 1);
183117119Stmm	sc->sc_memmap = pci_read_config(dev, APBR_MEMMAP, 1);
184117119Stmm	ofw_pcib_gen_setup(dev);
18586231Stmm
18686231Stmm	if (bootverbose) {
187172394Smarius		device_printf(dev, "  domain            %d\n",
188172394Smarius		    sc->sc_bsc.ops_pcib_sc.domain);
189117119Stmm		device_printf(dev, "  secondary bus     %d\n",
190117119Stmm		    sc->sc_bsc.ops_pcib_sc.secbus);
191117119Stmm		device_printf(dev, "  subordinate bus   %d\n",
192117119Stmm		    sc->sc_bsc.ops_pcib_sc.subbus);
19386231Stmm		device_printf(dev, "  I/O decode        ");
194117119Stmm		apb_map_print(sc->sc_iomap, APB_IO_SCALE);
19586231Stmm		printf("\n");
19686231Stmm		device_printf(dev, "  memory decode     ");
197117119Stmm		apb_map_print(sc->sc_memmap, APB_MEM_SCALE);
19886231Stmm		printf("\n");
19986231Stmm	}
20086231Stmm
201117119Stmm	device_add_child(dev, "pci", sc->sc_bsc.ops_pcib_sc.secbus);
202117119Stmm	return (bus_generic_attach(dev));
20386231Stmm}
20486231Stmm
20586231Stmm/*
20686231Stmm * We have to trap resource allocation requests and ensure that the bridge
20786231Stmm * is set up to, or capable of handling them.
20886231Stmm */
20986231Stmmstatic struct resource *
21086231Stmmapb_alloc_resource(device_t dev, device_t child, int type, int *rid,
21186231Stmm    u_long start, u_long end, u_long count, u_int flags)
21286231Stmm{
21388369Stmm	struct apb_softc *sc;
21486231Stmm
21586231Stmm	sc = device_get_softc(dev);
216145610Smarcel
21786231Stmm	/*
21886231Stmm	 * If this is a "default" allocation against this rid, we can't work
219129051Smarius	 * out where it's coming from (we should actually never see these) so
220129051Smarius	 * we just have to punt.
22186231Stmm	 */
222145610Smarcel	if (start == 0 && end == ~0) {
22386231Stmm		device_printf(dev, "can't decode default resource id %d for "
22486231Stmm		    "%s%d, bypassing\n", *rid, device_get_name(child),
22586231Stmm		    device_get_unit(child));
226145610Smarcel		goto passup;
227145610Smarcel	}
22886231Stmm
229145610Smarcel	/*
230145610Smarcel	 * Fail the allocation for this range if it's not supported.
231145610Smarcel	 * XXX we should probably just fix up the bridge decode and
232145610Smarcel	 * soldier on.
233145610Smarcel	 */
234145610Smarcel	switch (type) {
235145610Smarcel	case SYS_RES_IOPORT:
236145610Smarcel		if (!apb_checkrange(sc->sc_iomap, APB_IO_SCALE, start, end)) {
237145610Smarcel			device_printf(dev, "device %s%d requested unsupported "
238145610Smarcel			    "I/O range 0x%lx-0x%lx\n", device_get_name(child),
239145610Smarcel			    device_get_unit(child), start, end);
240145610Smarcel			return (NULL);
241145610Smarcel		}
242145610Smarcel		if (bootverbose)
243145610Smarcel			device_printf(sc->sc_bsc.ops_pcib_sc.dev, "device "
244145610Smarcel			    "%s%d requested decoded I/O range 0x%lx-0x%lx\n",
245145610Smarcel			    device_get_name(child), device_get_unit(child),
246145610Smarcel			    start, end);
247145610Smarcel		break;
24886231Stmm
249145610Smarcel	case SYS_RES_MEMORY:
250145610Smarcel		if (!apb_checkrange(sc->sc_memmap, APB_MEM_SCALE, start, end)) {
251145610Smarcel			device_printf(dev, "device %s%d requested unsupported "
252145610Smarcel			    "memory range 0x%lx-0x%lx\n",
253145610Smarcel			    device_get_name(child), device_get_unit(child),
254145610Smarcel			    start, end);
255145610Smarcel			return (NULL);
25686231Stmm		}
257145610Smarcel		if (bootverbose)
258145610Smarcel			device_printf(sc->sc_bsc.ops_pcib_sc.dev, "device "
259145610Smarcel			    "%s%d requested decoded memory range 0x%lx-0x%lx\n",
260145610Smarcel			    device_get_name(child), device_get_unit(child),
261145610Smarcel			    start, end);
262145610Smarcel		break;
263145610Smarcel
264145610Smarcel	default:
265145610Smarcel		break;
26686231Stmm	}
26786231Stmm
268145610Smarcel passup:
26986231Stmm	/*
27086231Stmm	 * Bridge is OK decoding this resource, so pass it up.
27186231Stmm	 */
27286231Stmm	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
27386231Stmm	    count, flags));
27486231Stmm}
275