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: releng/11.0/sys/sparc64/pci/apb.c 297000 2016-03-18 01:28:41Z jhibbits $");
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>
51221393Sjhb#include <sys/rman.h>
52225931Smarius#include <sys/sysctl.h>
5386231Stmm
54133589Smarius#include <dev/ofw/ofw_bus.h>
5593067Stmm#include <dev/ofw/openfirm.h>
5693067Stmm
57117119Stmm#include <machine/bus.h>
5886231Stmm#include <machine/resource.h>
5986231Stmm
60119291Simp#include <dev/pci/pcireg.h>
61119291Simp#include <dev/pci/pcivar.h>
62119291Simp#include <dev/pci/pcib_private.h>
6386231Stmm
6486231Stmm#include "pcib_if.h"
6586231Stmm
66117119Stmm#include <sparc64/pci/ofw_pci.h>
67117119Stmm#include <sparc64/pci/ofw_pcib_subr.h>
68117119Stmm
6986231Stmm/*
7086231Stmm * Bridge-specific data.
7186231Stmm */
7286231Stmmstruct apb_softc {
73117119Stmm	struct ofw_pcib_gen_softc	sc_bsc;
74153057Smarius	uint8_t		sc_iomap;
75153057Smarius	uint8_t		sc_memmap;
7686231Stmm};
7786231Stmm
78117119Stmmstatic device_probe_t apb_probe;
79117119Stmmstatic device_attach_t apb_attach;
80117119Stmmstatic bus_alloc_resource_t apb_alloc_resource;
81225931Smariusstatic bus_adjust_resource_t apb_adjust_resource;
8286231Stmm
8386231Stmmstatic device_method_t apb_methods[] = {
8486231Stmm	/* Device interface */
8586231Stmm	DEVMETHOD(device_probe,		apb_probe),
8686231Stmm	DEVMETHOD(device_attach,	apb_attach),
8786231Stmm
8886231Stmm	/* Bus interface */
8986231Stmm	DEVMETHOD(bus_alloc_resource,	apb_alloc_resource),
90225931Smarius	DEVMETHOD(bus_adjust_resource,	apb_adjust_resource),
91225931Smarius	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
9286231Stmm
9386231Stmm	/* pcib interface */
94117119Stmm	DEVMETHOD(pcib_route_interrupt,	ofw_pcib_gen_route_interrupt),
9586231Stmm
96133589Smarius	/* ofw_bus interface */
97133589Smarius	DEVMETHOD(ofw_bus_get_node,	ofw_pcib_gen_get_node),
98133589Smarius
99227848Smarius	DEVMETHOD_END
10086231Stmm};
10186231Stmm
102154079Sjhbstatic devclass_t pcib_devclass;
10386231Stmm
104216962SmariusDEFINE_CLASS_1(pcib, apb_driver, apb_methods, sizeof(struct apb_softc),
105216962Smarius    pcib_driver);
106200874SmariusEARLY_DRIVER_MODULE(apb, pci, apb_driver, pcib_devclass, 0, 0, BUS_PASS_BUS);
107200815SmariusMODULE_DEPEND(apb, pci, 1, 1, 1);
10886231Stmm
10986231Stmm/* APB specific registers */
11086231Stmm#define	APBR_IOMAP	0xde
11186231Stmm#define	APBR_MEMMAP	0xdf
11286231Stmm
11386231Stmm/* Definitions for the mapping registers */
11486231Stmm#define	APB_IO_SCALE	0x200000
11586231Stmm#define	APB_MEM_SCALE	0x20000000
11686231Stmm
11786231Stmm/*
11886231Stmm * Generic device interface
11986231Stmm */
12086231Stmmstatic int
12186231Stmmapb_probe(device_t dev)
12286231Stmm{
12386231Stmm
12486231Stmm	if (pci_get_vendor(dev) == 0x108e &&	/* Sun */
12586231Stmm	    pci_get_device(dev) == 0x5000)  {	/* APB */
12686231Stmm		device_set_desc(dev, "APB PCI-PCI bridge");
12786231Stmm		return (0);
12886231Stmm	}
12986231Stmm	return (ENXIO);
13086231Stmm}
13186231Stmm
13286231Stmmstatic void
133294883Sjhibbitsapb_map_print(uint8_t map, rman_res_t scale)
13486231Stmm{
13586231Stmm	int i, first;
13686231Stmm
13786231Stmm	for (first = 1, i = 0; i < 8; i++) {
13886231Stmm		if ((map & (1 << i)) != 0) {
139297000Sjhibbits			printf("%s0x%jx-0x%jx", first ? "" : ", ",
14086231Stmm			    i * scale, (i + 1) * scale - 1);
14186231Stmm			first = 0;
14286231Stmm		}
14386231Stmm	}
14486231Stmm}
14586231Stmm
14686231Stmmstatic int
147294883Sjhibbitsapb_checkrange(uint8_t map, rman_res_t scale, rman_res_t start, rman_res_t end)
14886231Stmm{
14986231Stmm	int i, ei;
15086231Stmm
15186231Stmm	i = start / scale;
15286231Stmm	ei = end / scale;
15386231Stmm	if (i > 7 || ei > 7)
15486231Stmm		return (0);
15586231Stmm	for (; i <= ei; i++)
15686231Stmm		if ((map & (1 << i)) == 0)
15786231Stmm			return (0);
15886231Stmm	return (1);
15986231Stmm}
16086231Stmm
16186231Stmmstatic int
16286231Stmmapb_attach(device_t dev)
16386231Stmm{
16488369Stmm	struct apb_softc *sc;
165225931Smarius	struct sysctl_ctx_list *sctx;
166225931Smarius	struct sysctl_oid *soid;
16786231Stmm
16886231Stmm	sc = device_get_softc(dev);
16986231Stmm
17086231Stmm	/*
17186231Stmm	 * Get current bridge configuration.
17286231Stmm	 */
173178279Smarius	sc->sc_bsc.ops_pcib_sc.domain = pci_get_domain(dev);
174281930Sjhb	sc->sc_bsc.ops_pcib_sc.pribus = pci_get_bus(dev);
175281930Sjhb	pci_write_config(dev, PCIR_PRIBUS_1, sc->sc_bsc.ops_pcib_sc.pribus, 1);
176261790Sjhb	sc->sc_bsc.ops_pcib_sc.bus.sec =
177178279Smarius	    pci_read_config(dev, PCIR_SECBUS_1, 1);
178261790Sjhb	sc->sc_bsc.ops_pcib_sc.bus.sub =
179178279Smarius	    pci_read_config(dev, PCIR_SUBBUS_1, 1);
180225931Smarius	sc->sc_bsc.ops_pcib_sc.bridgectl =
181225931Smarius	    pci_read_config(dev, PCIR_BRIDGECTL_1, 2);
182117119Stmm	sc->sc_iomap = pci_read_config(dev, APBR_IOMAP, 1);
183117119Stmm	sc->sc_memmap = pci_read_config(dev, APBR_MEMMAP, 1);
184225931Smarius
185225931Smarius	/*
186225931Smarius	 * Setup SYSCTL reporting nodes.
187225931Smarius	 */
188225931Smarius	sctx = device_get_sysctl_ctx(dev);
189225931Smarius	soid = device_get_sysctl_tree(dev);
190225931Smarius	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain",
191225931Smarius	    CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.domain, 0,
192225931Smarius	    "Domain number");
193225931Smarius	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus",
194225931Smarius	    CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.pribus, 0,
195225931Smarius	    "Primary bus number");
196225931Smarius	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus",
197261790Sjhb	    CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.bus.sec, 0,
198225931Smarius	    "Secondary bus number");
199225931Smarius	SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus",
200261790Sjhb	    CTLFLAG_RD, &sc->sc_bsc.ops_pcib_sc.bus.sub, 0,
201225931Smarius	    "Subordinate bus number");
202225931Smarius
203117119Stmm	ofw_pcib_gen_setup(dev);
20486231Stmm
20586231Stmm	if (bootverbose) {
206172394Smarius		device_printf(dev, "  domain            %d\n",
207172394Smarius		    sc->sc_bsc.ops_pcib_sc.domain);
208117119Stmm		device_printf(dev, "  secondary bus     %d\n",
209261790Sjhb		    sc->sc_bsc.ops_pcib_sc.bus.sec);
210117119Stmm		device_printf(dev, "  subordinate bus   %d\n",
211261790Sjhb		    sc->sc_bsc.ops_pcib_sc.bus.sub);
21286231Stmm		device_printf(dev, "  I/O decode        ");
213117119Stmm		apb_map_print(sc->sc_iomap, APB_IO_SCALE);
21486231Stmm		printf("\n");
21586231Stmm		device_printf(dev, "  memory decode     ");
216117119Stmm		apb_map_print(sc->sc_memmap, APB_MEM_SCALE);
21786231Stmm		printf("\n");
21886231Stmm	}
21986231Stmm
220178279Smarius	device_add_child(dev, "pci", -1);
221117119Stmm	return (bus_generic_attach(dev));
22286231Stmm}
22386231Stmm
22486231Stmm/*
22586231Stmm * We have to trap resource allocation requests and ensure that the bridge
22686231Stmm * is set up to, or capable of handling them.
22786231Stmm */
22886231Stmmstatic struct resource *
229178279Smariusapb_alloc_resource(device_t dev, device_t child, int type, int *rid,
230294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
23186231Stmm{
23288369Stmm	struct apb_softc *sc;
23386231Stmm
23486231Stmm	sc = device_get_softc(dev);
235145610Smarcel
23686231Stmm	/*
23786231Stmm	 * If this is a "default" allocation against this rid, we can't work
238129051Smarius	 * out where it's coming from (we should actually never see these) so
239129051Smarius	 * we just have to punt.
24086231Stmm	 */
241295832Sjhibbits	if (RMAN_IS_DEFAULT_RANGE(start, end)) {
24286231Stmm		device_printf(dev, "can't decode default resource id %d for "
243206019Smarius		    "%s, bypassing\n", *rid, device_get_nameunit(child));
244145610Smarcel		goto passup;
245145610Smarcel	}
24686231Stmm
247145610Smarcel	/*
248145610Smarcel	 * Fail the allocation for this range if it's not supported.
249145610Smarcel	 * XXX we should probably just fix up the bridge decode and
250145610Smarcel	 * soldier on.
251145610Smarcel	 */
252145610Smarcel	switch (type) {
253145610Smarcel	case SYS_RES_IOPORT:
254145610Smarcel		if (!apb_checkrange(sc->sc_iomap, APB_IO_SCALE, start, end)) {
255206019Smarius			device_printf(dev, "device %s requested unsupported "
256297000Sjhibbits			    "I/O range 0x%jx-0x%jx\n",
257206019Smarius			    device_get_nameunit(child), start, end);
258145610Smarcel			return (NULL);
259145610Smarcel		}
260145610Smarcel		if (bootverbose)
261145610Smarcel			device_printf(sc->sc_bsc.ops_pcib_sc.dev, "device "
262297000Sjhibbits			    "%s requested decoded I/O range 0x%jx-0x%jx\n",
263206019Smarius			    device_get_nameunit(child), start, end);
264145610Smarcel		break;
265145610Smarcel	case SYS_RES_MEMORY:
266225931Smarius		if (!apb_checkrange(sc->sc_memmap, APB_MEM_SCALE, start,
267225931Smarius		    end)) {
268206019Smarius			device_printf(dev, "device %s requested unsupported "
269297000Sjhibbits			    "memory range 0x%jx-0x%jx\n",
270206019Smarius			    device_get_nameunit(child), start, end);
271145610Smarcel			return (NULL);
27286231Stmm		}
273145610Smarcel		if (bootverbose)
274145610Smarcel			device_printf(sc->sc_bsc.ops_pcib_sc.dev, "device "
275297000Sjhibbits			    "%s requested decoded memory range 0x%jx-0x%jx\n",
276206019Smarius			    device_get_nameunit(child), start, end);
277145610Smarcel		break;
27886231Stmm	}
27986231Stmm
280145610Smarcel passup:
28186231Stmm	/*
28286231Stmm	 * Bridge is OK decoding this resource, so pass it up.
28386231Stmm	 */
28486231Stmm	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
28586231Stmm	    count, flags));
28686231Stmm}
287225931Smarius
288225931Smariusstatic int
289225931Smariusapb_adjust_resource(device_t dev, device_t child, int type,
290294883Sjhibbits    struct resource *r, rman_res_t start, rman_res_t end)
291225931Smarius{
292225931Smarius	struct apb_softc *sc;
293225931Smarius
294225931Smarius	sc = device_get_softc(dev);
295225931Smarius	switch (type) {
296225931Smarius	case SYS_RES_IOPORT:
297225931Smarius		if (!apb_checkrange(sc->sc_iomap, APB_IO_SCALE, start, end))
298225931Smarius			return (ENXIO);
299225931Smarius		break;
300225931Smarius	case SYS_RES_MEMORY:
301225931Smarius		if (!apb_checkrange(sc->sc_memmap, APB_MEM_SCALE, start, end))
302225931Smarius			return (ENXIO);
303225931Smarius		break;
304225931Smarius	}
305225931Smarius	return (bus_generic_adjust_resource(dev, child, type, r, start, end));
306225931Smarius}
307