xref: /freebsd/sys/arm/mv/mv_pci.c (revision 1b96faf8fa3fa07672531955414dbca709c865e4)
16975124cSRafal Jaworowski /*-
2db5ef4fcSRafal Jaworowski  * Copyright (c) 2008 MARVELL INTERNATIONAL LTD.
3db5ef4fcSRafal Jaworowski  * Copyright (c) 2010 The FreeBSD Foundation
46975124cSRafal Jaworowski  * All rights reserved.
56975124cSRafal Jaworowski  *
66975124cSRafal Jaworowski  * Developed by Semihalf.
76975124cSRafal Jaworowski  *
8db5ef4fcSRafal Jaworowski  * Portions of this software were developed by Semihalf
9db5ef4fcSRafal Jaworowski  * under sponsorship from the FreeBSD Foundation.
10db5ef4fcSRafal Jaworowski  *
116975124cSRafal Jaworowski  * Redistribution and use in source and binary forms, with or without
126975124cSRafal Jaworowski  * modification, are permitted provided that the following conditions
136975124cSRafal Jaworowski  * are met:
146975124cSRafal Jaworowski  * 1. Redistributions of source code must retain the above copyright
156975124cSRafal Jaworowski  *    notice, this list of conditions and the following disclaimer.
166975124cSRafal Jaworowski  * 2. Redistributions in binary form must reproduce the above copyright
176975124cSRafal Jaworowski  *    notice, this list of conditions and the following disclaimer in the
186975124cSRafal Jaworowski  *    documentation and/or other materials provided with the distribution.
196975124cSRafal Jaworowski  * 3. Neither the name of MARVELL nor the names of contributors
206975124cSRafal Jaworowski  *    may be used to endorse or promote products derived from this software
216975124cSRafal Jaworowski  *    without specific prior written permission.
226975124cSRafal Jaworowski  *
236975124cSRafal Jaworowski  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
246975124cSRafal Jaworowski  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
256975124cSRafal Jaworowski  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
266975124cSRafal Jaworowski  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
276975124cSRafal Jaworowski  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
286975124cSRafal Jaworowski  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
296975124cSRafal Jaworowski  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
306975124cSRafal Jaworowski  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
316975124cSRafal Jaworowski  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
326975124cSRafal Jaworowski  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
336975124cSRafal Jaworowski  * SUCH DAMAGE.
346975124cSRafal Jaworowski  */
356975124cSRafal Jaworowski 
366975124cSRafal Jaworowski /*
376975124cSRafal Jaworowski  * Marvell integrated PCI/PCI-Express controller driver.
386975124cSRafal Jaworowski  */
396975124cSRafal Jaworowski 
406975124cSRafal Jaworowski #include <sys/cdefs.h>
416975124cSRafal Jaworowski __FBSDID("$FreeBSD$");
426975124cSRafal Jaworowski 
436975124cSRafal Jaworowski #include <sys/param.h>
446975124cSRafal Jaworowski #include <sys/systm.h>
456975124cSRafal Jaworowski #include <sys/kernel.h>
466975124cSRafal Jaworowski #include <sys/lock.h>
476975124cSRafal Jaworowski #include <sys/malloc.h>
486975124cSRafal Jaworowski #include <sys/module.h>
496975124cSRafal Jaworowski #include <sys/mutex.h>
506975124cSRafal Jaworowski #include <sys/queue.h>
516975124cSRafal Jaworowski #include <sys/bus.h>
526975124cSRafal Jaworowski #include <sys/rman.h>
536975124cSRafal Jaworowski #include <sys/endian.h>
546975124cSRafal Jaworowski 
556975124cSRafal Jaworowski #include <vm/vm.h>
566975124cSRafal Jaworowski #include <vm/pmap.h>
576975124cSRafal Jaworowski 
58db5ef4fcSRafal Jaworowski #include <dev/fdt/fdt_common.h>
59db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h>
60db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h>
616975124cSRafal Jaworowski #include <dev/pci/pcivar.h>
626975124cSRafal Jaworowski #include <dev/pci/pcireg.h>
636975124cSRafal Jaworowski #include <dev/pci/pcib_private.h>
646975124cSRafal Jaworowski 
65db5ef4fcSRafal Jaworowski #include "ofw_bus_if.h"
666975124cSRafal Jaworowski #include "pcib_if.h"
676975124cSRafal Jaworowski 
686975124cSRafal Jaworowski #include <machine/resource.h>
696975124cSRafal Jaworowski #include <machine/bus.h>
706975124cSRafal Jaworowski 
716975124cSRafal Jaworowski #include <arm/mv/mvreg.h>
726975124cSRafal Jaworowski #include <arm/mv/mvvar.h>
73db5ef4fcSRafal Jaworowski #include <arm/mv/mvwin.h>
746975124cSRafal Jaworowski 
756975124cSRafal Jaworowski #define PCI_CFG_ENA		(1 << 31)
766975124cSRafal Jaworowski #define PCI_CFG_BUS(bus)	(((bus) & 0xff) << 16)
776975124cSRafal Jaworowski #define PCI_CFG_DEV(dev)	(((dev) & 0x1f) << 11)
786975124cSRafal Jaworowski #define PCI_CFG_FUN(fun)	(((fun) & 0x7) << 8)
796975124cSRafal Jaworowski #define PCI_CFG_PCIE_REG(reg)	((reg) & 0xfc)
806975124cSRafal Jaworowski 
816975124cSRafal Jaworowski #define PCI_REG_CFG_ADDR	0x0C78
826975124cSRafal Jaworowski #define PCI_REG_CFG_DATA	0x0C7C
836975124cSRafal Jaworowski #define PCI_REG_P2P_CONF	0x1D14
846975124cSRafal Jaworowski 
856975124cSRafal Jaworowski #define PCIE_REG_CFG_ADDR	0x18F8
866975124cSRafal Jaworowski #define PCIE_REG_CFG_DATA	0x18FC
876975124cSRafal Jaworowski #define PCIE_REG_CONTROL	0x1A00
886975124cSRafal Jaworowski #define   PCIE_CTRL_LINK1X	0x00000001
896975124cSRafal Jaworowski #define PCIE_REG_STATUS		0x1A04
906975124cSRafal Jaworowski #define PCIE_REG_IRQ_MASK	0x1910
916975124cSRafal Jaworowski 
924e883c81SRafal Jaworowski #define STATUS_LINK_DOWN	1
936975124cSRafal Jaworowski #define STATUS_BUS_OFFS		8
946975124cSRafal Jaworowski #define STATUS_BUS_MASK		(0xFF << STATUS_BUS_OFFS)
956975124cSRafal Jaworowski #define STATUS_DEV_OFFS		16
966975124cSRafal Jaworowski #define STATUS_DEV_MASK		(0x1F << STATUS_DEV_OFFS)
976975124cSRafal Jaworowski 
986975124cSRafal Jaworowski #define P2P_CONF_BUS_OFFS	16
996975124cSRafal Jaworowski #define P2P_CONF_BUS_MASK	(0xFF << P2P_CONF_BUS_OFFS)
1006975124cSRafal Jaworowski #define P2P_CONF_DEV_OFFS	24
1016975124cSRafal Jaworowski #define P2P_CONF_DEV_MASK	(0x1F << P2P_CONF_DEV_OFFS)
1026975124cSRafal Jaworowski 
1036975124cSRafal Jaworowski #define PCI_VENDORID_MRVL	0x11AB
1046975124cSRafal Jaworowski 
105db5ef4fcSRafal Jaworowski struct mv_pcib_softc {
1066975124cSRafal Jaworowski 	device_t	sc_dev;
1076975124cSRafal Jaworowski 
108db5ef4fcSRafal Jaworowski 	struct rman	sc_mem_rman;
109db5ef4fcSRafal Jaworowski 	bus_addr_t	sc_mem_base;
110db5ef4fcSRafal Jaworowski 	bus_addr_t	sc_mem_size;
111db5ef4fcSRafal Jaworowski 	bus_addr_t	sc_mem_alloc;		/* Next allocation. */
112db5ef4fcSRafal Jaworowski 	int		sc_mem_win_target;
113db5ef4fcSRafal Jaworowski 	int		sc_mem_win_attr;
1146975124cSRafal Jaworowski 
115db5ef4fcSRafal Jaworowski 	struct rman	sc_io_rman;
116db5ef4fcSRafal Jaworowski 	bus_addr_t	sc_io_base;
117db5ef4fcSRafal Jaworowski 	bus_addr_t	sc_io_size;
118db5ef4fcSRafal Jaworowski 	bus_addr_t	sc_io_alloc;		/* Next allocation. */
119db5ef4fcSRafal Jaworowski 	int		sc_io_win_target;
120db5ef4fcSRafal Jaworowski 	int		sc_io_win_attr;
1216975124cSRafal Jaworowski 
1226975124cSRafal Jaworowski 	struct resource	*sc_res;
1236975124cSRafal Jaworowski 	bus_space_handle_t sc_bsh;
1246975124cSRafal Jaworowski 	bus_space_tag_t	sc_bst;
1256975124cSRafal Jaworowski 	int		sc_rid;
1266975124cSRafal Jaworowski 
1276975124cSRafal Jaworowski 	int		sc_busnr;		/* Host bridge bus number */
1286975124cSRafal Jaworowski 	int		sc_devnr;		/* Host bridge device number */
129db5ef4fcSRafal Jaworowski 	int		sc_type;
1306975124cSRafal Jaworowski 
131db5ef4fcSRafal Jaworowski 	struct fdt_pci_intr	sc_intr_info;
1326975124cSRafal Jaworowski };
1336975124cSRafal Jaworowski 
134db5ef4fcSRafal Jaworowski /* Local forward prototypes */
135db5ef4fcSRafal Jaworowski static int mv_pcib_decode_win(phandle_t, struct mv_pcib_softc *);
136db5ef4fcSRafal Jaworowski static void mv_pcib_hw_cfginit(void);
137db5ef4fcSRafal Jaworowski static uint32_t mv_pcib_hw_cfgread(struct mv_pcib_softc *, u_int, u_int,
138db5ef4fcSRafal Jaworowski     u_int, u_int, int);
139db5ef4fcSRafal Jaworowski static void mv_pcib_hw_cfgwrite(struct mv_pcib_softc *, u_int, u_int,
140db5ef4fcSRafal Jaworowski     u_int, u_int, uint32_t, int);
141db5ef4fcSRafal Jaworowski static int mv_pcib_init(struct mv_pcib_softc *, int, int);
142db5ef4fcSRafal Jaworowski static int mv_pcib_init_all_bars(struct mv_pcib_softc *, int, int, int, int);
143db5ef4fcSRafal Jaworowski static void mv_pcib_init_bridge(struct mv_pcib_softc *, int, int, int);
144db5ef4fcSRafal Jaworowski static int mv_pcib_intr_info(phandle_t, struct mv_pcib_softc *);
145db5ef4fcSRafal Jaworowski static inline void pcib_write_irq_mask(struct mv_pcib_softc *, uint32_t);
1466975124cSRafal Jaworowski 
147db5ef4fcSRafal Jaworowski 
148db5ef4fcSRafal Jaworowski /* Forward prototypes */
149db5ef4fcSRafal Jaworowski static int mv_pcib_probe(device_t);
150db5ef4fcSRafal Jaworowski static int mv_pcib_attach(device_t);
151db5ef4fcSRafal Jaworowski 
152db5ef4fcSRafal Jaworowski static struct resource *mv_pcib_alloc_resource(device_t, device_t, int, int *,
1536975124cSRafal Jaworowski     u_long, u_long, u_long, u_int);
154db5ef4fcSRafal Jaworowski static int mv_pcib_release_resource(device_t, device_t, int, int,
1556975124cSRafal Jaworowski     struct resource *);
156db5ef4fcSRafal Jaworowski static int mv_pcib_read_ivar(device_t, device_t, int, uintptr_t *);
157db5ef4fcSRafal Jaworowski static int mv_pcib_write_ivar(device_t, device_t, int, uintptr_t);
1586975124cSRafal Jaworowski 
159db5ef4fcSRafal Jaworowski static int mv_pcib_maxslots(device_t);
160db5ef4fcSRafal Jaworowski static uint32_t mv_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int);
161db5ef4fcSRafal Jaworowski static void mv_pcib_write_config(device_t, u_int, u_int, u_int, u_int,
1626975124cSRafal Jaworowski     uint32_t, int);
163db5ef4fcSRafal Jaworowski static int mv_pcib_route_interrupt(device_t, device_t, int);
1646975124cSRafal Jaworowski 
1656975124cSRafal Jaworowski /*
1666975124cSRafal Jaworowski  * Bus interface definitions.
1676975124cSRafal Jaworowski  */
168db5ef4fcSRafal Jaworowski static device_method_t mv_pcib_methods[] = {
1696975124cSRafal Jaworowski 	/* Device interface */
170db5ef4fcSRafal Jaworowski 	DEVMETHOD(device_probe,			mv_pcib_probe),
171db5ef4fcSRafal Jaworowski 	DEVMETHOD(device_attach,		mv_pcib_attach),
1726975124cSRafal Jaworowski 
1736975124cSRafal Jaworowski 	/* Bus interface */
1746975124cSRafal Jaworowski 	DEVMETHOD(bus_print_child,		bus_generic_print_child),
175db5ef4fcSRafal Jaworowski 	DEVMETHOD(bus_read_ivar,		mv_pcib_read_ivar),
176db5ef4fcSRafal Jaworowski 	DEVMETHOD(bus_write_ivar,		mv_pcib_write_ivar),
177db5ef4fcSRafal Jaworowski 	DEVMETHOD(bus_alloc_resource,		mv_pcib_alloc_resource),
178db5ef4fcSRafal Jaworowski 	DEVMETHOD(bus_release_resource,		mv_pcib_release_resource),
1796975124cSRafal Jaworowski 	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
1806975124cSRafal Jaworowski 	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
1816975124cSRafal Jaworowski 	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
1826975124cSRafal Jaworowski 	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
1836975124cSRafal Jaworowski 
1846975124cSRafal Jaworowski 	/* pcib interface */
185db5ef4fcSRafal Jaworowski 	DEVMETHOD(pcib_maxslots,		mv_pcib_maxslots),
186db5ef4fcSRafal Jaworowski 	DEVMETHOD(pcib_read_config,		mv_pcib_read_config),
187db5ef4fcSRafal Jaworowski 	DEVMETHOD(pcib_write_config,		mv_pcib_write_config),
188db5ef4fcSRafal Jaworowski 	DEVMETHOD(pcib_route_interrupt,		mv_pcib_route_interrupt),
189db5ef4fcSRafal Jaworowski 
190db5ef4fcSRafal Jaworowski 	/* OFW bus interface */
191db5ef4fcSRafal Jaworowski 	DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
192db5ef4fcSRafal Jaworowski 	DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
193db5ef4fcSRafal Jaworowski 	DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
194db5ef4fcSRafal Jaworowski 	DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
195db5ef4fcSRafal Jaworowski 	DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
1966975124cSRafal Jaworowski 
1976975124cSRafal Jaworowski 	{ 0, 0 }
1986975124cSRafal Jaworowski };
1996975124cSRafal Jaworowski 
200db5ef4fcSRafal Jaworowski static driver_t mv_pcib_driver = {
2016975124cSRafal Jaworowski 	"pcib",
202db5ef4fcSRafal Jaworowski 	mv_pcib_methods,
203db5ef4fcSRafal Jaworowski 	sizeof(struct mv_pcib_softc),
2046975124cSRafal Jaworowski };
2056975124cSRafal Jaworowski 
2066975124cSRafal Jaworowski devclass_t pcib_devclass;
2076975124cSRafal Jaworowski 
208db5ef4fcSRafal Jaworowski DRIVER_MODULE(pcib, fdtbus, mv_pcib_driver, pcib_devclass, 0, 0);
2096975124cSRafal Jaworowski 
2106975124cSRafal Jaworowski static struct mtx pcicfg_mtx;
2116975124cSRafal Jaworowski 
212db5ef4fcSRafal Jaworowski static int
213db5ef4fcSRafal Jaworowski mv_pcib_probe(device_t self)
2146975124cSRafal Jaworowski {
215*1b96faf8SMarcel Moolenaar 	phandle_t node;
2166975124cSRafal Jaworowski 
217*1b96faf8SMarcel Moolenaar 	node = ofw_bus_get_node(self);
218*1b96faf8SMarcel Moolenaar 	if (!fdt_is_type(node, "pci"))
219db5ef4fcSRafal Jaworowski 		return (ENXIO);
220*1b96faf8SMarcel Moolenaar 
221*1b96faf8SMarcel Moolenaar 	if (!(fdt_is_compatible(node, "mrvl,pcie") ||
222*1b96faf8SMarcel Moolenaar 	    fdt_is_compatible(node, "mrvl,pci")))
223db5ef4fcSRafal Jaworowski 		return (ENXIO);
2246975124cSRafal Jaworowski 
225db5ef4fcSRafal Jaworowski 	device_set_desc(self, "Marvell Integrated PCI/PCI-E Controller");
226db5ef4fcSRafal Jaworowski 	return (BUS_PROBE_DEFAULT);
227db5ef4fcSRafal Jaworowski }
228db5ef4fcSRafal Jaworowski 
229db5ef4fcSRafal Jaworowski static int
230db5ef4fcSRafal Jaworowski mv_pcib_attach(device_t self)
231db5ef4fcSRafal Jaworowski {
232db5ef4fcSRafal Jaworowski 	struct mv_pcib_softc *sc;
233db5ef4fcSRafal Jaworowski 	phandle_t node, parnode;
234db5ef4fcSRafal Jaworowski 	uint32_t val;
235db5ef4fcSRafal Jaworowski 	int err;
236db5ef4fcSRafal Jaworowski 
237db5ef4fcSRafal Jaworowski 	sc = device_get_softc(self);
238db5ef4fcSRafal Jaworowski 	sc->sc_dev = self;
239db5ef4fcSRafal Jaworowski 
240*1b96faf8SMarcel Moolenaar 	node = ofw_bus_get_node(self);
241*1b96faf8SMarcel Moolenaar 	parnode = OF_parent(node);
242*1b96faf8SMarcel Moolenaar 	if (fdt_is_compatible(node, "mrvl,pcie")) {
243db5ef4fcSRafal Jaworowski 		sc->sc_type = MV_TYPE_PCIE;
244db5ef4fcSRafal Jaworowski 		sc->sc_mem_win_target = MV_WIN_PCIE_MEM_TARGET;
245db5ef4fcSRafal Jaworowski 		sc->sc_mem_win_attr = MV_WIN_PCIE_MEM_ATTR;
246db5ef4fcSRafal Jaworowski 		sc->sc_io_win_target = MV_WIN_PCIE_IO_TARGET;
247db5ef4fcSRafal Jaworowski 		sc->sc_io_win_attr = MV_WIN_PCIE_IO_ATTR;
248db5ef4fcSRafal Jaworowski #ifdef SOC_MV_ORION
249*1b96faf8SMarcel Moolenaar 	} else if (fdt_is_compatible(node, "mrvl,pci")) {
250db5ef4fcSRafal Jaworowski 		sc->sc_type = MV_TYPE_PCI;
251db5ef4fcSRafal Jaworowski 		sc->sc_mem_win_target = MV_WIN_PCI_MEM_TARGET;
252db5ef4fcSRafal Jaworowski 		sc->sc_mem_win_attr = MV_WIN_PCI_MEM_ATTR;
253db5ef4fcSRafal Jaworowski 		sc->sc_io_win_target = MV_WIN_PCI_IO_TARGET;
254db5ef4fcSRafal Jaworowski 		sc->sc_io_win_attr = MV_WIN_PCI_IO_ATTR;
255db5ef4fcSRafal Jaworowski #endif
256db5ef4fcSRafal Jaworowski 	} else
257db5ef4fcSRafal Jaworowski 		return (ENXIO);
258db5ef4fcSRafal Jaworowski 
259db5ef4fcSRafal Jaworowski 	/*
260db5ef4fcSRafal Jaworowski 	 * Get PCI interrupt info.
261db5ef4fcSRafal Jaworowski 	 */
262db5ef4fcSRafal Jaworowski 	if (mv_pcib_intr_info(node, sc) != 0) {
263db5ef4fcSRafal Jaworowski 		device_printf(self, "could not retrieve interrupt info\n");
264db5ef4fcSRafal Jaworowski 		return (ENXIO);
265db5ef4fcSRafal Jaworowski 	}
266db5ef4fcSRafal Jaworowski 
267db5ef4fcSRafal Jaworowski 	/*
268db5ef4fcSRafal Jaworowski 	 * Retrieve our mem-mapped registers range.
269db5ef4fcSRafal Jaworowski 	 */
270db5ef4fcSRafal Jaworowski 	sc->sc_rid = 0;
271db5ef4fcSRafal Jaworowski 	sc->sc_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &sc->sc_rid,
272db5ef4fcSRafal Jaworowski 	    RF_ACTIVE);
273db5ef4fcSRafal Jaworowski 	if (sc->sc_res == NULL) {
274db5ef4fcSRafal Jaworowski 		device_printf(self, "could not map memory\n");
275db5ef4fcSRafal Jaworowski 		return (ENXIO);
276db5ef4fcSRafal Jaworowski 	}
277db5ef4fcSRafal Jaworowski 	sc->sc_bst = rman_get_bustag(sc->sc_res);
278db5ef4fcSRafal Jaworowski 	sc->sc_bsh = rman_get_bushandle(sc->sc_res);
279db5ef4fcSRafal Jaworowski 
280db5ef4fcSRafal Jaworowski 	/*
281db5ef4fcSRafal Jaworowski 	 * Configure decode windows for PCI(E) access.
282db5ef4fcSRafal Jaworowski 	 */
283db5ef4fcSRafal Jaworowski 	if (mv_pcib_decode_win(node, sc) != 0)
284db5ef4fcSRafal Jaworowski 		return (ENXIO);
285db5ef4fcSRafal Jaworowski 
286db5ef4fcSRafal Jaworowski 	mv_pcib_hw_cfginit();
287db5ef4fcSRafal Jaworowski 
288db5ef4fcSRafal Jaworowski 	/*
289db5ef4fcSRafal Jaworowski 	 * Enable PCI bridge.
290db5ef4fcSRafal Jaworowski 	 */
291db5ef4fcSRafal Jaworowski 	val = mv_pcib_hw_cfgread(sc, sc->sc_busnr, sc->sc_devnr, 0,
292db5ef4fcSRafal Jaworowski 	    PCIR_COMMAND, 2);
293db5ef4fcSRafal Jaworowski 	val |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN |
294db5ef4fcSRafal Jaworowski 	    PCIM_CMD_PORTEN;
295db5ef4fcSRafal Jaworowski 	mv_pcib_hw_cfgwrite(sc, sc->sc_busnr, sc->sc_devnr, 0,
296db5ef4fcSRafal Jaworowski 	    PCIR_COMMAND, val, 2);
297db5ef4fcSRafal Jaworowski 
298db5ef4fcSRafal Jaworowski 	sc->sc_mem_alloc = sc->sc_mem_base;
299db5ef4fcSRafal Jaworowski 	sc->sc_io_alloc = sc->sc_io_base;
300db5ef4fcSRafal Jaworowski 
301db5ef4fcSRafal Jaworowski 	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
302db5ef4fcSRafal Jaworowski 	err = rman_init(&sc->sc_mem_rman);
303db5ef4fcSRafal Jaworowski 	if (err)
304db5ef4fcSRafal Jaworowski 		return (err);
305db5ef4fcSRafal Jaworowski 
306db5ef4fcSRafal Jaworowski 	sc->sc_io_rman.rm_type = RMAN_ARRAY;
307db5ef4fcSRafal Jaworowski 	err = rman_init(&sc->sc_io_rman);
308db5ef4fcSRafal Jaworowski 	if (err) {
309db5ef4fcSRafal Jaworowski 		rman_fini(&sc->sc_mem_rman);
310db5ef4fcSRafal Jaworowski 		return (err);
311db5ef4fcSRafal Jaworowski 	}
312db5ef4fcSRafal Jaworowski 
313db5ef4fcSRafal Jaworowski 	err = rman_manage_region(&sc->sc_mem_rman, sc->sc_mem_base,
314db5ef4fcSRafal Jaworowski 	    sc->sc_mem_base + sc->sc_mem_size - 1);
315db5ef4fcSRafal Jaworowski 	if (err)
316db5ef4fcSRafal Jaworowski 		goto error;
317db5ef4fcSRafal Jaworowski 
318db5ef4fcSRafal Jaworowski 	err = rman_manage_region(&sc->sc_io_rman, sc->sc_io_base,
319db5ef4fcSRafal Jaworowski 	    sc->sc_io_base + sc->sc_io_size - 1);
320db5ef4fcSRafal Jaworowski 	if (err)
321db5ef4fcSRafal Jaworowski 		goto error;
322db5ef4fcSRafal Jaworowski 
323db5ef4fcSRafal Jaworowski 	err = mv_pcib_init(sc, sc->sc_busnr, mv_pcib_maxslots(sc->sc_dev));
324db5ef4fcSRafal Jaworowski 	if (err)
325db5ef4fcSRafal Jaworowski 		goto error;
326db5ef4fcSRafal Jaworowski 
327db5ef4fcSRafal Jaworowski 	device_add_child(self, "pci", -1);
328db5ef4fcSRafal Jaworowski 	return (bus_generic_attach(self));
329db5ef4fcSRafal Jaworowski 
330db5ef4fcSRafal Jaworowski error:
331db5ef4fcSRafal Jaworowski 	/* XXX SYS_RES_ should be released here */
332db5ef4fcSRafal Jaworowski 	rman_fini(&sc->sc_mem_rman);
333db5ef4fcSRafal Jaworowski 	rman_fini(&sc->sc_io_rman);
334db5ef4fcSRafal Jaworowski 	return (err);
335db5ef4fcSRafal Jaworowski }
336db5ef4fcSRafal Jaworowski 
337db5ef4fcSRafal Jaworowski static int
338db5ef4fcSRafal Jaworowski mv_pcib_init_bar(struct mv_pcib_softc *sc, int bus, int slot, int func,
339db5ef4fcSRafal Jaworowski     int barno)
340db5ef4fcSRafal Jaworowski {
341db5ef4fcSRafal Jaworowski 	bus_addr_t *allocp, limit;
342db5ef4fcSRafal Jaworowski 	uint32_t addr, bar, mask, size;
343db5ef4fcSRafal Jaworowski 	int reg, width;
344db5ef4fcSRafal Jaworowski 
345db5ef4fcSRafal Jaworowski 	reg = PCIR_BAR(barno);
346db5ef4fcSRafal Jaworowski 	bar = mv_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4);
347db5ef4fcSRafal Jaworowski 	if (bar == 0)
348db5ef4fcSRafal Jaworowski 		return (1);
349db5ef4fcSRafal Jaworowski 
350db5ef4fcSRafal Jaworowski 	/* Calculate BAR size: 64 or 32 bit (in 32-bit units) */
351db5ef4fcSRafal Jaworowski 	width = ((bar & 7) == 4) ? 2 : 1;
352db5ef4fcSRafal Jaworowski 
353db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4);
354db5ef4fcSRafal Jaworowski 	size = mv_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4);
355db5ef4fcSRafal Jaworowski 
356db5ef4fcSRafal Jaworowski 	/* Get BAR type and size */
357db5ef4fcSRafal Jaworowski 	if (bar & 1) {
358db5ef4fcSRafal Jaworowski 		/* I/O port */
359db5ef4fcSRafal Jaworowski 		allocp = &sc->sc_io_alloc;
360db5ef4fcSRafal Jaworowski 		limit = sc->sc_io_base + sc->sc_io_size;
361db5ef4fcSRafal Jaworowski 		size &= ~0x3;
362db5ef4fcSRafal Jaworowski 		if ((size & 0xffff0000) == 0)
363db5ef4fcSRafal Jaworowski 			size |= 0xffff0000;
364db5ef4fcSRafal Jaworowski 	} else {
365db5ef4fcSRafal Jaworowski 		/* Memory */
366db5ef4fcSRafal Jaworowski 		allocp = &sc->sc_mem_alloc;
367db5ef4fcSRafal Jaworowski 		limit = sc->sc_mem_base + sc->sc_mem_size;
368db5ef4fcSRafal Jaworowski 		size &= ~0xF;
369db5ef4fcSRafal Jaworowski 	}
370db5ef4fcSRafal Jaworowski 	mask = ~size;
371db5ef4fcSRafal Jaworowski 	size = mask + 1;
372db5ef4fcSRafal Jaworowski 
373db5ef4fcSRafal Jaworowski 	/* Sanity check (must be a power of 2) */
374db5ef4fcSRafal Jaworowski 	if (size & mask)
375db5ef4fcSRafal Jaworowski 		return (width);
376db5ef4fcSRafal Jaworowski 
377db5ef4fcSRafal Jaworowski 	addr = (*allocp + mask) & ~mask;
378db5ef4fcSRafal Jaworowski 	if ((*allocp = addr + size) > limit)
379db5ef4fcSRafal Jaworowski 		return (-1);
380db5ef4fcSRafal Jaworowski 
381db5ef4fcSRafal Jaworowski 	if (bootverbose)
382db5ef4fcSRafal Jaworowski 		printf("PCI %u:%u:%u: reg %x: size=%08x: addr=%08x\n",
383db5ef4fcSRafal Jaworowski 		    bus, slot, func, reg, size, addr);
384db5ef4fcSRafal Jaworowski 
385db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4);
386db5ef4fcSRafal Jaworowski 	if (width == 2)
387db5ef4fcSRafal Jaworowski 		mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg + 4,
388db5ef4fcSRafal Jaworowski 		    0, 4);
389db5ef4fcSRafal Jaworowski 
390db5ef4fcSRafal Jaworowski 	return (width);
3916975124cSRafal Jaworowski }
3926975124cSRafal Jaworowski 
3936975124cSRafal Jaworowski static void
394db5ef4fcSRafal Jaworowski mv_pcib_init_bridge(struct mv_pcib_softc *sc, int bus, int slot, int func)
395db5ef4fcSRafal Jaworowski {
396db5ef4fcSRafal Jaworowski 	bus_addr_t io_base, mem_base;
397db5ef4fcSRafal Jaworowski 	uint32_t io_limit, mem_limit;
398db5ef4fcSRafal Jaworowski 	int secbus;
399db5ef4fcSRafal Jaworowski 
400db5ef4fcSRafal Jaworowski 	io_base = sc->sc_io_base;
401db5ef4fcSRafal Jaworowski 	io_limit = io_base + sc->sc_io_size - 1;
402db5ef4fcSRafal Jaworowski 	mem_base = sc->sc_mem_base;
403db5ef4fcSRafal Jaworowski 	mem_limit = mem_base + sc->sc_mem_size - 1;
404db5ef4fcSRafal Jaworowski 
405db5ef4fcSRafal Jaworowski 	/* Configure I/O decode registers */
406db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEL_1,
407db5ef4fcSRafal Jaworowski 	    io_base >> 8, 1);
408db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEH_1,
409db5ef4fcSRafal Jaworowski 	    io_base >> 16, 2);
410db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITL_1,
411db5ef4fcSRafal Jaworowski 	    io_limit >> 8, 1);
412db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITH_1,
413db5ef4fcSRafal Jaworowski 	    io_limit >> 16, 2);
414db5ef4fcSRafal Jaworowski 
415db5ef4fcSRafal Jaworowski 	/* Configure memory decode registers */
416db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMBASE_1,
417db5ef4fcSRafal Jaworowski 	    mem_base >> 16, 2);
418db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMLIMIT_1,
419db5ef4fcSRafal Jaworowski 	    mem_limit >> 16, 2);
420db5ef4fcSRafal Jaworowski 
421db5ef4fcSRafal Jaworowski 	/* Disable memory prefetch decode */
422db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEL_1,
423db5ef4fcSRafal Jaworowski 	    0x10, 2);
424db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEH_1,
425db5ef4fcSRafal Jaworowski 	    0x0, 4);
426db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITL_1,
427db5ef4fcSRafal Jaworowski 	    0xF, 2);
428db5ef4fcSRafal Jaworowski 	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITH_1,
429db5ef4fcSRafal Jaworowski 	    0x0, 4);
430db5ef4fcSRafal Jaworowski 
431db5ef4fcSRafal Jaworowski 	secbus = mv_pcib_read_config(sc->sc_dev, bus, slot, func,
432db5ef4fcSRafal Jaworowski 	    PCIR_SECBUS_1, 1);
433db5ef4fcSRafal Jaworowski 
434db5ef4fcSRafal Jaworowski 	/* Configure buses behind the bridge */
435db5ef4fcSRafal Jaworowski 	mv_pcib_init(sc, secbus, PCI_SLOTMAX);
436db5ef4fcSRafal Jaworowski }
437db5ef4fcSRafal Jaworowski 
438db5ef4fcSRafal Jaworowski static int
439db5ef4fcSRafal Jaworowski mv_pcib_init(struct mv_pcib_softc *sc, int bus, int maxslot)
440db5ef4fcSRafal Jaworowski {
441db5ef4fcSRafal Jaworowski 	int slot, func, maxfunc, error;
442db5ef4fcSRafal Jaworowski 	uint8_t hdrtype, command, class, subclass;
443db5ef4fcSRafal Jaworowski 
444db5ef4fcSRafal Jaworowski 	for (slot = 0; slot <= maxslot; slot++) {
445db5ef4fcSRafal Jaworowski 		maxfunc = 0;
446db5ef4fcSRafal Jaworowski 		for (func = 0; func <= maxfunc; func++) {
447db5ef4fcSRafal Jaworowski 			hdrtype = mv_pcib_read_config(sc->sc_dev, bus, slot,
448db5ef4fcSRafal Jaworowski 			    func, PCIR_HDRTYPE, 1);
449db5ef4fcSRafal Jaworowski 
450db5ef4fcSRafal Jaworowski 			if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
451db5ef4fcSRafal Jaworowski 				continue;
452db5ef4fcSRafal Jaworowski 
453db5ef4fcSRafal Jaworowski 			if (func == 0 && (hdrtype & PCIM_MFDEV))
454db5ef4fcSRafal Jaworowski 				maxfunc = PCI_FUNCMAX;
455db5ef4fcSRafal Jaworowski 
456db5ef4fcSRafal Jaworowski 			command = mv_pcib_read_config(sc->sc_dev, bus, slot,
457db5ef4fcSRafal Jaworowski 			    func, PCIR_COMMAND, 1);
458db5ef4fcSRafal Jaworowski 			command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN);
459db5ef4fcSRafal Jaworowski 			mv_pcib_write_config(sc->sc_dev, bus, slot, func,
460db5ef4fcSRafal Jaworowski 			    PCIR_COMMAND, command, 1);
461db5ef4fcSRafal Jaworowski 
462db5ef4fcSRafal Jaworowski 			error = mv_pcib_init_all_bars(sc, bus, slot, func,
463db5ef4fcSRafal Jaworowski 			    hdrtype);
464db5ef4fcSRafal Jaworowski 
465db5ef4fcSRafal Jaworowski 			if (error)
466db5ef4fcSRafal Jaworowski 				return (error);
467db5ef4fcSRafal Jaworowski 
468db5ef4fcSRafal Jaworowski 			command |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN |
469db5ef4fcSRafal Jaworowski 			    PCIM_CMD_PORTEN;
470db5ef4fcSRafal Jaworowski 			mv_pcib_write_config(sc->sc_dev, bus, slot, func,
471db5ef4fcSRafal Jaworowski 			    PCIR_COMMAND, command, 1);
472db5ef4fcSRafal Jaworowski 
473db5ef4fcSRafal Jaworowski 			/* Handle PCI-PCI bridges */
474db5ef4fcSRafal Jaworowski 			class = mv_pcib_read_config(sc->sc_dev, bus, slot,
475db5ef4fcSRafal Jaworowski 			    func, PCIR_CLASS, 1);
476db5ef4fcSRafal Jaworowski 			subclass = mv_pcib_read_config(sc->sc_dev, bus, slot,
477db5ef4fcSRafal Jaworowski 			    func, PCIR_SUBCLASS, 1);
478db5ef4fcSRafal Jaworowski 
479db5ef4fcSRafal Jaworowski 			if (class != PCIC_BRIDGE ||
480db5ef4fcSRafal Jaworowski 			    subclass != PCIS_BRIDGE_PCI)
481db5ef4fcSRafal Jaworowski 				continue;
482db5ef4fcSRafal Jaworowski 
483db5ef4fcSRafal Jaworowski 			mv_pcib_init_bridge(sc, bus, slot, func);
484db5ef4fcSRafal Jaworowski 		}
485db5ef4fcSRafal Jaworowski 	}
486db5ef4fcSRafal Jaworowski 
487db5ef4fcSRafal Jaworowski 	/* Enable all ABCD interrupts */
488db5ef4fcSRafal Jaworowski 	pcib_write_irq_mask(sc, (0xF << 24));
489db5ef4fcSRafal Jaworowski 
490db5ef4fcSRafal Jaworowski 	return (0);
491db5ef4fcSRafal Jaworowski }
492db5ef4fcSRafal Jaworowski 
493db5ef4fcSRafal Jaworowski static int
494db5ef4fcSRafal Jaworowski mv_pcib_init_all_bars(struct mv_pcib_softc *sc, int bus, int slot,
495db5ef4fcSRafal Jaworowski     int func, int hdrtype)
496db5ef4fcSRafal Jaworowski {
497db5ef4fcSRafal Jaworowski 	int maxbar, bar, i;
498db5ef4fcSRafal Jaworowski 
499db5ef4fcSRafal Jaworowski 	maxbar = (hdrtype & PCIM_HDRTYPE) ? 0 : 6;
500db5ef4fcSRafal Jaworowski 	bar = 0;
501db5ef4fcSRafal Jaworowski 
502db5ef4fcSRafal Jaworowski 	/* Program the base address registers */
503db5ef4fcSRafal Jaworowski 	while (bar < maxbar) {
504db5ef4fcSRafal Jaworowski 		i = mv_pcib_init_bar(sc, bus, slot, func, bar);
505db5ef4fcSRafal Jaworowski 		bar += i;
506db5ef4fcSRafal Jaworowski 		if (i < 0) {
507db5ef4fcSRafal Jaworowski 			device_printf(sc->sc_dev,
508db5ef4fcSRafal Jaworowski 			    "PCI IO/Memory space exhausted\n");
509db5ef4fcSRafal Jaworowski 			return (ENOMEM);
510db5ef4fcSRafal Jaworowski 		}
511db5ef4fcSRafal Jaworowski 	}
512db5ef4fcSRafal Jaworowski 
513db5ef4fcSRafal Jaworowski 	return (0);
514db5ef4fcSRafal Jaworowski }
515db5ef4fcSRafal Jaworowski 
516db5ef4fcSRafal Jaworowski static struct resource *
517db5ef4fcSRafal Jaworowski mv_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
518db5ef4fcSRafal Jaworowski     u_long start, u_long end, u_long count, u_int flags)
519db5ef4fcSRafal Jaworowski {
520db5ef4fcSRafal Jaworowski 	struct mv_pcib_softc *sc = device_get_softc(dev);
521db5ef4fcSRafal Jaworowski 	struct rman *rm = NULL;
522db5ef4fcSRafal Jaworowski 	struct resource *res;
523db5ef4fcSRafal Jaworowski 
524db5ef4fcSRafal Jaworowski 	switch (type) {
525db5ef4fcSRafal Jaworowski 	case SYS_RES_IOPORT:
526db5ef4fcSRafal Jaworowski 		rm = &sc->sc_io_rman;
527db5ef4fcSRafal Jaworowski 		break;
528db5ef4fcSRafal Jaworowski 	case SYS_RES_MEMORY:
529db5ef4fcSRafal Jaworowski 		rm = &sc->sc_mem_rman;
530db5ef4fcSRafal Jaworowski 		break;
531db5ef4fcSRafal Jaworowski 	default:
532db5ef4fcSRafal Jaworowski 		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
533db5ef4fcSRafal Jaworowski 		    type, rid, start, end, count, flags));
534db5ef4fcSRafal Jaworowski 	};
535db5ef4fcSRafal Jaworowski 
536db5ef4fcSRafal Jaworowski 	res = rman_reserve_resource(rm, start, end, count, flags, child);
537db5ef4fcSRafal Jaworowski 	if (res == NULL)
538db5ef4fcSRafal Jaworowski 		return (NULL);
539db5ef4fcSRafal Jaworowski 
540db5ef4fcSRafal Jaworowski 	rman_set_rid(res, *rid);
541db5ef4fcSRafal Jaworowski 	rman_set_bustag(res, fdtbus_bs_tag);
542db5ef4fcSRafal Jaworowski 	rman_set_bushandle(res, start);
543db5ef4fcSRafal Jaworowski 
544db5ef4fcSRafal Jaworowski 	if (flags & RF_ACTIVE)
545db5ef4fcSRafal Jaworowski 		if (bus_activate_resource(child, type, *rid, res)) {
546db5ef4fcSRafal Jaworowski 			rman_release_resource(res);
547db5ef4fcSRafal Jaworowski 			return (NULL);
548db5ef4fcSRafal Jaworowski 		}
549db5ef4fcSRafal Jaworowski 
550db5ef4fcSRafal Jaworowski 	return (res);
551db5ef4fcSRafal Jaworowski }
552db5ef4fcSRafal Jaworowski 
553db5ef4fcSRafal Jaworowski static int
554db5ef4fcSRafal Jaworowski mv_pcib_release_resource(device_t dev, device_t child, int type, int rid,
555db5ef4fcSRafal Jaworowski     struct resource *res)
556db5ef4fcSRafal Jaworowski {
557db5ef4fcSRafal Jaworowski 
558db5ef4fcSRafal Jaworowski 	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY)
559db5ef4fcSRafal Jaworowski 		return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
560db5ef4fcSRafal Jaworowski 		    type, rid, res));
561db5ef4fcSRafal Jaworowski 
562db5ef4fcSRafal Jaworowski 	return (rman_release_resource(res));
563db5ef4fcSRafal Jaworowski }
564db5ef4fcSRafal Jaworowski 
565db5ef4fcSRafal Jaworowski static int
566db5ef4fcSRafal Jaworowski mv_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
567db5ef4fcSRafal Jaworowski {
568db5ef4fcSRafal Jaworowski 	struct mv_pcib_softc *sc = device_get_softc(dev);
569db5ef4fcSRafal Jaworowski 
570db5ef4fcSRafal Jaworowski 	switch (which) {
571db5ef4fcSRafal Jaworowski 	case PCIB_IVAR_BUS:
572db5ef4fcSRafal Jaworowski 		*result = sc->sc_busnr;
573db5ef4fcSRafal Jaworowski 		return (0);
574db5ef4fcSRafal Jaworowski 	case PCIB_IVAR_DOMAIN:
575db5ef4fcSRafal Jaworowski 		*result = device_get_unit(dev);
576db5ef4fcSRafal Jaworowski 		return (0);
577db5ef4fcSRafal Jaworowski 	}
578db5ef4fcSRafal Jaworowski 
579db5ef4fcSRafal Jaworowski 	return (ENOENT);
580db5ef4fcSRafal Jaworowski }
581db5ef4fcSRafal Jaworowski 
582db5ef4fcSRafal Jaworowski static int
583db5ef4fcSRafal Jaworowski mv_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
584db5ef4fcSRafal Jaworowski {
585db5ef4fcSRafal Jaworowski 	struct mv_pcib_softc *sc = device_get_softc(dev);
586db5ef4fcSRafal Jaworowski 
587db5ef4fcSRafal Jaworowski 	switch (which) {
588db5ef4fcSRafal Jaworowski 	case PCIB_IVAR_BUS:
589db5ef4fcSRafal Jaworowski 		sc->sc_busnr = value;
590db5ef4fcSRafal Jaworowski 		return (0);
591db5ef4fcSRafal Jaworowski 	}
592db5ef4fcSRafal Jaworowski 
593db5ef4fcSRafal Jaworowski 	return (ENOENT);
594db5ef4fcSRafal Jaworowski }
595db5ef4fcSRafal Jaworowski 
596db5ef4fcSRafal Jaworowski static inline void
597db5ef4fcSRafal Jaworowski pcib_write_irq_mask(struct mv_pcib_softc *sc, uint32_t mask)
598db5ef4fcSRafal Jaworowski {
599db5ef4fcSRafal Jaworowski 
600db5ef4fcSRafal Jaworowski 	if (!sc->sc_type != MV_TYPE_PCI)
601db5ef4fcSRafal Jaworowski 		return;
602db5ef4fcSRafal Jaworowski 
603db5ef4fcSRafal Jaworowski 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_IRQ_MASK, mask);
604db5ef4fcSRafal Jaworowski }
605db5ef4fcSRafal Jaworowski 
606db5ef4fcSRafal Jaworowski static void
607db5ef4fcSRafal Jaworowski mv_pcib_hw_cfginit(void)
6086975124cSRafal Jaworowski {
6096975124cSRafal Jaworowski 	static int opened = 0;
6106975124cSRafal Jaworowski 
6116975124cSRafal Jaworowski 	if (opened)
6126975124cSRafal Jaworowski 		return;
6136975124cSRafal Jaworowski 
6146975124cSRafal Jaworowski 	mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
6156975124cSRafal Jaworowski 	opened = 1;
6166975124cSRafal Jaworowski }
6176975124cSRafal Jaworowski 
6186975124cSRafal Jaworowski static uint32_t
619db5ef4fcSRafal Jaworowski mv_pcib_hw_cfgread(struct mv_pcib_softc *sc, u_int bus, u_int slot,
6206975124cSRafal Jaworowski     u_int func, u_int reg, int bytes)
6216975124cSRafal Jaworowski {
6226975124cSRafal Jaworowski 	uint32_t addr, data, ca, cd;
6236975124cSRafal Jaworowski 
624db5ef4fcSRafal Jaworowski 	ca = (sc->sc_type != MV_TYPE_PCI) ?
6256975124cSRafal Jaworowski 	    PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR;
626db5ef4fcSRafal Jaworowski 	cd = (sc->sc_type != MV_TYPE_PCI) ?
6276975124cSRafal Jaworowski 	    PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA;
6286975124cSRafal Jaworowski 	addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) |
6296975124cSRafal Jaworowski 	    PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg);
6306975124cSRafal Jaworowski 
6316975124cSRafal Jaworowski 	mtx_lock_spin(&pcicfg_mtx);
6326975124cSRafal Jaworowski 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr);
6336975124cSRafal Jaworowski 
6346975124cSRafal Jaworowski 	data = ~0;
6356975124cSRafal Jaworowski 	switch (bytes) {
6366975124cSRafal Jaworowski 	case 1:
6376975124cSRafal Jaworowski 		data = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
6386975124cSRafal Jaworowski 		    cd + (reg & 3));
6396975124cSRafal Jaworowski 		break;
6406975124cSRafal Jaworowski 	case 2:
6416975124cSRafal Jaworowski 		data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh,
6426975124cSRafal Jaworowski 		    cd + (reg & 2)));
6436975124cSRafal Jaworowski 		break;
6446975124cSRafal Jaworowski 	case 4:
6456975124cSRafal Jaworowski 		data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
6466975124cSRafal Jaworowski 		    cd));
6476975124cSRafal Jaworowski 		break;
6486975124cSRafal Jaworowski 	}
6496975124cSRafal Jaworowski 	mtx_unlock_spin(&pcicfg_mtx);
6506975124cSRafal Jaworowski 	return (data);
6516975124cSRafal Jaworowski }
6526975124cSRafal Jaworowski 
6536975124cSRafal Jaworowski static void
654db5ef4fcSRafal Jaworowski mv_pcib_hw_cfgwrite(struct mv_pcib_softc *sc, u_int bus, u_int slot,
6556975124cSRafal Jaworowski     u_int func, u_int reg, uint32_t data, int bytes)
6566975124cSRafal Jaworowski {
6576975124cSRafal Jaworowski 	uint32_t addr, ca, cd;
6586975124cSRafal Jaworowski 
659db5ef4fcSRafal Jaworowski 	ca = (sc->sc_type != MV_TYPE_PCI) ?
6606975124cSRafal Jaworowski 	    PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR;
661db5ef4fcSRafal Jaworowski 	cd = (sc->sc_type != MV_TYPE_PCI) ?
6626975124cSRafal Jaworowski 	    PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA;
6636975124cSRafal Jaworowski 	addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) |
6646975124cSRafal Jaworowski 	    PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg);
6656975124cSRafal Jaworowski 
6666975124cSRafal Jaworowski 	mtx_lock_spin(&pcicfg_mtx);
6676975124cSRafal Jaworowski 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr);
6686975124cSRafal Jaworowski 
6696975124cSRafal Jaworowski 	switch (bytes) {
6706975124cSRafal Jaworowski 	case 1:
6716975124cSRafal Jaworowski 		bus_space_write_1(sc->sc_bst, sc->sc_bsh,
6726975124cSRafal Jaworowski 		    cd + (reg & 3), data);
6736975124cSRafal Jaworowski 		break;
6746975124cSRafal Jaworowski 	case 2:
6756975124cSRafal Jaworowski 		bus_space_write_2(sc->sc_bst, sc->sc_bsh,
6766975124cSRafal Jaworowski 		    cd + (reg & 2), htole16(data));
6776975124cSRafal Jaworowski 		break;
6786975124cSRafal Jaworowski 	case 4:
6796975124cSRafal Jaworowski 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
6806975124cSRafal Jaworowski 		    cd, htole32(data));
6816975124cSRafal Jaworowski 		break;
6826975124cSRafal Jaworowski 	}
6836975124cSRafal Jaworowski 	mtx_unlock_spin(&pcicfg_mtx);
6846975124cSRafal Jaworowski }
6856975124cSRafal Jaworowski 
6866975124cSRafal Jaworowski static int
687db5ef4fcSRafal Jaworowski mv_pcib_maxslots(device_t dev)
6886975124cSRafal Jaworowski {
689db5ef4fcSRafal Jaworowski 	struct mv_pcib_softc *sc = device_get_softc(dev);
6906975124cSRafal Jaworowski 
691db5ef4fcSRafal Jaworowski 	return ((sc->sc_type != MV_TYPE_PCI) ? 1 : PCI_SLOTMAX);
6926975124cSRafal Jaworowski }
6936975124cSRafal Jaworowski 
6946975124cSRafal Jaworowski static uint32_t
695db5ef4fcSRafal Jaworowski mv_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
6966975124cSRafal Jaworowski     u_int reg, int bytes)
6976975124cSRafal Jaworowski {
698db5ef4fcSRafal Jaworowski 	struct mv_pcib_softc *sc = device_get_softc(dev);
6996975124cSRafal Jaworowski 
7006975124cSRafal Jaworowski 	/* Skip self */
7016975124cSRafal Jaworowski 	if (bus == sc->sc_busnr && slot == sc->sc_devnr)
7026975124cSRafal Jaworowski 		return (~0U);
7036975124cSRafal Jaworowski 
704db5ef4fcSRafal Jaworowski 	return (mv_pcib_hw_cfgread(sc, bus, slot, func, reg, bytes));
7056975124cSRafal Jaworowski }
7066975124cSRafal Jaworowski 
7076975124cSRafal Jaworowski static void
708db5ef4fcSRafal Jaworowski mv_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
7096975124cSRafal Jaworowski     u_int reg, uint32_t val, int bytes)
7106975124cSRafal Jaworowski {
711db5ef4fcSRafal Jaworowski 	struct mv_pcib_softc *sc = device_get_softc(dev);
7126975124cSRafal Jaworowski 
7136975124cSRafal Jaworowski 	/* Skip self */
7146975124cSRafal Jaworowski 	if (bus == sc->sc_busnr && slot == sc->sc_devnr)
7156975124cSRafal Jaworowski 		return;
7166975124cSRafal Jaworowski 
717db5ef4fcSRafal Jaworowski 	mv_pcib_hw_cfgwrite(sc, bus, slot, func, reg, val, bytes);
7186975124cSRafal Jaworowski }
7196975124cSRafal Jaworowski 
720db5ef4fcSRafal Jaworowski static int
721db5ef4fcSRafal Jaworowski mv_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
7226975124cSRafal Jaworowski {
723db5ef4fcSRafal Jaworowski 	struct mv_pcib_softc *sc;
724db5ef4fcSRafal Jaworowski 	int err, interrupt;
725db5ef4fcSRafal Jaworowski 
726db5ef4fcSRafal Jaworowski 	sc = device_get_softc(pcib);
727db5ef4fcSRafal Jaworowski 
728db5ef4fcSRafal Jaworowski 	err = fdt_pci_route_intr(pci_get_bus(dev), pci_get_slot(dev),
729db5ef4fcSRafal Jaworowski 	    pci_get_function(dev), pin, &sc->sc_intr_info, &interrupt);
730db5ef4fcSRafal Jaworowski 	if (err == 0)
731db5ef4fcSRafal Jaworowski 		return (interrupt);
732db5ef4fcSRafal Jaworowski 
733db5ef4fcSRafal Jaworowski 	device_printf(pcib, "could not route pin %d for device %d.%d\n",
734db5ef4fcSRafal Jaworowski 	    pin, pci_get_slot(dev), pci_get_function(dev));
735db5ef4fcSRafal Jaworowski 	return (PCI_INVALID_IRQ);
736db5ef4fcSRafal Jaworowski }
737db5ef4fcSRafal Jaworowski 
738db5ef4fcSRafal Jaworowski static int
739db5ef4fcSRafal Jaworowski mv_pcib_decode_win(phandle_t node, struct mv_pcib_softc *sc)
740db5ef4fcSRafal Jaworowski {
741db5ef4fcSRafal Jaworowski 	struct fdt_pci_range io_space, mem_space;
742db5ef4fcSRafal Jaworowski 	device_t dev;
7436975124cSRafal Jaworowski 	int error;
7446975124cSRafal Jaworowski 
745db5ef4fcSRafal Jaworowski 	dev = sc->sc_dev;
746db5ef4fcSRafal Jaworowski 
747db5ef4fcSRafal Jaworowski 	if ((error = fdt_pci_ranges(node, &io_space, &mem_space)) != 0) {
748db5ef4fcSRafal Jaworowski 		device_printf(dev, "could not retrieve 'ranges' data\n");
749db5ef4fcSRafal Jaworowski 		return (error);
750db5ef4fcSRafal Jaworowski 	}
751db5ef4fcSRafal Jaworowski 
7526975124cSRafal Jaworowski 	/* Configure CPU decoding windows */
753db5ef4fcSRafal Jaworowski 	error = decode_win_cpu_set(sc->sc_io_win_target,
754db5ef4fcSRafal Jaworowski 	    sc->sc_io_win_attr, io_space.base_parent, io_space.len, -1);
7556975124cSRafal Jaworowski 	if (error < 0) {
756db5ef4fcSRafal Jaworowski 		device_printf(dev, "could not set up CPU decode "
7576975124cSRafal Jaworowski 		    "window for PCI IO\n");
758db5ef4fcSRafal Jaworowski 		return (ENXIO);
7596975124cSRafal Jaworowski 	}
760db5ef4fcSRafal Jaworowski 	error = decode_win_cpu_set(sc->sc_mem_win_target,
761db5ef4fcSRafal Jaworowski 	    sc->sc_mem_win_attr, mem_space.base_parent, mem_space.len, -1);
7626975124cSRafal Jaworowski 	if (error < 0) {
763db5ef4fcSRafal Jaworowski 		device_printf(dev, "could not set up CPU decode "
7646975124cSRafal Jaworowski 		    "windows for PCI MEM\n");
765db5ef4fcSRafal Jaworowski 		return (ENXIO);
7666975124cSRafal Jaworowski 	}
7676975124cSRafal Jaworowski 
768db5ef4fcSRafal Jaworowski 	sc->sc_io_base = io_space.base_parent;
769db5ef4fcSRafal Jaworowski 	sc->sc_io_size = io_space.len;
770db5ef4fcSRafal Jaworowski 
771db5ef4fcSRafal Jaworowski 	sc->sc_mem_base = mem_space.base_parent;
772db5ef4fcSRafal Jaworowski 	sc->sc_mem_size = mem_space.len;
773db5ef4fcSRafal Jaworowski 
774db5ef4fcSRafal Jaworowski 	return (0);
7756975124cSRafal Jaworowski }
7766975124cSRafal Jaworowski 
777db5ef4fcSRafal Jaworowski static int
778db5ef4fcSRafal Jaworowski mv_pcib_intr_info(phandle_t node, struct mv_pcib_softc *sc)
7796975124cSRafal Jaworowski {
780db5ef4fcSRafal Jaworowski 	int error;
7816975124cSRafal Jaworowski 
782db5ef4fcSRafal Jaworowski 	if ((error = fdt_pci_intr_info(node, &sc->sc_intr_info)) != 0)
783db5ef4fcSRafal Jaworowski 		return (error);
7846975124cSRafal Jaworowski 
785db5ef4fcSRafal Jaworowski 	return (0);
7866975124cSRafal Jaworowski }
7876975124cSRafal Jaworowski 
788db5ef4fcSRafal Jaworowski #if 0
7896975124cSRafal Jaworowski 		control = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
7906975124cSRafal Jaworowski 		    PCIE_REG_CONTROL);
7916975124cSRafal Jaworowski 
7926975124cSRafal Jaworowski 		/*
7936975124cSRafal Jaworowski 		 * If this PCI-E port (controller) is configured (by the
7946975124cSRafal Jaworowski 		 * underlying firmware) with lane width other than 1x, there
7956975124cSRafal Jaworowski 		 * are auxiliary resources defined for aggregating more width
7966975124cSRafal Jaworowski 		 * on our lane. Skip all such entries as they are not
7976975124cSRafal Jaworowski 		 * standalone ports and must not have a device object
7986975124cSRafal Jaworowski 		 * instantiated.
7996975124cSRafal Jaworowski 		 */
8006975124cSRafal Jaworowski 		if ((control & PCIE_CTRL_LINK1X) == 0)
8016975124cSRafal Jaworowski 			while (info->op_base &&
8026975124cSRafal Jaworowski 			    info->op_type == MV_TYPE_PCIE_AGGR_LANE)
8036975124cSRafal Jaworowski 				info++;
8046975124cSRafal Jaworowski 
805db5ef4fcSRafal Jaworowski 		mv_pcib_add_child(driver, parent, sc);
806db5ef4fcSRafal Jaworowski #endif
807