mv_pci.c revision 240493
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 240493 2012-09-14 10:06:56Z gber $");
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
56240493Sgber#include <machine/intr.h>
57240493Sgber
58185089Sraj#include <vm/vm.h>
59185089Sraj#include <vm/pmap.h>
60185089Sraj
61209131Sraj#include <dev/fdt/fdt_common.h>
62209131Sraj#include <dev/ofw/ofw_bus.h>
63209131Sraj#include <dev/ofw/ofw_bus_subr.h>
64185089Sraj#include <dev/pci/pcivar.h>
65185089Sraj#include <dev/pci/pcireg.h>
66185089Sraj#include <dev/pci/pcib_private.h>
67185089Sraj
68209131Sraj#include "ofw_bus_if.h"
69185089Sraj#include "pcib_if.h"
70185089Sraj
71185089Sraj#include <machine/resource.h>
72185089Sraj#include <machine/bus.h>
73185089Sraj
74185089Sraj#include <arm/mv/mvreg.h>
75185089Sraj#include <arm/mv/mvvar.h>
76209131Sraj#include <arm/mv/mvwin.h>
77185089Sraj
78240493Sgber#ifdef DEBUG
79240493Sgber#define debugf(fmt, args...) do { printf(fmt,##args); } while (0)
80240493Sgber#else
81240493Sgber#define debugf(fmt, args...)
82240493Sgber#endif
83240493Sgber
84185089Sraj#define PCI_CFG_ENA		(1 << 31)
85185089Sraj#define PCI_CFG_BUS(bus)	(((bus) & 0xff) << 16)
86185089Sraj#define PCI_CFG_DEV(dev)	(((dev) & 0x1f) << 11)
87185089Sraj#define PCI_CFG_FUN(fun)	(((fun) & 0x7) << 8)
88185089Sraj#define PCI_CFG_PCIE_REG(reg)	((reg) & 0xfc)
89185089Sraj
90185089Sraj#define PCI_REG_CFG_ADDR	0x0C78
91185089Sraj#define PCI_REG_CFG_DATA	0x0C7C
92185089Sraj
93185089Sraj#define PCIE_REG_CFG_ADDR	0x18F8
94185089Sraj#define PCIE_REG_CFG_DATA	0x18FC
95185089Sraj#define PCIE_REG_CONTROL	0x1A00
96185089Sraj#define   PCIE_CTRL_LINK1X	0x00000001
97185089Sraj#define PCIE_REG_STATUS		0x1A04
98185089Sraj#define PCIE_REG_IRQ_MASK	0x1910
99185089Sraj
100240489Sgber#define PCIE_CONTROL_ROOT_CMPLX	(1 << 1)
101240489Sgber#define PCIE_CONTROL_HOT_RESET	(1 << 24)
102185089Sraj
103240489Sgber#define PCIE_LINK_TIMEOUT	1000000
104185089Sraj
105240489Sgber#define PCIE_STATUS_LINK_DOWN	1
106240489Sgber#define PCIE_STATUS_DEV_OFFS	16
107185089Sraj
108240489Sgber/* Minimum PCI Memory and I/O allocations taken from PCI spec (in bytes) */
109240489Sgber#define PCI_MIN_IO_ALLOC	4
110240489Sgber#define PCI_MIN_MEM_ALLOC	16
111240489Sgber
112240489Sgber#define BITS_PER_UINT32		(NBBY * sizeof(uint32_t))
113240489Sgber
114209131Srajstruct mv_pcib_softc {
115185089Sraj	device_t	sc_dev;
116185089Sraj
117209131Sraj	struct rman	sc_mem_rman;
118209131Sraj	bus_addr_t	sc_mem_base;
119209131Sraj	bus_addr_t	sc_mem_size;
120240489Sgber	uint32_t	sc_mem_map[MV_PCI_MEM_SLICE_SIZE /
121240489Sgber	    (PCI_MIN_MEM_ALLOC * BITS_PER_UINT32)];
122240489Sgber	int		sc_win_target;
123209131Sraj	int		sc_mem_win_attr;
124185089Sraj
125209131Sraj	struct rman	sc_io_rman;
126209131Sraj	bus_addr_t	sc_io_base;
127209131Sraj	bus_addr_t	sc_io_size;
128240489Sgber	uint32_t	sc_io_map[MV_PCI_IO_SLICE_SIZE /
129240489Sgber	    (PCI_MIN_IO_ALLOC * BITS_PER_UINT32)];
130209131Sraj	int		sc_io_win_attr;
131185089Sraj
132185089Sraj	struct resource	*sc_res;
133185089Sraj	bus_space_handle_t sc_bsh;
134185089Sraj	bus_space_tag_t	sc_bst;
135185089Sraj	int		sc_rid;
136185089Sraj
137240493Sgber	struct mtx	sc_msi_mtx;
138240493Sgber	uint32_t	sc_msi_bitmap;
139240493Sgber
140185089Sraj	int		sc_busnr;		/* Host bridge bus number */
141185089Sraj	int		sc_devnr;		/* Host bridge device number */
142209131Sraj	int		sc_type;
143240489Sgber	int		sc_mode;		/* Endpoint / Root Complex */
144185089Sraj
145209131Sraj	struct fdt_pci_intr	sc_intr_info;
146185089Sraj};
147185089Sraj
148209131Sraj/* Local forward prototypes */
149209131Srajstatic int mv_pcib_decode_win(phandle_t, struct mv_pcib_softc *);
150209131Srajstatic void mv_pcib_hw_cfginit(void);
151209131Srajstatic uint32_t mv_pcib_hw_cfgread(struct mv_pcib_softc *, u_int, u_int,
152209131Sraj    u_int, u_int, int);
153209131Srajstatic void mv_pcib_hw_cfgwrite(struct mv_pcib_softc *, u_int, u_int,
154209131Sraj    u_int, u_int, uint32_t, int);
155209131Srajstatic int mv_pcib_init(struct mv_pcib_softc *, int, int);
156209131Srajstatic int mv_pcib_init_all_bars(struct mv_pcib_softc *, int, int, int, int);
157209131Srajstatic void mv_pcib_init_bridge(struct mv_pcib_softc *, int, int, int);
158209131Srajstatic int mv_pcib_intr_info(phandle_t, struct mv_pcib_softc *);
159209131Srajstatic inline void pcib_write_irq_mask(struct mv_pcib_softc *, uint32_t);
160240489Sgberstatic void mv_pcib_enable(struct mv_pcib_softc *, uint32_t);
161240489Sgberstatic int mv_pcib_mem_init(struct mv_pcib_softc *);
162185089Sraj
163209131Sraj/* Forward prototypes */
164209131Srajstatic int mv_pcib_probe(device_t);
165209131Srajstatic int mv_pcib_attach(device_t);
166209131Sraj
167209131Srajstatic struct resource *mv_pcib_alloc_resource(device_t, device_t, int, int *,
168185089Sraj    u_long, u_long, u_long, u_int);
169209131Srajstatic int mv_pcib_release_resource(device_t, device_t, int, int,
170185089Sraj    struct resource *);
171209131Srajstatic int mv_pcib_read_ivar(device_t, device_t, int, uintptr_t *);
172209131Srajstatic int mv_pcib_write_ivar(device_t, device_t, int, uintptr_t);
173185089Sraj
174209131Srajstatic int mv_pcib_maxslots(device_t);
175209131Srajstatic uint32_t mv_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int);
176209131Srajstatic void mv_pcib_write_config(device_t, u_int, u_int, u_int, u_int,
177185089Sraj    uint32_t, int);
178209131Srajstatic int mv_pcib_route_interrupt(device_t, device_t, int);
179240493Sgber#if defined(SOC_MV_ARMADAXP)
180240493Sgberstatic int mv_pcib_alloc_msi(device_t, device_t, int, int, int *);
181240493Sgberstatic int mv_pcib_map_msi(device_t, device_t, int, uint64_t *, uint32_t *);
182240493Sgberstatic int mv_pcib_release_msi(device_t, device_t, int, int *);
183240493Sgber#endif
184185089Sraj
185185089Sraj/*
186185089Sraj * Bus interface definitions.
187185089Sraj */
188209131Srajstatic device_method_t mv_pcib_methods[] = {
189185089Sraj	/* Device interface */
190209131Sraj	DEVMETHOD(device_probe,			mv_pcib_probe),
191209131Sraj	DEVMETHOD(device_attach,		mv_pcib_attach),
192185089Sraj
193185089Sraj	/* Bus interface */
194209131Sraj	DEVMETHOD(bus_read_ivar,		mv_pcib_read_ivar),
195209131Sraj	DEVMETHOD(bus_write_ivar,		mv_pcib_write_ivar),
196209131Sraj	DEVMETHOD(bus_alloc_resource,		mv_pcib_alloc_resource),
197209131Sraj	DEVMETHOD(bus_release_resource,		mv_pcib_release_resource),
198185089Sraj	DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
199185089Sraj	DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
200185089Sraj	DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
201185089Sraj	DEVMETHOD(bus_teardown_intr,		bus_generic_teardown_intr),
202185089Sraj
203185089Sraj	/* pcib interface */
204209131Sraj	DEVMETHOD(pcib_maxslots,		mv_pcib_maxslots),
205209131Sraj	DEVMETHOD(pcib_read_config,		mv_pcib_read_config),
206209131Sraj	DEVMETHOD(pcib_write_config,		mv_pcib_write_config),
207209131Sraj	DEVMETHOD(pcib_route_interrupt,		mv_pcib_route_interrupt),
208240493Sgber
209240493Sgber#if defined(SOC_MV_ARMADAXP)
210240493Sgber	DEVMETHOD(pcib_alloc_msi,		mv_pcib_alloc_msi),
211240493Sgber	DEVMETHOD(pcib_release_msi,		mv_pcib_release_msi),
212240493Sgber	DEVMETHOD(pcib_map_msi,			mv_pcib_map_msi),
213240493Sgber#endif
214240493Sgber
215209131Sraj	/* OFW bus interface */
216209131Sraj	DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
217209131Sraj	DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
218209131Sraj	DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
219209131Sraj	DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
220209131Sraj	DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
221209131Sraj
222227843Smarius	DEVMETHOD_END
223185089Sraj};
224185089Sraj
225209131Srajstatic driver_t mv_pcib_driver = {
226185089Sraj	"pcib",
227209131Sraj	mv_pcib_methods,
228209131Sraj	sizeof(struct mv_pcib_softc),
229185089Sraj};
230185089Sraj
231185089Srajdevclass_t pcib_devclass;
232185089Sraj
233209131SrajDRIVER_MODULE(pcib, fdtbus, mv_pcib_driver, pcib_devclass, 0, 0);
234185089Sraj
235185089Srajstatic struct mtx pcicfg_mtx;
236185089Sraj
237185089Srajstatic int
238209131Srajmv_pcib_probe(device_t self)
239185089Sraj{
240218228Smarcel	phandle_t node;
241185089Sraj
242218228Smarcel	node = ofw_bus_get_node(self);
243218228Smarcel	if (!fdt_is_type(node, "pci"))
244209131Sraj		return (ENXIO);
245218228Smarcel
246218228Smarcel	if (!(fdt_is_compatible(node, "mrvl,pcie") ||
247218228Smarcel	    fdt_is_compatible(node, "mrvl,pci")))
248209131Sraj		return (ENXIO);
249185089Sraj
250209131Sraj	device_set_desc(self, "Marvell Integrated PCI/PCI-E Controller");
251209131Sraj	return (BUS_PROBE_DEFAULT);
252185089Sraj}
253185089Sraj
254185089Srajstatic int
255209131Srajmv_pcib_attach(device_t self)
256185089Sraj{
257209131Sraj	struct mv_pcib_softc *sc;
258209131Sraj	phandle_t node, parnode;
259240489Sgber	uint32_t val, unit;
260209131Sraj	int err;
261185089Sraj
262185089Sraj	sc = device_get_softc(self);
263209131Sraj	sc->sc_dev = self;
264240489Sgber	unit = fdt_get_unit(self);
265185089Sraj
266240489Sgber
267218228Smarcel	node = ofw_bus_get_node(self);
268218228Smarcel	parnode = OF_parent(node);
269218228Smarcel	if (fdt_is_compatible(node, "mrvl,pcie")) {
270209131Sraj		sc->sc_type = MV_TYPE_PCIE;
271240489Sgber		sc->sc_win_target = MV_WIN_PCIE_TARGET(unit);
272240489Sgber		sc->sc_mem_win_attr = MV_WIN_PCIE_MEM_ATTR(unit);
273240489Sgber		sc->sc_io_win_attr = MV_WIN_PCIE_IO_ATTR(unit);
274218228Smarcel	} else if (fdt_is_compatible(node, "mrvl,pci")) {
275209131Sraj		sc->sc_type = MV_TYPE_PCI;
276240489Sgber		sc->sc_win_target = MV_WIN_PCI_TARGET;
277209131Sraj		sc->sc_mem_win_attr = MV_WIN_PCI_MEM_ATTR;
278209131Sraj		sc->sc_io_win_attr = MV_WIN_PCI_IO_ATTR;
279209131Sraj	} else
280185089Sraj		return (ENXIO);
281185089Sraj
282209131Sraj	/*
283209131Sraj	 * Retrieve our mem-mapped registers range.
284209131Sraj	 */
285185089Sraj	sc->sc_rid = 0;
286185089Sraj	sc->sc_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &sc->sc_rid,
287185089Sraj	    RF_ACTIVE);
288185089Sraj	if (sc->sc_res == NULL) {
289209131Sraj		device_printf(self, "could not map memory\n");
290185089Sraj		return (ENXIO);
291185089Sraj	}
292185089Sraj	sc->sc_bst = rman_get_bustag(sc->sc_res);
293185089Sraj	sc->sc_bsh = rman_get_bushandle(sc->sc_res);
294185089Sraj
295240489Sgber	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_CONTROL);
296240489Sgber	sc->sc_mode = (val & PCIE_CONTROL_ROOT_CMPLX ? MV_MODE_ROOT :
297240489Sgber	    MV_MODE_ENDPOINT);
298240489Sgber
299209131Sraj	/*
300240489Sgber	 * Get PCI interrupt info.
301240489Sgber	 */
302240489Sgber	if ((sc->sc_mode == MV_MODE_ROOT) &&
303240489Sgber	    (mv_pcib_intr_info(node, sc) != 0)) {
304240489Sgber		device_printf(self, "could not retrieve interrupt info\n");
305240489Sgber		return (ENXIO);
306240489Sgber	}
307240489Sgber
308240489Sgber	/*
309209131Sraj	 * Configure decode windows for PCI(E) access.
310209131Sraj	 */
311209131Sraj	if (mv_pcib_decode_win(node, sc) != 0)
312209131Sraj		return (ENXIO);
313209131Sraj
314209131Sraj	mv_pcib_hw_cfginit();
315209131Sraj
316209131Sraj	/*
317240489Sgber	 * Enable PCIE device.
318209131Sraj	 */
319240489Sgber	mv_pcib_enable(sc, unit);
320185089Sraj
321240489Sgber	/*
322240489Sgber	 * Memory management.
323240489Sgber	 */
324240489Sgber	err = mv_pcib_mem_init(sc);
325240489Sgber	if (err)
326240489Sgber		return (err);
327185089Sraj
328240489Sgber	if (sc->sc_mode == MV_MODE_ROOT) {
329240489Sgber		err = mv_pcib_init(sc, sc->sc_busnr,
330240489Sgber		    mv_pcib_maxslots(sc->sc_dev));
331240489Sgber		if (err)
332240489Sgber			goto error;
333240489Sgber
334240489Sgber		device_add_child(self, "pci", -1);
335240489Sgber	} else {
336240489Sgber		sc->sc_devnr = 1;
337240489Sgber		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
338240489Sgber		    PCIE_REG_STATUS, 1 << PCIE_STATUS_DEV_OFFS);
339240489Sgber		device_add_child(self, "pci_ep", -1);
340240489Sgber	}
341240489Sgber
342240493Sgber	mtx_init(&sc->sc_msi_mtx, "msi_mtx", NULL, MTX_DEF);
343240489Sgber	return (bus_generic_attach(self));
344240489Sgber
345240489Sgbererror:
346240489Sgber	/* XXX SYS_RES_ should be released here */
347240489Sgber	rman_fini(&sc->sc_mem_rman);
348240489Sgber	rman_fini(&sc->sc_io_rman);
349240489Sgber
350240489Sgber	return (err);
351240489Sgber}
352240489Sgber
353240489Sgberstatic void
354240489Sgbermv_pcib_enable(struct mv_pcib_softc *sc, uint32_t unit)
355240489Sgber{
356240489Sgber	uint32_t val;
357240489Sgber#if !defined(SOC_MV_ARMADAXP)
358240489Sgber	int timeout;
359240489Sgber
360240489Sgber	/*
361240489Sgber	 * Check if PCIE device is enabled.
362240489Sgber	 */
363240489Sgber	if (read_cpu_ctrl(CPU_CONTROL) & CPU_CONTROL_PCIE_DISABLE(unit)) {
364240489Sgber		write_cpu_ctrl(CPU_CONTROL, read_cpu_ctrl(CPU_CONTROL) &
365240489Sgber		    ~(CPU_CONTROL_PCIE_DISABLE(unit)));
366240489Sgber
367240489Sgber		timeout = PCIE_LINK_TIMEOUT;
368240489Sgber		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
369240489Sgber		    PCIE_REG_STATUS);
370240489Sgber		while (((val & PCIE_STATUS_LINK_DOWN) == 1) && (timeout > 0)) {
371240489Sgber			DELAY(1000);
372240489Sgber			timeout -= 1000;
373240489Sgber			val = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
374240489Sgber			    PCIE_REG_STATUS);
375240489Sgber		}
376240489Sgber	}
377240489Sgber#endif
378240489Sgber
379240489Sgber
380240489Sgber	if (sc->sc_mode == MV_MODE_ROOT) {
381240489Sgber		/*
382240489Sgber		 * Enable PCI bridge.
383240489Sgber		 */
384240489Sgber		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIR_COMMAND);
385240489Sgber		val |= PCIM_CMD_SERRESPEN | PCIM_CMD_BUSMASTEREN |
386240489Sgber		    PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
387240489Sgber		bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIR_COMMAND, val);
388240489Sgber	}
389240489Sgber}
390240489Sgber
391240489Sgberstatic int
392240489Sgbermv_pcib_mem_init(struct mv_pcib_softc *sc)
393240489Sgber{
394240489Sgber	int err;
395240489Sgber
396240489Sgber	/*
397240489Sgber	 * Memory management.
398240489Sgber	 */
399209131Sraj	sc->sc_mem_rman.rm_type = RMAN_ARRAY;
400209131Sraj	err = rman_init(&sc->sc_mem_rman);
401186932Sraj	if (err)
402186932Sraj		return (err);
403186932Sraj
404209131Sraj	sc->sc_io_rman.rm_type = RMAN_ARRAY;
405209131Sraj	err = rman_init(&sc->sc_io_rman);
406186932Sraj	if (err) {
407209131Sraj		rman_fini(&sc->sc_mem_rman);
408186932Sraj		return (err);
409186932Sraj	}
410186932Sraj
411209131Sraj	err = rman_manage_region(&sc->sc_mem_rman, sc->sc_mem_base,
412209131Sraj	    sc->sc_mem_base + sc->sc_mem_size - 1);
413186932Sraj	if (err)
414186932Sraj		goto error;
415186932Sraj
416209131Sraj	err = rman_manage_region(&sc->sc_io_rman, sc->sc_io_base,
417209131Sraj	    sc->sc_io_base + sc->sc_io_size - 1);
418186932Sraj	if (err)
419186932Sraj		goto error;
420186932Sraj
421240489Sgber	return (0);
422185089Sraj
423186932Srajerror:
424209131Sraj	rman_fini(&sc->sc_mem_rman);
425209131Sraj	rman_fini(&sc->sc_io_rman);
426240489Sgber
427186932Sraj	return (err);
428185089Sraj}
429185089Sraj
430240489Sgberstatic inline uint32_t
431240489Sgberpcib_bit_get(uint32_t *map, uint32_t bit)
432240489Sgber{
433240489Sgber	uint32_t n = bit / BITS_PER_UINT32;
434240489Sgber
435240489Sgber	bit = bit % BITS_PER_UINT32;
436240489Sgber	return (map[n] & (1 << bit));
437240489Sgber}
438240489Sgber
439240489Sgberstatic inline void
440240489Sgberpcib_bit_set(uint32_t *map, uint32_t bit)
441240489Sgber{
442240489Sgber	uint32_t n = bit / BITS_PER_UINT32;
443240489Sgber
444240489Sgber	bit = bit % BITS_PER_UINT32;
445240489Sgber	map[n] |= (1 << bit);
446240489Sgber}
447240489Sgber
448240489Sgberstatic inline uint32_t
449240489Sgberpcib_map_check(uint32_t *map, uint32_t start, uint32_t bits)
450240489Sgber{
451240489Sgber	uint32_t i;
452240489Sgber
453240489Sgber	for (i = start; i < start + bits; i++)
454240489Sgber		if (pcib_bit_get(map, i))
455240489Sgber			return (0);
456240489Sgber
457240489Sgber	return (1);
458240489Sgber}
459240489Sgber
460240489Sgberstatic inline void
461240489Sgberpcib_map_set(uint32_t *map, uint32_t start, uint32_t bits)
462240489Sgber{
463240489Sgber	uint32_t i;
464240489Sgber
465240489Sgber	for (i = start; i < start + bits; i++)
466240489Sgber		pcib_bit_set(map, i);
467240489Sgber}
468240489Sgber
469240489Sgber/*
470240489Sgber * The idea of this allocator is taken from ARM No-Cache memory
471240489Sgber * management code (sys/arm/arm/vm_machdep.c).
472240489Sgber */
473240489Sgberstatic bus_addr_t
474240489Sgberpcib_alloc(struct mv_pcib_softc *sc, uint32_t smask)
475240489Sgber{
476240489Sgber	uint32_t bits, bits_limit, i, *map, min_alloc, size;
477240489Sgber	bus_addr_t addr = 0;
478240489Sgber	bus_addr_t base;
479240489Sgber
480240489Sgber	if (smask & 1) {
481240489Sgber		base = sc->sc_io_base;
482240489Sgber		min_alloc = PCI_MIN_IO_ALLOC;
483240489Sgber		bits_limit = sc->sc_io_size / min_alloc;
484240489Sgber		map = sc->sc_io_map;
485240489Sgber		smask &= ~0x3;
486240489Sgber	} else {
487240489Sgber		base = sc->sc_mem_base;
488240489Sgber		min_alloc = PCI_MIN_MEM_ALLOC;
489240489Sgber		bits_limit = sc->sc_mem_size / min_alloc;
490240489Sgber		map = sc->sc_mem_map;
491240489Sgber		smask &= ~0xF;
492240489Sgber	}
493240489Sgber
494240489Sgber	size = ~smask + 1;
495240489Sgber	bits = size / min_alloc;
496240489Sgber
497240489Sgber	for (i = 0; i + bits <= bits_limit; i += bits)
498240489Sgber		if (pcib_map_check(map, i, bits)) {
499240489Sgber			pcib_map_set(map, i, bits);
500240489Sgber			addr = base + (i * min_alloc);
501240489Sgber			return (addr);
502240489Sgber		}
503240489Sgber
504240489Sgber	return (addr);
505240489Sgber}
506240489Sgber
507185089Srajstatic int
508209131Srajmv_pcib_init_bar(struct mv_pcib_softc *sc, int bus, int slot, int func,
509185089Sraj    int barno)
510185089Sraj{
511240489Sgber	uint32_t addr, bar;
512185089Sraj	int reg, width;
513185089Sraj
514185089Sraj	reg = PCIR_BAR(barno);
515240489Sgber
516240489Sgber	/*
517240489Sgber	 * Need to init the BAR register with 0xffffffff before correct
518240489Sgber	 * value can be read.
519240489Sgber	 */
520240489Sgber	mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, ~0, 4);
521209131Sraj	bar = mv_pcib_read_config(sc->sc_dev, bus, slot, func, reg, 4);
522185089Sraj	if (bar == 0)
523185089Sraj		return (1);
524185089Sraj
525185089Sraj	/* Calculate BAR size: 64 or 32 bit (in 32-bit units) */
526185089Sraj	width = ((bar & 7) == 4) ? 2 : 1;
527185089Sraj
528240489Sgber	addr = pcib_alloc(sc, bar);
529240489Sgber	if (!addr)
530185089Sraj		return (-1);
531185089Sraj
532185089Sraj	if (bootverbose)
533240489Sgber		printf("PCI %u:%u:%u: reg %x: smask=%08x: addr=%08x\n",
534240489Sgber		    bus, slot, func, reg, bar, addr);
535185089Sraj
536209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg, addr, 4);
537185089Sraj	if (width == 2)
538209131Sraj		mv_pcib_write_config(sc->sc_dev, bus, slot, func, reg + 4,
539185089Sraj		    0, 4);
540185089Sraj
541185089Sraj	return (width);
542185089Sraj}
543185089Sraj
544185089Srajstatic void
545209131Srajmv_pcib_init_bridge(struct mv_pcib_softc *sc, int bus, int slot, int func)
546185089Sraj{
547185089Sraj	bus_addr_t io_base, mem_base;
548185089Sraj	uint32_t io_limit, mem_limit;
549185089Sraj	int secbus;
550185089Sraj
551209131Sraj	io_base = sc->sc_io_base;
552209131Sraj	io_limit = io_base + sc->sc_io_size - 1;
553209131Sraj	mem_base = sc->sc_mem_base;
554209131Sraj	mem_limit = mem_base + sc->sc_mem_size - 1;
555185089Sraj
556185089Sraj	/* Configure I/O decode registers */
557209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEL_1,
558185639Sraj	    io_base >> 8, 1);
559209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOBASEH_1,
560185639Sraj	    io_base >> 16, 2);
561209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITL_1,
562185089Sraj	    io_limit >> 8, 1);
563209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_IOLIMITH_1,
564185089Sraj	    io_limit >> 16, 2);
565185089Sraj
566185089Sraj	/* Configure memory decode registers */
567209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMBASE_1,
568185089Sraj	    mem_base >> 16, 2);
569209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_MEMLIMIT_1,
570185089Sraj	    mem_limit >> 16, 2);
571185089Sraj
572185089Sraj	/* Disable memory prefetch decode */
573209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEL_1,
574185089Sraj	    0x10, 2);
575209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMBASEH_1,
576185089Sraj	    0x0, 4);
577209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITL_1,
578185089Sraj	    0xF, 2);
579209131Sraj	mv_pcib_write_config(sc->sc_dev, bus, slot, func, PCIR_PMLIMITH_1,
580185089Sraj	    0x0, 4);
581185089Sraj
582209131Sraj	secbus = mv_pcib_read_config(sc->sc_dev, bus, slot, func,
583185089Sraj	    PCIR_SECBUS_1, 1);
584185089Sraj
585185089Sraj	/* Configure buses behind the bridge */
586209131Sraj	mv_pcib_init(sc, secbus, PCI_SLOTMAX);
587185089Sraj}
588185089Sraj
589185089Srajstatic int
590209131Srajmv_pcib_init(struct mv_pcib_softc *sc, int bus, int maxslot)
591185089Sraj{
592185089Sraj	int slot, func, maxfunc, error;
593185089Sraj	uint8_t hdrtype, command, class, subclass;
594185089Sraj
595185089Sraj	for (slot = 0; slot <= maxslot; slot++) {
596185089Sraj		maxfunc = 0;
597185089Sraj		for (func = 0; func <= maxfunc; func++) {
598209131Sraj			hdrtype = mv_pcib_read_config(sc->sc_dev, bus, slot,
599185089Sraj			    func, PCIR_HDRTYPE, 1);
600185089Sraj
601185089Sraj			if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
602185089Sraj				continue;
603185089Sraj
604185089Sraj			if (func == 0 && (hdrtype & PCIM_MFDEV))
605185089Sraj				maxfunc = PCI_FUNCMAX;
606185089Sraj
607209131Sraj			command = mv_pcib_read_config(sc->sc_dev, bus, slot,
608185089Sraj			    func, PCIR_COMMAND, 1);
609185089Sraj			command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN);
610209131Sraj			mv_pcib_write_config(sc->sc_dev, bus, slot, func,
611185089Sraj			    PCIR_COMMAND, command, 1);
612185089Sraj
613209131Sraj			error = mv_pcib_init_all_bars(sc, bus, slot, func,
614185089Sraj			    hdrtype);
615185089Sraj
616185089Sraj			if (error)
617185089Sraj				return (error);
618185089Sraj
619185089Sraj			command |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN |
620185089Sraj			    PCIM_CMD_PORTEN;
621209131Sraj			mv_pcib_write_config(sc->sc_dev, bus, slot, func,
622185089Sraj			    PCIR_COMMAND, command, 1);
623185089Sraj
624185089Sraj			/* Handle PCI-PCI bridges */
625209131Sraj			class = mv_pcib_read_config(sc->sc_dev, bus, slot,
626185089Sraj			    func, PCIR_CLASS, 1);
627209131Sraj			subclass = mv_pcib_read_config(sc->sc_dev, bus, slot,
628185089Sraj			    func, PCIR_SUBCLASS, 1);
629185089Sraj
630185089Sraj			if (class != PCIC_BRIDGE ||
631185089Sraj			    subclass != PCIS_BRIDGE_PCI)
632185089Sraj				continue;
633185089Sraj
634209131Sraj			mv_pcib_init_bridge(sc, bus, slot, func);
635185089Sraj		}
636185089Sraj	}
637185089Sraj
638185089Sraj	/* Enable all ABCD interrupts */
639185089Sraj	pcib_write_irq_mask(sc, (0xF << 24));
640185089Sraj
641185089Sraj	return (0);
642185089Sraj}
643185089Sraj
644209131Srajstatic int
645209131Srajmv_pcib_init_all_bars(struct mv_pcib_softc *sc, int bus, int slot,
646209131Sraj    int func, int hdrtype)
647209131Sraj{
648209131Sraj	int maxbar, bar, i;
649209131Sraj
650209131Sraj	maxbar = (hdrtype & PCIM_HDRTYPE) ? 0 : 6;
651209131Sraj	bar = 0;
652209131Sraj
653209131Sraj	/* Program the base address registers */
654209131Sraj	while (bar < maxbar) {
655209131Sraj		i = mv_pcib_init_bar(sc, bus, slot, func, bar);
656209131Sraj		bar += i;
657209131Sraj		if (i < 0) {
658209131Sraj			device_printf(sc->sc_dev,
659209131Sraj			    "PCI IO/Memory space exhausted\n");
660209131Sraj			return (ENOMEM);
661209131Sraj		}
662209131Sraj	}
663209131Sraj
664209131Sraj	return (0);
665209131Sraj}
666209131Sraj
667185089Srajstatic struct resource *
668209131Srajmv_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
669185089Sraj    u_long start, u_long end, u_long count, u_int flags)
670185089Sraj{
671209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
672186932Sraj	struct rman *rm = NULL;
673186932Sraj	struct resource *res;
674185089Sraj
675186932Sraj	switch (type) {
676186932Sraj	case SYS_RES_IOPORT:
677209131Sraj		rm = &sc->sc_io_rman;
678186932Sraj		break;
679186932Sraj	case SYS_RES_MEMORY:
680209131Sraj		rm = &sc->sc_mem_rman;
681186932Sraj		break;
682186932Sraj	default:
683240489Sgber		return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
684186932Sraj		    type, rid, start, end, count, flags));
685186932Sraj	};
686186932Sraj
687240489Sgber	if ((start == 0UL) && (end == ~0UL)) {
688240489Sgber		start = sc->sc_mem_base;
689240489Sgber		end = sc->sc_mem_base + sc->sc_mem_size - 1;
690240489Sgber		count = sc->sc_mem_size;
691240489Sgber	}
692240489Sgber
693240489Sgber	if ((start < sc->sc_mem_base) || (start + count - 1 != end) ||
694240489Sgber	    (end > sc->sc_mem_base + sc->sc_mem_size - 1))
695240489Sgber		return (NULL);
696240489Sgber
697186932Sraj	res = rman_reserve_resource(rm, start, end, count, flags, child);
698186932Sraj	if (res == NULL)
699186932Sraj		return (NULL);
700186932Sraj
701186932Sraj	rman_set_rid(res, *rid);
702209131Sraj	rman_set_bustag(res, fdtbus_bs_tag);
703186932Sraj	rman_set_bushandle(res, start);
704186932Sraj
705186932Sraj	if (flags & RF_ACTIVE)
706186932Sraj		if (bus_activate_resource(child, type, *rid, res)) {
707186932Sraj			rman_release_resource(res);
708186932Sraj			return (NULL);
709186932Sraj		}
710186932Sraj
711186932Sraj	return (res);
712185089Sraj}
713185089Sraj
714185089Srajstatic int
715209131Srajmv_pcib_release_resource(device_t dev, device_t child, int type, int rid,
716185089Sraj    struct resource *res)
717185089Sraj{
718185089Sraj
719186932Sraj	if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY)
720186932Sraj		return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
721186932Sraj		    type, rid, res));
722186932Sraj
723186932Sraj	return (rman_release_resource(res));
724185089Sraj}
725185089Sraj
726185089Srajstatic int
727209131Srajmv_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
728185089Sraj{
729209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
730185089Sraj
731185089Sraj	switch (which) {
732185089Sraj	case PCIB_IVAR_BUS:
733185089Sraj		*result = sc->sc_busnr;
734185089Sraj		return (0);
735185089Sraj	case PCIB_IVAR_DOMAIN:
736185089Sraj		*result = device_get_unit(dev);
737185089Sraj		return (0);
738185089Sraj	}
739185089Sraj
740185089Sraj	return (ENOENT);
741185089Sraj}
742185089Sraj
743185089Srajstatic int
744209131Srajmv_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
745185089Sraj{
746209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
747185089Sraj
748185089Sraj	switch (which) {
749185089Sraj	case PCIB_IVAR_BUS:
750185089Sraj		sc->sc_busnr = value;
751185089Sraj		return (0);
752185089Sraj	}
753185089Sraj
754185089Sraj	return (ENOENT);
755185089Sraj}
756209131Sraj
757209131Srajstatic inline void
758209131Srajpcib_write_irq_mask(struct mv_pcib_softc *sc, uint32_t mask)
759209131Sraj{
760209131Sraj
761209131Sraj	if (!sc->sc_type != MV_TYPE_PCI)
762209131Sraj		return;
763209131Sraj
764209131Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_IRQ_MASK, mask);
765209131Sraj}
766209131Sraj
767209131Srajstatic void
768209131Srajmv_pcib_hw_cfginit(void)
769209131Sraj{
770209131Sraj	static int opened = 0;
771209131Sraj
772209131Sraj	if (opened)
773209131Sraj		return;
774209131Sraj
775209131Sraj	mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
776209131Sraj	opened = 1;
777209131Sraj}
778209131Sraj
779209131Srajstatic uint32_t
780209131Srajmv_pcib_hw_cfgread(struct mv_pcib_softc *sc, u_int bus, u_int slot,
781209131Sraj    u_int func, u_int reg, int bytes)
782209131Sraj{
783209131Sraj	uint32_t addr, data, ca, cd;
784209131Sraj
785209131Sraj	ca = (sc->sc_type != MV_TYPE_PCI) ?
786209131Sraj	    PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR;
787209131Sraj	cd = (sc->sc_type != MV_TYPE_PCI) ?
788209131Sraj	    PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA;
789209131Sraj	addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) |
790209131Sraj	    PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg);
791209131Sraj
792209131Sraj	mtx_lock_spin(&pcicfg_mtx);
793209131Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr);
794209131Sraj
795209131Sraj	data = ~0;
796209131Sraj	switch (bytes) {
797209131Sraj	case 1:
798209131Sraj		data = bus_space_read_1(sc->sc_bst, sc->sc_bsh,
799209131Sraj		    cd + (reg & 3));
800209131Sraj		break;
801209131Sraj	case 2:
802209131Sraj		data = le16toh(bus_space_read_2(sc->sc_bst, sc->sc_bsh,
803209131Sraj		    cd + (reg & 2)));
804209131Sraj		break;
805209131Sraj	case 4:
806209131Sraj		data = le32toh(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
807209131Sraj		    cd));
808209131Sraj		break;
809209131Sraj	}
810209131Sraj	mtx_unlock_spin(&pcicfg_mtx);
811209131Sraj	return (data);
812209131Sraj}
813209131Sraj
814209131Srajstatic void
815209131Srajmv_pcib_hw_cfgwrite(struct mv_pcib_softc *sc, u_int bus, u_int slot,
816209131Sraj    u_int func, u_int reg, uint32_t data, int bytes)
817209131Sraj{
818209131Sraj	uint32_t addr, ca, cd;
819209131Sraj
820209131Sraj	ca = (sc->sc_type != MV_TYPE_PCI) ?
821209131Sraj	    PCIE_REG_CFG_ADDR : PCI_REG_CFG_ADDR;
822209131Sraj	cd = (sc->sc_type != MV_TYPE_PCI) ?
823209131Sraj	    PCIE_REG_CFG_DATA : PCI_REG_CFG_DATA;
824209131Sraj	addr = PCI_CFG_ENA | PCI_CFG_BUS(bus) | PCI_CFG_DEV(slot) |
825209131Sraj	    PCI_CFG_FUN(func) | PCI_CFG_PCIE_REG(reg);
826209131Sraj
827209131Sraj	mtx_lock_spin(&pcicfg_mtx);
828209131Sraj	bus_space_write_4(sc->sc_bst, sc->sc_bsh, ca, addr);
829209131Sraj
830209131Sraj	switch (bytes) {
831209131Sraj	case 1:
832209131Sraj		bus_space_write_1(sc->sc_bst, sc->sc_bsh,
833209131Sraj		    cd + (reg & 3), data);
834209131Sraj		break;
835209131Sraj	case 2:
836209131Sraj		bus_space_write_2(sc->sc_bst, sc->sc_bsh,
837209131Sraj		    cd + (reg & 2), htole16(data));
838209131Sraj		break;
839209131Sraj	case 4:
840209131Sraj		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
841209131Sraj		    cd, htole32(data));
842209131Sraj		break;
843209131Sraj	}
844209131Sraj	mtx_unlock_spin(&pcicfg_mtx);
845209131Sraj}
846209131Sraj
847209131Srajstatic int
848209131Srajmv_pcib_maxslots(device_t dev)
849209131Sraj{
850209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
851209131Sraj
852209131Sraj	return ((sc->sc_type != MV_TYPE_PCI) ? 1 : PCI_SLOTMAX);
853209131Sraj}
854209131Sraj
855209131Srajstatic uint32_t
856209131Srajmv_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
857209131Sraj    u_int reg, int bytes)
858209131Sraj{
859209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
860209131Sraj
861240489Sgber	/* Return ~0 if link is inactive or trying to read from Root */
862240489Sgber	if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS) &
863240489Sgber	    PCIE_STATUS_LINK_DOWN) || (slot == 0))
864209131Sraj		return (~0U);
865209131Sraj
866209131Sraj	return (mv_pcib_hw_cfgread(sc, bus, slot, func, reg, bytes));
867209131Sraj}
868209131Sraj
869209131Srajstatic void
870209131Srajmv_pcib_write_config(device_t dev, u_int bus, u_int slot, u_int func,
871209131Sraj    u_int reg, uint32_t val, int bytes)
872209131Sraj{
873209131Sraj	struct mv_pcib_softc *sc = device_get_softc(dev);
874209131Sraj
875240489Sgber	/* Return if link is inactive or trying to write to Root */
876240489Sgber	if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, PCIE_REG_STATUS) &
877240489Sgber	    PCIE_STATUS_LINK_DOWN) || (slot == 0))
878209131Sraj		return;
879209131Sraj
880209131Sraj	mv_pcib_hw_cfgwrite(sc, bus, slot, func, reg, val, bytes);
881209131Sraj}
882209131Sraj
883209131Srajstatic int
884209131Srajmv_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
885209131Sraj{
886209131Sraj	struct mv_pcib_softc *sc;
887209131Sraj	int err, interrupt;
888209131Sraj
889209131Sraj	sc = device_get_softc(pcib);
890209131Sraj
891209131Sraj	err = fdt_pci_route_intr(pci_get_bus(dev), pci_get_slot(dev),
892209131Sraj	    pci_get_function(dev), pin, &sc->sc_intr_info, &interrupt);
893209131Sraj	if (err == 0)
894209131Sraj		return (interrupt);
895209131Sraj
896209131Sraj	device_printf(pcib, "could not route pin %d for device %d.%d\n",
897209131Sraj	    pin, pci_get_slot(dev), pci_get_function(dev));
898209131Sraj	return (PCI_INVALID_IRQ);
899209131Sraj}
900209131Sraj
901209131Srajstatic int
902209131Srajmv_pcib_decode_win(phandle_t node, struct mv_pcib_softc *sc)
903209131Sraj{
904209131Sraj	struct fdt_pci_range io_space, mem_space;
905209131Sraj	device_t dev;
906209131Sraj	int error;
907209131Sraj
908209131Sraj	dev = sc->sc_dev;
909209131Sraj
910209131Sraj	if ((error = fdt_pci_ranges(node, &io_space, &mem_space)) != 0) {
911209131Sraj		device_printf(dev, "could not retrieve 'ranges' data\n");
912209131Sraj		return (error);
913209131Sraj	}
914209131Sraj
915209131Sraj	/* Configure CPU decoding windows */
916240489Sgber	error = decode_win_cpu_set(sc->sc_win_target,
917240489Sgber	    sc->sc_io_win_attr, io_space.base_parent, io_space.len, ~0);
918209131Sraj	if (error < 0) {
919209131Sraj		device_printf(dev, "could not set up CPU decode "
920209131Sraj		    "window for PCI IO\n");
921209131Sraj		return (ENXIO);
922209131Sraj	}
923240489Sgber	error = decode_win_cpu_set(sc->sc_win_target,
924240489Sgber	    sc->sc_mem_win_attr, mem_space.base_parent, mem_space.len,
925240489Sgber	    mem_space.base_parent);
926209131Sraj	if (error < 0) {
927209131Sraj		device_printf(dev, "could not set up CPU decode "
928209131Sraj		    "windows for PCI MEM\n");
929209131Sraj		return (ENXIO);
930209131Sraj	}
931209131Sraj
932209131Sraj	sc->sc_io_base = io_space.base_parent;
933209131Sraj	sc->sc_io_size = io_space.len;
934209131Sraj
935209131Sraj	sc->sc_mem_base = mem_space.base_parent;
936209131Sraj	sc->sc_mem_size = mem_space.len;
937209131Sraj
938209131Sraj	return (0);
939209131Sraj}
940209131Sraj
941209131Srajstatic int
942209131Srajmv_pcib_intr_info(phandle_t node, struct mv_pcib_softc *sc)
943209131Sraj{
944209131Sraj	int error;
945209131Sraj
946209131Sraj	if ((error = fdt_pci_intr_info(node, &sc->sc_intr_info)) != 0)
947209131Sraj		return (error);
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