mv_pci.c revision 260327
1185089Sraj/*-
2209131Sraj * Copyright (c) 2008 MARVELL INTERNATIONAL LTD.
3209131Sraj * Copyright (c) 2010 The FreeBSD Foundation
4240489Sgber * Copyright (c) 2010-2012 Semihalf
5185089Sraj * All rights reserved.
6185089Sraj *
7185089Sraj * Developed by Semihalf.
8185089Sraj *
9209131Sraj * Portions of this software were developed by Semihalf
10209131Sraj * under sponsorship from the FreeBSD Foundation.
11209131Sraj *
12185089Sraj * Redistribution and use in source and binary forms, with or without
13185089Sraj * modification, are permitted provided that the following conditions
14185089Sraj * are met:
15185089Sraj * 1. Redistributions of source code must retain the above copyright
16185089Sraj *    notice, this list of conditions and the following disclaimer.
17185089Sraj * 2. Redistributions in binary form must reproduce the above copyright
18185089Sraj *    notice, this list of conditions and the following disclaimer in the
19185089Sraj *    documentation and/or other materials provided with the distribution.
20185089Sraj * 3. Neither the name of MARVELL nor the names of contributors
21185089Sraj *    may be used to endorse or promote products derived from this software
22185089Sraj *    without specific prior written permission.
23185089Sraj *
24185089Sraj * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25185089Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26185089Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27185089Sraj * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
28185089Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29185089Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30185089Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31185089Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32185089Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33185089Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34185089Sraj * SUCH DAMAGE.
35185089Sraj */
36185089Sraj
37185089Sraj/*
38185089Sraj * Marvell integrated PCI/PCI-Express controller driver.
39185089Sraj */
40185089Sraj
41185089Sraj#include <sys/cdefs.h>
42185089Sraj__FBSDID("$FreeBSD: head/sys/arm/mv/mv_pci.c 260327 2014-01-05 18:46:58Z nwhitehorn $");
43185089Sraj
44185089Sraj#include <sys/param.h>
45185089Sraj#include <sys/systm.h>
46185089Sraj#include <sys/kernel.h>
47185089Sraj#include <sys/lock.h>
48185089Sraj#include <sys/malloc.h>
49185089Sraj#include <sys/module.h>
50185089Sraj#include <sys/mutex.h>
51185089Sraj#include <sys/queue.h>
52185089Sraj#include <sys/bus.h>
53185089Sraj#include <sys/rman.h>
54185089Sraj#include <sys/endian.h>
55185089Sraj
56260327Snwhitehorn#include <machine/fdt.h>
57240493Sgber#include <machine/intr.h>
58240493Sgber
59185089Sraj#include <vm/vm.h>
60185089Sraj#include <vm/pmap.h>
61185089Sraj
62209131Sraj#include <dev/fdt/fdt_common.h>
63209131Sraj#include <dev/ofw/ofw_bus.h>
64259484Snwhitehorn#include <dev/ofw/ofw_pci.h>
65209131Sraj#include <dev/ofw/ofw_bus_subr.h>
66185089Sraj#include <dev/pci/pcivar.h>
67185089Sraj#include <dev/pci/pcireg.h>
68185089Sraj#include <dev/pci/pcib_private.h>
69185089Sraj
70209131Sraj#include "ofw_bus_if.h"
71185089Sraj#include "pcib_if.h"
72185089Sraj
73185089Sraj#include <machine/resource.h>
74185089Sraj#include <machine/bus.h>
75185089Sraj
76185089Sraj#include <arm/mv/mvreg.h>
77185089Sraj#include <arm/mv/mvvar.h>
78209131Sraj#include <arm/mv/mvwin.h>
79185089Sraj
80240493Sgber#ifdef DEBUG
81240493Sgber#define debugf(fmt, args...) do { printf(fmt,##args); } while (0)
82240493Sgber#else
83240493Sgber#define debugf(fmt, args...)
84240493Sgber#endif
85240493Sgber
86258780Seadler#define PCI_CFG_ENA		(1U << 31)
87185089Sraj#define PCI_CFG_BUS(bus)	(((bus) & 0xff) << 16)
88185089Sraj#define PCI_CFG_DEV(dev)	(((dev) & 0x1f) << 11)
89185089Sraj#define PCI_CFG_FUN(fun)	(((fun) & 0x7) << 8)
90185089Sraj#define PCI_CFG_PCIE_REG(reg)	((reg) & 0xfc)
91185089Sraj
92185089Sraj#define PCI_REG_CFG_ADDR	0x0C78
93185089Sraj#define PCI_REG_CFG_DATA	0x0C7C
94185089Sraj
95185089Sraj#define PCIE_REG_CFG_ADDR	0x18F8
96185089Sraj#define PCIE_REG_CFG_DATA	0x18FC
97185089Sraj#define PCIE_REG_CONTROL	0x1A00
98185089Sraj#define   PCIE_CTRL_LINK1X	0x00000001
99185089Sraj#define PCIE_REG_STATUS		0x1A04
100185089Sraj#define PCIE_REG_IRQ_MASK	0x1910
101185089Sraj
102240489Sgber#define PCIE_CONTROL_ROOT_CMPLX	(1 << 1)
103240489Sgber#define PCIE_CONTROL_HOT_RESET	(1 << 24)
104185089Sraj
105240489Sgber#define PCIE_LINK_TIMEOUT	1000000
106185089Sraj
107240489Sgber#define PCIE_STATUS_LINK_DOWN	1
108240489Sgber#define PCIE_STATUS_DEV_OFFS	16
109185089Sraj
110240489Sgber/* Minimum PCI Memory and I/O allocations taken from PCI spec (in bytes) */
111240489Sgber#define PCI_MIN_IO_ALLOC	4
112240489Sgber#define PCI_MIN_MEM_ALLOC	16
113240489Sgber
114240489Sgber#define BITS_PER_UINT32		(NBBY * sizeof(uint32_t))
115240489Sgber
116209131Srajstruct mv_pcib_softc {
117185089Sraj	device_t	sc_dev;
118185089Sraj
119209131Sraj	struct rman	sc_mem_rman;
120209131Sraj	bus_addr_t	sc_mem_base;
121209131Sraj	bus_addr_t	sc_mem_size;
122240489Sgber	uint32_t	sc_mem_map[MV_PCI_MEM_SLICE_SIZE /
123240489Sgber	    (PCI_MIN_MEM_ALLOC * BITS_PER_UINT32)];
124240489Sgber	int		sc_win_target;
125209131Sraj	int		sc_mem_win_attr;
126185089Sraj
127209131Sraj	struct rman	sc_io_rman;
128209131Sraj	bus_addr_t	sc_io_base;
129209131Sraj	bus_addr_t	sc_io_size;
130240489Sgber	uint32_t	sc_io_map[MV_PCI_IO_SLICE_SIZE /
131240489Sgber	    (PCI_MIN_IO_ALLOC * BITS_PER_UINT32)];
132209131Sraj	int		sc_io_win_attr;
133185089Sraj
134185089Sraj	struct resource	*sc_res;
135185089Sraj	bus_space_handle_t sc_bsh;
136185089Sraj	bus_space_tag_t	sc_bst;
137185089Sraj	int		sc_rid;
138185089Sraj
139240493Sgber	struct mtx	sc_msi_mtx;
140240493Sgber	uint32_t	sc_msi_bitmap;
141240493Sgber
142185089Sraj	int		sc_busnr;		/* Host bridge bus number */
143185089Sraj	int		sc_devnr;		/* Host bridge device number */
144209131Sraj	int		sc_type;
145240489Sgber	int		sc_mode;		/* Endpoint / Root Complex */
146185089Sraj
147259484Snwhitehorn	struct ofw_bus_iinfo	sc_pci_iinfo;
148185089Sraj};
149185089Sraj
150209131Sraj/* Local forward prototypes */
151209131Srajstatic int mv_pcib_decode_win(phandle_t, struct mv_pcib_softc *);
152209131Srajstatic void mv_pcib_hw_cfginit(void);
153209131Srajstatic uint32_t mv_pcib_hw_cfgread(struct mv_pcib_softc *, u_int, u_int,
154209131Sraj    u_int, u_int, int);
155209131Srajstatic void mv_pcib_hw_cfgwrite(struct mv_pcib_softc *, u_int, u_int,
156209131Sraj    u_int, u_int, uint32_t, int);
157209131Srajstatic int mv_pcib_init(struct mv_pcib_softc *, int, int);
158209131Srajstatic int mv_pcib_init_all_bars(struct mv_pcib_softc *, int, int, int, int);
159209131Srajstatic void mv_pcib_init_bridge(struct mv_pcib_softc *, int, int, int);
160209131Srajstatic inline void pcib_write_irq_mask(struct mv_pcib_softc *, uint32_t);
161240489Sgberstatic void mv_pcib_enable(struct mv_pcib_softc *, uint32_t);
162240489Sgberstatic int mv_pcib_mem_init(struct mv_pcib_softc *);
163185089Sraj
164209131Sraj/* Forward prototypes */
165209131Srajstatic int mv_pcib_probe(device_t);
166209131Srajstatic int mv_pcib_attach(device_t);
167209131Sraj
168209131Srajstatic struct resource *mv_pcib_alloc_resource(device_t, device_t, int, int *,
169185089Sraj    u_long, u_long, u_long, u_int);
170209131Srajstatic int mv_pcib_release_resource(device_t, device_t, int, int,
171185089Sraj    struct resource *);
172209131Srajstatic int mv_pcib_read_ivar(device_t, device_t, int, uintptr_t *);
173209131Srajstatic int mv_pcib_write_ivar(device_t, device_t, int, uintptr_t);
174185089Sraj
175209131Srajstatic int mv_pcib_maxslots(device_t);
176209131Srajstatic uint32_t mv_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int);
177209131Srajstatic void mv_pcib_write_config(device_t, u_int, u_int, u_int, u_int,
178185089Sraj    uint32_t, int);
179209131Srajstatic int mv_pcib_route_interrupt(device_t, device_t, int);
180240493Sgber#if defined(SOC_MV_ARMADAXP)
181240493Sgberstatic int mv_pcib_alloc_msi(device_t, device_t, int, int, int *);
182240493Sgberstatic int mv_pcib_map_msi(device_t, device_t, int, uint64_t *, uint32_t *);
183240493Sgberstatic int mv_pcib_release_msi(device_t, device_t, int, int *);
184240493Sgber#endif
185185089Sraj
186185089Sraj/*
187185089Sraj * Bus interface definitions.
188185089Sraj */
189209131Srajstatic device_method_t mv_pcib_methods[] = {
190185089Sraj	/* Device interface */
191209131Sraj	DEVMETHOD(device_probe,			mv_pcib_probe),
192209131Sraj	DEVMETHOD(device_attach,		mv_pcib_attach),
193185089Sraj
194185089Sraj	/* Bus interface */
195209131Sraj	DEVMETHOD(bus_read_ivar,		mv_pcib_read_ivar),
196209131Sraj	DEVMETHOD(bus_write_ivar,		mv_pcib_write_ivar),
197209131Sraj	DEVMETHOD(bus_alloc_resource,		mv_pcib_alloc_resource),
198209131Sraj	DEVMETHOD(bus_release_resource,		mv_pcib_release_resource),
199185089Sraj	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
200185089Sraj	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
201185089Sraj	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
202185089Sraj	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
203185089Sraj
204185089Sraj	/* pcib interface */
205209131Sraj	DEVMETHOD(pcib_maxslots,		mv_pcib_maxslots),
206209131Sraj	DEVMETHOD(pcib_read_config,		mv_pcib_read_config),
207209131Sraj	DEVMETHOD(pcib_write_config,		mv_pcib_write_config),
208209131Sraj	DEVMETHOD(pcib_route_interrupt,		mv_pcib_route_interrupt),
209240493Sgber
210240493Sgber#if defined(SOC_MV_ARMADAXP)
211240493Sgber	DEVMETHOD(pcib_alloc_msi,		mv_pcib_alloc_msi),
212240493Sgber	DEVMETHOD(pcib_release_msi,		mv_pcib_release_msi),
213240493Sgber	DEVMETHOD(pcib_map_msi,			mv_pcib_map_msi),
214240493Sgber#endif
215240493Sgber
216209131Sraj	/* OFW bus interface */
217209131Sraj	DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
218209131Sraj	DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
219209131Sraj	DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
220209131Sraj	DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
221209131Sraj	DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
222209131Sraj
223227843Smarius	DEVMETHOD_END
224185089Sraj};
225185089Sraj
226209131Srajstatic driver_t mv_pcib_driver = {
227185089Sraj	"pcib",
228209131Sraj	mv_pcib_methods,
229209131Sraj	sizeof(struct mv_pcib_softc),
230185089Sraj};
231185089Sraj
232185089Srajdevclass_t pcib_devclass;
233185089Sraj
234257702SnwhitehornDRIVER_MODULE(pcib, nexus, mv_pcib_driver, pcib_devclass, 0, 0);
235185089Sraj
236185089Srajstatic struct mtx pcicfg_mtx;
237185089Sraj
238185089Srajstatic int
239209131Srajmv_pcib_probe(device_t self)
240185089Sraj{
241218228Smarcel	phandle_t node;
242185089Sraj
243218228Smarcel	node = ofw_bus_get_node(self);
244218228Smarcel	if (!fdt_is_type(node, "pci"))
245209131Sraj		return (ENXIO);
246218228Smarcel
247259484Snwhitehorn	if (!(ofw_bus_is_compatible(self, "mrvl,pcie") ||
248259484Snwhitehorn	    ofw_bus_is_compatible(self, "mrvl,pci")))
249209131Sraj		return (ENXIO);
250185089Sraj
251209131Sraj	device_set_desc(self, "Marvell Integrated PCI/PCI-E Controller");
252209131Sraj	return (BUS_PROBE_DEFAULT);
253185089Sraj}
254185089Sraj
255185089Srajstatic int
256209131Srajmv_pcib_attach(device_t self)
257185089Sraj{
258209131Sraj	struct mv_pcib_softc *sc;
259209131Sraj	phandle_t node, parnode;
260240489Sgber	uint32_t val, unit;
261209131Sraj	int err;
262185089Sraj
263185089Sraj	sc = device_get_softc(self);
264209131Sraj	sc->sc_dev = self;
265240489Sgber	unit = fdt_get_unit(self);
266185089Sraj
267240489Sgber
268218228Smarcel	node = ofw_bus_get_node(self);
269218228Smarcel	parnode = OF_parent(node);
270218228Smarcel	if (fdt_is_compatible(node, "mrvl,pcie")) {
271209131Sraj		sc->sc_type = MV_TYPE_PCIE;
272240489Sgber		sc->sc_win_target = MV_WIN_PCIE_TARGET(unit);
273240489Sgber		sc->sc_mem_win_attr = MV_WIN_PCIE_MEM_ATTR(unit);
274240489Sgber		sc->sc_io_win_attr = MV_WIN_PCIE_IO_ATTR(unit);
275218228Smarcel	} else if (fdt_is_compatible(node, "mrvl,pci")) {
276209131Sraj		sc->sc_type = MV_TYPE_PCI;
277240489Sgber		sc->sc_win_target = MV_WIN_PCI_TARGET;
278209131Sraj		sc->sc_mem_win_attr = MV_WIN_PCI_MEM_ATTR;
279209131Sraj		sc->sc_io_win_attr = MV_WIN_PCI_IO_ATTR;
280209131Sraj	} else
281185089Sraj		return (ENXIO);
282185089Sraj
283209131Sraj	/*
284209131Sraj	 * Retrieve our mem-mapped registers range.
285209131Sraj	 */
286185089Sraj	sc->sc_rid = 0;
287185089Sraj	sc->sc_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &sc->sc_rid,
288185089Sraj	    RF_ACTIVE);
289185089Sraj	if (sc->sc_res == NULL) {
290209131Sraj		device_printf(self, "could not map memory\n");
291185089Sraj		return (ENXIO);
292185089Sraj	}
293185089Sraj	sc->sc_bst = rman_get_bustag(sc->sc_res);
294185089Sraj	sc->sc_bsh = rman_get_bushandle(sc->sc_res);
295185089Sraj
296240489Sgber	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_CONTROL);
297240489Sgber	sc->sc_mode = (val & PCIE_CONTROL_ROOT_CMPLX ? MV_MODE_ROOT :
298240489Sgber	    MV_MODE_ENDPOINT);
299240489Sgber
300209131Sraj	/*
301240489Sgber	 * Get PCI interrupt info.
302240489Sgber	 */
303259484Snwhitehorn	if (sc->sc_mode == MV_MODE_ROOT)
304259484Snwhitehorn		ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(pcell_t));
305240489Sgber
306240489Sgber	/*
307209131Sraj	 * Configure decode windows for PCI(E) access.
308209131Sraj	 */
309209131Sraj	if (mv_pcib_decode_win(node, sc) != 0)
310209131Sraj		return (ENXIO);
311209131Sraj
312209131Sraj	mv_pcib_hw_cfginit();
313209131Sraj
314209131Sraj	/*
315240489Sgber	 * Enable PCIE device.
316209131Sraj	 */
317240489Sgber	mv_pcib_enable(sc, unit);
318185089Sraj
319240489Sgber	/*
320240489Sgber	 * Memory management.
321240489Sgber	 */
322240489Sgber	err = mv_pcib_mem_init(sc);
323240489Sgber	if (err)
324240489Sgber		return (err);
325185089Sraj
326240489Sgber	if (sc->sc_mode == MV_MODE_ROOT) {
327240489Sgber		err = mv_pcib_init(sc, sc->sc_busnr,
328240489Sgber		    mv_pcib_maxslots(sc->sc_dev));
329240489Sgber		if (err)
330240489Sgber			goto error;
331240489Sgber
332240489Sgber		device_add_child(self, "pci", -1);
333240489Sgber	} else {
334240489Sgber		sc->sc_devnr = 1;
335240489Sgber		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
336240489Sgber		    PCIE_REG_STATUS, 1 << PCIE_STATUS_DEV_OFFS);
337240489Sgber		device_add_child(self, "pci_ep", -1);
338240489Sgber	}
339240489Sgber
340240493Sgber	mtx_init(&sc->sc_msi_mtx, "msi_mtx", NULL, MTX_DEF);
341240489Sgber	return (bus_generic_attach(self));
342240489Sgber
343240489Sgbererror:
344240489Sgber	/* XXX SYS_RES_ should be released here */
345240489Sgber	rman_fini(&sc->sc_mem_rman);
346240489Sgber	rman_fini(&sc->sc_io_rman);
347240489Sgber
348240489Sgber	return (err);
349240489Sgber}
350240489Sgber
351240489Sgberstatic void
352240489Sgbermv_pcib_enable(struct mv_pcib_softc *sc, uint32_t unit)
353240489Sgber{
354240489Sgber	uint32_t val;
355240489Sgber#if !defined(SOC_MV_ARMADAXP)
356240489Sgber	int timeout;
357240489Sgber
358240489Sgber	/*
359240489Sgber	 * Check if PCIE device is enabled.
360240489Sgber	 */
361240489Sgber	if (read_cpu_ctrl(CPU_CONTROL) & CPU_CONTROL_PCIE_DISABLE(unit)) {
362240489Sgber		write_cpu_ctrl(CPU_CONTROL, read_cpu_ctrl(CPU_CONTROL) &
363240489Sgber		    ~(CPU_CONTROL_PCIE_DISABLE(unit)));
364240489Sgber
365240489Sgber		timeout = PCIE_LINK_TIMEOUT;
366240489Sgber		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
367240489Sgber		    PCIE_REG_STATUS);
368240489Sgber		while (((val & PCIE_STATUS_LINK_DOWN) == 1) && (timeout > 0)) {
369240489Sgber			DELAY(1000);
370240489Sgber			timeout -= 1000;
371240489Sgber			val = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
372240489Sgber			    PCIE_REG_STATUS);
373240489Sgber		}
374240489Sgber	}
375240489Sgber#endif
376240489Sgber
377240489Sgber
378240489Sgber	if (sc->sc_mode == MV_MODE_ROOT) {
379240489Sgber		/*
380240489Sgber		 * Enable PCI bridge.
381240489Sgber		 */
382240489Sgber		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIR_COMMAND);
383240489Sgber		val |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN |
384240489Sgber		    PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
385240489Sgber		bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIR_COMMAND, val);
386240489Sgber	}
387240489Sgber}
388240489Sgber
389240489Sgberstatic int
390240489Sgbermv_pcib_mem_init(struct mv_pcib_softc *sc)
391240489Sgber{
392240489Sgber	int err;
393240489Sgber
394240489Sgber	/*
395240489Sgber	 * Memory management.
396240489Sgber	 */
397209131Sraj	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
398209131Sraj	err = rman_init(&sc->sc_mem_rman);
399186932Sraj	if (err)
400186932Sraj		return (err);
401186932Sraj
402209131Sraj	sc->sc_io_rman.rm_type = RMAN_ARRAY;
403209131Sraj	err = rman_init(&sc->sc_io_rman);
404186932Sraj	if (err) {
405209131Sraj		rman_fini(&sc->sc_mem_rman);
406186932Sraj		return (err);
407186932Sraj	}
408186932Sraj
409209131Sraj	err = rman_manage_region(&sc->sc_mem_rman, sc->sc_mem_base,
410209131Sraj	    sc->sc_mem_base + sc->sc_mem_size - 1);
411186932Sraj	if (err)
412186932Sraj		goto error;
413186932Sraj
414209131Sraj	err = rman_manage_region(&sc->sc_io_rman, sc->sc_io_base,
415209131Sraj	    sc->sc_io_base + sc->sc_io_size - 1);
416186932Sraj	if (err)
417186932Sraj		goto error;
418186932Sraj
419240489Sgber	return (0);
420185089Sraj
421186932Srajerror:
422209131Sraj	rman_fini(&sc->sc_mem_rman);
423209131Sraj	rman_fini(&sc->sc_io_rman);
424240489Sgber
425186932Sraj	return (err);
426185089Sraj}
427185089Sraj
428240489Sgberstatic inline uint32_t
429240489Sgberpcib_bit_get(uint32_t *map, uint32_t bit)
430240489Sgber{
431240489Sgber	uint32_t n = bit / BITS_PER_UINT32;
432240489Sgber
433240489Sgber	bit = bit % BITS_PER_UINT32;
434240489Sgber	return (map[n] & (1 << bit));
435240489Sgber}
436240489Sgber
437240489Sgberstatic inline void
438240489Sgberpcib_bit_set(uint32_t *map, uint32_t bit)
439240489Sgber{
440240489Sgber	uint32_t n = bit / BITS_PER_UINT32;
441240489Sgber
442240489Sgber	bit = bit % BITS_PER_UINT32;
443240489Sgber	map[n] |= (1 << bit);
444240489Sgber}
445240489Sgber
446240489Sgberstatic inline uint32_t
447240489Sgberpcib_map_check(uint32_t *map, uint32_t start, uint32_t bits)
448240489Sgber{
449240489Sgber	uint32_t i;
450240489Sgber
451240489Sgber	for (i = start; i < start + bits; i++)
452240489Sgber		if (pcib_bit_get(map, i))
453240489Sgber			return (0);
454240489Sgber
455240489Sgber	return (1);
456240489Sgber}
457240489Sgber
458240489Sgberstatic inline void
459240489Sgberpcib_map_set(uint32_t *map, uint32_t start, uint32_t bits)
460240489Sgber{
461240489Sgber	uint32_t i;
462240489Sgber
463240489Sgber	for (i = start; i < start + bits; i++)
464240489Sgber		pcib_bit_set(map, i);
465240489Sgber}
466240489Sgber
467240489Sgber/*
468240489Sgber * The idea of this allocator is taken from ARM No-Cache memory
469240489Sgber * management code (sys/arm/arm/vm_machdep.c).
470240489Sgber */
471240489Sgberstatic bus_addr_t
472240489Sgberpcib_alloc(struct mv_pcib_softc *sc, uint32_t smask)
473240489Sgber{
474240489Sgber	uint32_t bits, bits_limit, i, *map, min_alloc, size;
475240489Sgber	bus_addr_t addr = 0;
476240489Sgber	bus_addr_t base;
477240489Sgber
478240489Sgber	if (smask & 1) {
479240489Sgber		base = sc->sc_io_base;
480240489Sgber		min_alloc = PCI_MIN_IO_ALLOC;
481240489Sgber		bits_limit = sc->sc_io_size / min_alloc;
482240489Sgber		map = sc->sc_io_map;
483240489Sgber		smask &= ~0x3;
484240489Sgber	} else {
485240489Sgber		base = sc->sc_mem_base;
486240489Sgber		min_alloc = PCI_MIN_MEM_ALLOC;
487240489Sgber		bits_limit = sc->sc_mem_size / min_alloc;
488240489Sgber		map = sc->sc_mem_map;
489240489Sgber		smask &= ~0xF;
490240489Sgber	}
491240489Sgber
492240489Sgber	size = ~smask + 1;
493240489Sgber	bits = size / min_alloc;
494240489Sgber
495240489Sgber	for (i = 0; i + bits <= bits_limit; i += bits)
496240489Sgber		if (pcib_map_check(map, i, bits)) {
497240489Sgber			pcib_map_set(map, i, bits);
498240489Sgber			addr = base + (i * min_alloc);
499240489Sgber			return (addr);
500240489Sgber		}
501240489Sgber
502240489Sgber	return (addr);
503240489Sgber}
504240489Sgber
505185089Srajstatic int
506209131Srajmv_pcib_init_bar(struct mv_pcib_softc *sc, int bus, int slot, int func,
507185089Sraj    int barno)
508185089Sraj{
509240489Sgber	uint32_t addr, bar;
510185089Sraj	int reg, width;
511185089Sraj
512185089Sraj	reg = PCIR_BAR(barno);
513240489Sgber
514240489Sgber	/*
515240489Sgber	 * Need to init the BAR register with 0xffffffff before correct
516240489Sgber	 * value can be read.
517240489Sgber	 */
518240489Sgber	mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4);
519209131Sraj	bar = mv_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4);
520185089Sraj	if (bar == 0)
521185089Sraj		return (1);
522185089Sraj
523185089Sraj	/* Calculate BAR size: 64 or 32 bit (in 32-bit units) */
524185089Sraj	width = ((bar & 7) == 4) ? 2 : 1;
525185089Sraj
526240489Sgber	addr = pcib_alloc(sc, bar);
527240489Sgber	if (!addr)
528185089Sraj		return (-1);
529185089Sraj
530185089Sraj	if (bootverbose)
531240489Sgber		printf("PCI %u:%u:%u: reg %x: smask=%08x: addr=%08x\n",
532240489Sgber		    bus, slot, func, reg, bar, addr);
533185089Sraj
534209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4);
535185089Sraj	if (width == 2)
536209131Sraj		mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg + 4,
537185089Sraj		    0, 4);
538185089Sraj
539185089Sraj	return (width);
540185089Sraj}
541185089Sraj
542185089Srajstatic void
543209131Srajmv_pcib_init_bridge(struct mv_pcib_softc *sc, int bus, int slot, int func)
544185089Sraj{
545185089Sraj	bus_addr_t io_base, mem_base;
546185089Sraj	uint32_t io_limit, mem_limit;
547185089Sraj	int secbus;
548185089Sraj
549209131Sraj	io_base = sc->sc_io_base;
550209131Sraj	io_limit = io_base + sc->sc_io_size - 1;
551209131Sraj	mem_base = sc->sc_mem_base;
552209131Sraj	mem_limit = mem_base + sc->sc_mem_size - 1;
553185089Sraj
554185089Sraj	/* Configure I/O decode registers */
555209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEL_1,
556185639Sraj	    io_base >> 8, 1);
557209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEH_1,
558185639Sraj	    io_base >> 16, 2);
559209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITL_1,
560185089Sraj	    io_limit >> 8, 1);
561209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITH_1,
562185089Sraj	    io_limit >> 16, 2);
563185089Sraj
564185089Sraj	/* Configure memory decode registers */
565209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMBASE_1,
566185089Sraj	    mem_base >> 16, 2);
567209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMLIMIT_1,
568185089Sraj	    mem_limit >> 16, 2);
569185089Sraj
570185089Sraj	/* Disable memory prefetch decode */
571209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEL_1,
572185089Sraj	    0x10, 2);
573209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEH_1,
574185089Sraj	    0x0, 4);
575209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITL_1,
576185089Sraj	    0xF, 2);
577209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITH_1,
578185089Sraj	    0x0, 4);
579185089Sraj
580209131Sraj	secbus = mv_pcib_read_config(sc->sc_dev, bus, slot, func,
581185089Sraj	    PCIR_SECBUS_1, 1);
582185089Sraj
583185089Sraj	/* Configure buses behind the bridge */
584209131Sraj	mv_pcib_init(sc, secbus, PCI_SLOTMAX);
585185089Sraj}
586185089Sraj
587185089Srajstatic int
588209131Srajmv_pcib_init(struct mv_pcib_softc *sc, int bus, int maxslot)
589185089Sraj{
590185089Sraj	int slot, func, maxfunc, error;
591185089Sraj	uint8_t hdrtype, command, class, subclass;
592185089Sraj
593185089Sraj	for (slot = 0; slot <= maxslot; slot++) {
594185089Sraj		maxfunc = 0;
595185089Sraj		for (func = 0; func <= maxfunc; func++) {
596209131Sraj			hdrtype = mv_pcib_read_config(sc->sc_dev, bus, slot,
597185089Sraj			    func, PCIR_HDRTYPE, 1);
598185089Sraj
599185089Sraj			if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
600185089Sraj				continue;
601185089Sraj
602185089Sraj			if (func == 0 && (hdrtype & PCIM_MFDEV))
603185089Sraj				maxfunc = PCI_FUNCMAX;
604185089Sraj
605209131Sraj			command = mv_pcib_read_config(sc->sc_dev, bus, slot,
606185089Sraj			    func, PCIR_COMMAND, 1);
607185089Sraj			command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN);
608209131Sraj			mv_pcib_write_config(sc->sc_dev, bus, slot, func,
609185089Sraj			    PCIR_COMMAND, command, 1);
610185089Sraj
611209131Sraj			error = mv_pcib_init_all_bars(sc, bus, slot, func,
612185089Sraj			    hdrtype);
613185089Sraj
614185089Sraj			if (error)
615185089Sraj				return (error);
616185089Sraj
617185089Sraj			command |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN |
618185089Sraj			    PCIM_CMD_PORTEN;
619209131Sraj			mv_pcib_write_config(sc->sc_dev, bus, slot, func,
620185089Sraj			    PCIR_COMMAND, command, 1);
621185089Sraj
622185089Sraj			/* Handle PCI-PCI bridges */
623209131Sraj			class = mv_pcib_read_config(sc->sc_dev, bus, slot,
624185089Sraj			    func, PCIR_CLASS, 1);
625209131Sraj			subclass = mv_pcib_read_config(sc->sc_dev, bus, slot,
626185089Sraj			    func, PCIR_SUBCLASS, 1);
627185089Sraj
628185089Sraj			if (class != PCIC_BRIDGE ||
629185089Sraj			    subclass != PCIS_BRIDGE_PCI)
630185089Sraj				continue;
631185089Sraj
632209131Sraj			mv_pcib_init_bridge(sc, bus, slot, func);
633185089Sraj		}
634185089Sraj	}
635185089Sraj
636185089Sraj	/* Enable all ABCD interrupts */
637185089Sraj	pcib_write_irq_mask(sc, (0xF << 24));
638185089Sraj
639185089Sraj	return (0);
640185089Sraj}
641185089Sraj
642209131Srajstatic int
643209131Srajmv_pcib_init_all_bars(struct mv_pcib_softc *sc, int bus, int slot,
644209131Sraj    int func, int hdrtype)
645209131Sraj{
646209131Sraj	int maxbar, bar, i;
647209131Sraj
648209131Sraj	maxbar = (hdrtype & PCIM_HDRTYPE) ? 0 : 6;
649209131Sraj	bar = 0;
650209131Sraj
651209131Sraj	/* Program the base address registers */
652209131Sraj	while (bar < maxbar) {
653209131Sraj		i = mv_pcib_init_bar(sc, bus, slot, func, bar);
654209131Sraj		bar += i;
655209131Sraj		if (i < 0) {
656209131Sraj			device_printf(sc->sc_dev,
657209131Sraj			    "PCI IO/Memory space exhausted\n");
658209131Sraj			return (ENOMEM);
659209131Sraj		}
660209131Sraj	}
661209131Sraj
662209131Sraj	return (0);
663209131Sraj}
664209131Sraj
665185089Srajstatic struct resource *
666209131Srajmv_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
667185089Sraj    u_long start, u_long end, u_long count, u_int flags)
668185089Sraj{
669209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
670186932Sraj	struct rman *rm = NULL;
671186932Sraj	struct resource *res;
672185089Sraj
673186932Sraj	switch (type) {
674186932Sraj	case SYS_RES_IOPORT:
675209131Sraj		rm = &sc->sc_io_rman;
676186932Sraj		break;
677186932Sraj	case SYS_RES_MEMORY:
678209131Sraj		rm = &sc->sc_mem_rman;
679186932Sraj		break;
680186932Sraj	default:
681240489Sgber		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
682186932Sraj		    type, rid, start, end, count, flags));
683186932Sraj	};
684186932Sraj
685240489Sgber	if ((start == 0UL) && (end == ~0UL)) {
686240489Sgber		start = sc->sc_mem_base;
687240489Sgber		end = sc->sc_mem_base + sc->sc_mem_size - 1;
688240489Sgber		count = sc->sc_mem_size;
689240489Sgber	}
690240489Sgber
691240489Sgber	if ((start < sc->sc_mem_base) || (start + count - 1 != end) ||
692240489Sgber	    (end > sc->sc_mem_base + sc->sc_mem_size - 1))
693240489Sgber		return (NULL);
694240489Sgber
695186932Sraj	res = rman_reserve_resource(rm, start, end, count, flags, child);
696186932Sraj	if (res == NULL)
697186932Sraj		return (NULL);
698186932Sraj
699186932Sraj	rman_set_rid(res, *rid);
700209131Sraj	rman_set_bustag(res, fdtbus_bs_tag);
701186932Sraj	rman_set_bushandle(res, start);
702186932Sraj
703186932Sraj	if (flags & RF_ACTIVE)
704186932Sraj		if (bus_activate_resource(child, type, *rid, res)) {
705186932Sraj			rman_release_resource(res);
706186932Sraj			return (NULL);
707186932Sraj		}
708186932Sraj
709186932Sraj	return (res);
710185089Sraj}
711185089Sraj
712185089Srajstatic int
713209131Srajmv_pcib_release_resource(device_t dev, device_t child, int type, int rid,
714185089Sraj    struct resource *res)
715185089Sraj{
716185089Sraj
717186932Sraj	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY)
718186932Sraj		return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
719186932Sraj		    type, rid, res));
720186932Sraj
721186932Sraj	return (rman_release_resource(res));
722185089Sraj}
723185089Sraj
724185089Srajstatic int
725209131Srajmv_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
726185089Sraj{
727209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
728185089Sraj
729185089Sraj	switch (which) {
730185089Sraj	case PCIB_IVAR_BUS:
731185089Sraj		*result = sc->sc_busnr;
732185089Sraj		return (0);
733185089Sraj	case PCIB_IVAR_DOMAIN:
734185089Sraj		*result = device_get_unit(dev);
735185089Sraj		return (0);
736185089Sraj	}
737185089Sraj
738185089Sraj	return (ENOENT);
739185089Sraj}
740185089Sraj
741185089Srajstatic int
742209131Srajmv_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
743185089Sraj{
744209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
745185089Sraj
746185089Sraj	switch (which) {
747185089Sraj	case PCIB_IVAR_BUS:
748185089Sraj		sc->sc_busnr = value;
749185089Sraj		return (0);
750185089Sraj	}
751185089Sraj
752185089Sraj	return (ENOENT);
753185089Sraj}
754209131Sraj
755209131Srajstatic inline void
756209131Srajpcib_write_irq_mask(struct mv_pcib_softc *sc, uint32_t mask)
757209131Sraj{
758209131Sraj
759209131Sraj	if (!sc->sc_type != MV_TYPE_PCI)
760209131Sraj		return;
761209131Sraj
762209131Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_IRQ_MASK, mask);
763209131Sraj}
764209131Sraj
765209131Srajstatic void
766209131Srajmv_pcib_hw_cfginit(void)
767209131Sraj{
768209131Sraj	static int opened = 0;
769209131Sraj
770209131Sraj	if (opened)
771209131Sraj		return;
772209131Sraj
773209131Sraj	mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
774209131Sraj	opened = 1;
775209131Sraj}
776209131Sraj
777209131Srajstatic uint32_t
778209131Srajmv_pcib_hw_cfgread(struct mv_pcib_softc *sc, u_int bus, u_int slot,
779209131Sraj    u_int func, u_int reg, int bytes)
780209131Sraj{
781209131Sraj	uint32_t addr, data, ca, cd;
782209131Sraj
783209131Sraj	ca = (sc->sc_type != MV_TYPE_PCI) ?
784209131Sraj	    PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR;
785209131Sraj	cd = (sc->sc_type != MV_TYPE_PCI) ?
786209131Sraj	    PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA;
787209131Sraj	addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) |
788209131Sraj	    PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg);
789209131Sraj
790209131Sraj	mtx_lock_spin(&pcicfg_mtx);
791209131Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr);
792209131Sraj
793209131Sraj	data = ~0;
794209131Sraj	switch (bytes) {
795209131Sraj	case 1:
796209131Sraj		data = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
797209131Sraj		    cd + (reg & 3));
798209131Sraj		break;
799209131Sraj	case 2:
800209131Sraj		data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh,
801209131Sraj		    cd + (reg & 2)));
802209131Sraj		break;
803209131Sraj	case 4:
804209131Sraj		data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
805209131Sraj		    cd));
806209131Sraj		break;
807209131Sraj	}
808209131Sraj	mtx_unlock_spin(&pcicfg_mtx);
809209131Sraj	return (data);
810209131Sraj}
811209131Sraj
812209131Srajstatic void
813209131Srajmv_pcib_hw_cfgwrite(struct mv_pcib_softc *sc, u_int bus, u_int slot,
814209131Sraj    u_int func, u_int reg, uint32_t data, int bytes)
815209131Sraj{
816209131Sraj	uint32_t addr, ca, cd;
817209131Sraj
818209131Sraj	ca = (sc->sc_type != MV_TYPE_PCI) ?
819209131Sraj	    PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR;
820209131Sraj	cd = (sc->sc_type != MV_TYPE_PCI) ?
821209131Sraj	    PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA;
822209131Sraj	addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) |
823209131Sraj	    PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg);
824209131Sraj
825209131Sraj	mtx_lock_spin(&pcicfg_mtx);
826209131Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr);
827209131Sraj
828209131Sraj	switch (bytes) {
829209131Sraj	case 1:
830209131Sraj		bus_space_write_1(sc->sc_bst, sc->sc_bsh,
831209131Sraj		    cd + (reg & 3), data);
832209131Sraj		break;
833209131Sraj	case 2:
834209131Sraj		bus_space_write_2(sc->sc_bst, sc->sc_bsh,
835209131Sraj		    cd + (reg & 2), htole16(data));
836209131Sraj		break;
837209131Sraj	case 4:
838209131Sraj		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
839209131Sraj		    cd, htole32(data));
840209131Sraj		break;
841209131Sraj	}
842209131Sraj	mtx_unlock_spin(&pcicfg_mtx);
843209131Sraj}
844209131Sraj
845209131Srajstatic int
846209131Srajmv_pcib_maxslots(device_t dev)
847209131Sraj{
848209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
849209131Sraj
850209131Sraj	return ((sc->sc_type != MV_TYPE_PCI) ? 1 : PCI_SLOTMAX);
851209131Sraj}
852209131Sraj
853209131Srajstatic uint32_t
854209131Srajmv_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
855209131Sraj    u_int reg, int bytes)
856209131Sraj{
857209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
858209131Sraj
859240489Sgber	/* Return ~0 if link is inactive or trying to read from Root */
860240489Sgber	if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS) &
861240489Sgber	    PCIE_STATUS_LINK_DOWN) || (slot == 0))
862209131Sraj		return (~0U);
863209131Sraj
864209131Sraj	return (mv_pcib_hw_cfgread(sc, bus, slot, func, reg, bytes));
865209131Sraj}
866209131Sraj
867209131Srajstatic void
868209131Srajmv_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
869209131Sraj    u_int reg, uint32_t val, int bytes)
870209131Sraj{
871209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
872209131Sraj
873240489Sgber	/* Return if link is inactive or trying to write to Root */
874240489Sgber	if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS) &
875240489Sgber	    PCIE_STATUS_LINK_DOWN) || (slot == 0))
876209131Sraj		return;
877209131Sraj
878209131Sraj	mv_pcib_hw_cfgwrite(sc, bus, slot, func, reg, val, bytes);
879209131Sraj}
880209131Sraj
881209131Srajstatic int
882259484Snwhitehornmv_pcib_route_interrupt(device_t bus, device_t dev, int pin)
883209131Sraj{
884209131Sraj	struct mv_pcib_softc *sc;
885259484Snwhitehorn	struct ofw_pci_register reg;
886259484Snwhitehorn	uint32_t pintr, mintr;
887259484Snwhitehorn	phandle_t iparent;
888209131Sraj
889259484Snwhitehorn	sc = device_get_softc(bus);
890259484Snwhitehorn	pintr = pin;
891209131Sraj
892259484Snwhitehorn	/* Fabricate imap information in case this isn't an OFW device */
893259484Snwhitehorn	bzero(&reg, sizeof(reg));
894259484Snwhitehorn	reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
895259484Snwhitehorn	    (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
896259484Snwhitehorn	    (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
897209131Sraj
898259484Snwhitehorn	if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, &reg,
899259484Snwhitehorn	    sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
900259516Snwhitehorn	    &iparent))
901259484Snwhitehorn		return (ofw_bus_map_intr(dev, iparent, mintr));
902259484Snwhitehorn
903259484Snwhitehorn	/* Maybe it's a real interrupt, not an intpin */
904259484Snwhitehorn	if (pin > 4)
905259484Snwhitehorn		return (pin);
906259484Snwhitehorn
907259484Snwhitehorn	device_printf(bus, "could not route pin %d for device %d.%d\n",
908209131Sraj	    pin, pci_get_slot(dev), pci_get_function(dev));
909209131Sraj	return (PCI_INVALID_IRQ);
910209131Sraj}
911209131Sraj
912209131Srajstatic int
913209131Srajmv_pcib_decode_win(phandle_t node, struct mv_pcib_softc *sc)
914209131Sraj{
915209131Sraj	struct fdt_pci_range io_space, mem_space;
916209131Sraj	device_t dev;
917209131Sraj	int error;
918209131Sraj
919209131Sraj	dev = sc->sc_dev;
920209131Sraj
921209131Sraj	if ((error = fdt_pci_ranges(node, &io_space, &mem_space)) != 0) {
922209131Sraj		device_printf(dev, "could not retrieve 'ranges' data\n");
923209131Sraj		return (error);
924209131Sraj	}
925209131Sraj
926209131Sraj	/* Configure CPU decoding windows */
927240489Sgber	error = decode_win_cpu_set(sc->sc_win_target,
928240489Sgber	    sc->sc_io_win_attr, io_space.base_parent, io_space.len, ~0);
929209131Sraj	if (error < 0) {
930209131Sraj		device_printf(dev, "could not set up CPU decode "
931209131Sraj		    "window for PCI IO\n");
932209131Sraj		return (ENXIO);
933209131Sraj	}
934240489Sgber	error = decode_win_cpu_set(sc->sc_win_target,
935240489Sgber	    sc->sc_mem_win_attr, mem_space.base_parent, mem_space.len,
936240489Sgber	    mem_space.base_parent);
937209131Sraj	if (error < 0) {
938209131Sraj		device_printf(dev, "could not set up CPU decode "
939209131Sraj		    "windows for PCI MEM\n");
940209131Sraj		return (ENXIO);
941209131Sraj	}
942209131Sraj
943209131Sraj	sc->sc_io_base = io_space.base_parent;
944209131Sraj	sc->sc_io_size = io_space.len;
945209131Sraj
946209131Sraj	sc->sc_mem_base = mem_space.base_parent;
947209131Sraj	sc->sc_mem_size = mem_space.len;
948209131Sraj
949209131Sraj	return (0);
950209131Sraj}
951209131Sraj
952240493Sgber#if defined(SOC_MV_ARMADAXP)
953240493Sgberstatic int
954240493Sgbermv_pcib_map_msi(device_t dev, device_t child, int irq, uint64_t *addr,
955240493Sgber    uint32_t *data)
956240493Sgber{
957240493Sgber	struct mv_pcib_softc *sc;
958240493Sgber
959240493Sgber	sc = device_get_softc(dev);
960240493Sgber	irq = irq - MSI_IRQ;
961240493Sgber
962240493Sgber	/* validate parameters */
963240493Sgber	if (isclr(&sc->sc_msi_bitmap, irq)) {
964240493Sgber		device_printf(dev, "invalid MSI 0x%x\n", irq);
965240493Sgber		return (EINVAL);
966240493Sgber	}
967240493Sgber
968240493Sgber	mv_msi_data(irq, addr, data);
969240493Sgber
970240493Sgber	debugf("%s: irq: %d addr: %jx data: %x\n",
971240493Sgber	    __func__, irq, *addr, *data);
972240493Sgber
973240493Sgber	return (0);
974240493Sgber}
975240493Sgber
976240493Sgberstatic int
977240493Sgbermv_pcib_alloc_msi(device_t dev, device_t child, int count,
978240493Sgber    int maxcount __unused, int *irqs)
979240493Sgber{
980240493Sgber	struct mv_pcib_softc *sc;
981240493Sgber	u_int start = 0, i;
982240493Sgber
983240493Sgber	if (powerof2(count) == 0 || count > MSI_IRQ_NUM)
984240493Sgber		return (EINVAL);
985240493Sgber
986240493Sgber	sc = device_get_softc(dev);
987240493Sgber	mtx_lock(&sc->sc_msi_mtx);
988240493Sgber
989240493Sgber	for (start = 0; (start + count) < MSI_IRQ_NUM; start++) {
990240493Sgber		for (i = start; i < start + count; i++) {
991240493Sgber			if (isset(&sc->sc_msi_bitmap, i))
992240493Sgber				break;
993240493Sgber		}
994240493Sgber		if (i == start + count)
995240493Sgber			break;
996240493Sgber	}
997240493Sgber
998240493Sgber	if ((start + count) == MSI_IRQ_NUM) {
999240493Sgber		mtx_unlock(&sc->sc_msi_mtx);
1000240493Sgber		return (ENXIO);
1001240493Sgber	}
1002240493Sgber
1003240493Sgber	for (i = start; i < start + count; i++) {
1004240493Sgber		setbit(&sc->sc_msi_bitmap, i);
1005240493Sgber		irqs[i] = MSI_IRQ + i;
1006240493Sgber	}
1007240493Sgber	debugf("%s: start: %x count: %x\n", __func__, start, count);
1008240493Sgber
1009240493Sgber	mtx_unlock(&sc->sc_msi_mtx);
1010240493Sgber	return (0);
1011240493Sgber}
1012240493Sgber
1013240493Sgberstatic int
1014240493Sgbermv_pcib_release_msi(device_t dev, device_t child, int count, int *irqs)
1015240493Sgber{
1016240493Sgber	struct mv_pcib_softc *sc;
1017240493Sgber	u_int i;
1018240493Sgber
1019240493Sgber	sc = device_get_softc(dev);
1020240493Sgber	mtx_lock(&sc->sc_msi_mtx);
1021240493Sgber
1022240493Sgber	for (i = 0; i < count; i++)
1023240493Sgber		clrbit(&sc->sc_msi_bitmap, irqs[i] - MSI_IRQ);
1024240493Sgber
1025240493Sgber	mtx_unlock(&sc->sc_msi_mtx);
1026240493Sgber	return (0);
1027240493Sgber}
1028240493Sgber#endif
1029