1139825Simp/*-
286231Stmm * Copyright (c) 1999, 2000 Matthew R. Green
3117119Stmm * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>
4287726Smarius * Copyright (c) 2005 - 2015 by Marius Strobl <marius@FreeBSD.org>
586231Stmm * All rights reserved.
686231Stmm *
786231Stmm * Redistribution and use in source and binary forms, with or without
886231Stmm * modification, are permitted provided that the following conditions
986231Stmm * are met:
1086231Stmm * 1. Redistributions of source code must retain the above copyright
1186231Stmm *    notice, this list of conditions and the following disclaimer.
1286231Stmm * 2. Redistributions in binary form must reproduce the above copyright
1386231Stmm *    notice, this list of conditions and the following disclaimer in the
1486231Stmm *    documentation and/or other materials provided with the distribution.
1586231Stmm * 3. The name of the author may not be used to endorse or promote products
1686231Stmm *    derived from this software without specific prior written permission.
1786231Stmm *
1886231Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1986231Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2086231Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2186231Stmm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2286231Stmm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2386231Stmm * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2486231Stmm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2586231Stmm * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2686231Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2786231Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2886231Stmm * SUCH DAMAGE.
2986231Stmm *
3086231Stmm *	from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp
3186231Stmm */
3286231Stmm
33153057Smarius#include <sys/cdefs.h>
34153057Smarius__FBSDID("$FreeBSD$");
35153057Smarius
3686231Stmm#include "opt_ofw_pci.h"
3786231Stmm
3886231Stmm#include <sys/param.h>
3986231Stmm#include <sys/systm.h>
4086231Stmm#include <sys/bus.h>
41287726Smarius#include <sys/kernel.h>
42287726Smarius#include <sys/rman.h>
4386231Stmm
44287726Smarius#include <dev/ofw/ofw_bus.h>
45287726Smarius#include <dev/ofw/ofw_pci.h>
4686231Stmm#include <dev/ofw/openfirm.h>
4786231Stmm
48287726Smarius#include <dev/pci/pcireg.h>
49287726Smarius#include <dev/pci/pcivar.h>
50287726Smarius
51287726Smarius#include <machine/asi.h>
52115417Stmm#include <machine/bus.h>
53287726Smarius#include <machine/bus_private.h>
54287726Smarius#include <machine/cpufunc.h>
55287726Smarius#include <machine/fsr.h>
56287726Smarius#include <machine/resource.h>
5786231Stmm
58117119Stmm#include <sparc64/pci/ofw_pci.h>
59117119Stmm
60287726Smariusint
61287726Smariusofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize,
62287726Smarius    u_long memsize)
63287726Smarius{
64287726Smarius	struct ofw_pci_softc *sc;
65287726Smarius	struct ofw_pci_ranges *range;
66287726Smarius	phandle_t node;
67287726Smarius	uint32_t prop_array[2];
68287726Smarius	u_int i, j, nrange;
6986231Stmm
70287726Smarius	sc = device_get_softc(dev);
71287726Smarius	node = ofw_bus_get_node(dev);
72287726Smarius	sc->sc_node = node;
73287726Smarius	sc->sc_pci_dmat = dmat;
74117119Stmm
75287726Smarius	/* Initialize memory and I/O rmans. */
76287726Smarius	sc->sc_pci_io_rman.rm_type = RMAN_ARRAY;
77287726Smarius	sc->sc_pci_io_rman.rm_descr = "PCI I/O Ports";
78287726Smarius	if (rman_init(&sc->sc_pci_io_rman) != 0 ||
79287726Smarius	    rman_manage_region(&sc->sc_pci_io_rman, 0, iosize) != 0) {
80287726Smarius		device_printf(dev, "failed to set up I/O rman\n");
81287726Smarius		return (ENXIO);
82287726Smarius	}
83287726Smarius	sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY;
84287726Smarius	sc->sc_pci_mem_rman.rm_descr = "PCI Memory";
85287726Smarius	if (rman_init(&sc->sc_pci_mem_rman) != 0 ||
86287726Smarius	    rman_manage_region(&sc->sc_pci_mem_rman, 0, memsize) != 0) {
87287726Smarius		device_printf(dev, "failed to set up memory rman\n");
88287726Smarius		return (ENXIO);
89287726Smarius	}
9098148Stmm
91287726Smarius	/*
92287726Smarius	 * Find the addresses of the various bus spaces.  The physical
93287726Smarius	 * start addresses of the ranges are the configuration, I/O and
94287726Smarius	 * memory handles.  There should not be multiple ones of one kind.
95287726Smarius	 */
96287726Smarius	nrange = OF_getprop_alloc(node, "ranges", sizeof(*range),
97287726Smarius	    (void **)&range);
98287726Smarius	for (i = 0; i < nrange; i++) {
99287726Smarius		j = OFW_PCI_RANGE_CS(&range[i]);
100287726Smarius		if (sc->sc_pci_bh[j] != 0) {
101287726Smarius			device_printf(dev, "duplicate range for space %d\n",
102287726Smarius			    j);
103300173Sgonzo			OF_prop_free(range);
104287726Smarius			return (EINVAL);
10598148Stmm		}
106287726Smarius		sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]);
10798148Stmm	}
108300173Sgonzo	OF_prop_free(range);
109287726Smarius
110287726Smarius	/*
111287726Smarius	 * Make sure that the expected ranges are actually present.
112287726Smarius	 * The OFW_PCI_CS_MEM64 one is not currently used.
113287726Smarius	 */
114287726Smarius	if (sc->sc_pci_bh[OFW_PCI_CS_CONFIG] == 0) {
115287726Smarius		device_printf(dev, "missing CONFIG range\n");
116287726Smarius		return (ENXIO);
117287726Smarius	}
118287726Smarius	if (sc->sc_pci_bh[OFW_PCI_CS_IO] == 0) {
119287726Smarius		device_printf(dev, "missing IO range\n");
120287726Smarius		return (ENXIO);
121287726Smarius	}
122287726Smarius	if (sc->sc_pci_bh[OFW_PCI_CS_MEM32] == 0) {
123287726Smarius		device_printf(dev, "missing MEM32 range\n");
124287726Smarius		return (ENXIO);
125287726Smarius	}
126287726Smarius
127287726Smarius	/* Allocate our tags. */
128287726Smarius	sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE);
129287726Smarius	if (sc->sc_pci_iot == NULL) {
130287726Smarius		device_printf(dev, "could not allocate PCI I/O tag\n");
131287726Smarius		return (ENXIO);
132287726Smarius	}
133287726Smarius	sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE);
134287726Smarius	if (sc->sc_pci_cfgt == NULL) {
135287726Smarius		device_printf(dev,
136287726Smarius		    "could not allocate PCI configuration space tag\n");
137287726Smarius		return (ENXIO);
138287726Smarius	}
139287726Smarius
140287726Smarius	/*
141287726Smarius	 * Get the bus range from the firmware.
142287726Smarius	 */
143287726Smarius	i = OF_getprop(node, "bus-range", (void *)prop_array,
144287726Smarius	    sizeof(prop_array));
145287726Smarius	if (i == -1) {
146287726Smarius		device_printf(dev, "could not get bus-range\n");
147287726Smarius		return (ENXIO);
148287726Smarius	}
149287726Smarius	if (i != sizeof(prop_array)) {
150287726Smarius		device_printf(dev, "broken bus-range (%d)", i);
151287726Smarius		return (EINVAL);
152287726Smarius	}
153287726Smarius	sc->sc_pci_secbus = prop_array[0];
154287726Smarius	sc->sc_pci_subbus = prop_array[1];
155287726Smarius	if (bootverbose != 0)
156287726Smarius		device_printf(dev, "bus range %u to %u; PCI bus %d\n",
157287726Smarius		    sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus);
158287726Smarius
159287726Smarius	ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t));
160287726Smarius
161287726Smarius	return (0);
16298148Stmm}
163287726Smarius
164287726Smariusuint32_t
165287726Smariusofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset,
166287726Smarius    u_int bus, u_int slot, u_int func, u_int reg, int width)
167287726Smarius{
168287726Smarius	struct ofw_pci_softc *sc;
169287726Smarius	bus_space_handle_t bh;
170287726Smarius	uint32_t r, wrd;
171287726Smarius	int i;
172287726Smarius	uint16_t shrt;
173287726Smarius	uint8_t byte;
174287726Smarius
175287726Smarius	sc = device_get_softc(dev);
176287726Smarius	if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
177287726Smarius	    slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax)
178287726Smarius		return (-1);
179287726Smarius
180287726Smarius	bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
181287726Smarius	switch (width) {
182287726Smarius	case 1:
183287726Smarius		i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte);
184287726Smarius		r = byte;
185287726Smarius		break;
186287726Smarius	case 2:
187287726Smarius		i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt);
188287726Smarius		r = shrt;
189287726Smarius		break;
190287726Smarius	case 4:
191287726Smarius		i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd);
192287726Smarius		r = wrd;
193287726Smarius		break;
194287726Smarius	default:
195287726Smarius		panic("%s: bad width %d", __func__, width);
196287726Smarius		/* NOTREACHED */
197287726Smarius	}
198287726Smarius
199287726Smarius	if (i) {
200287726Smarius#ifdef OFW_PCI_DEBUG
201287726Smarius		printf("%s: read data error reading: %d.%d.%d: 0x%x\n",
202287726Smarius		    __func__, bus, slot, func, reg);
203287726Smarius#endif
204287726Smarius		r = -1;
205287726Smarius	}
206287726Smarius	return (r);
207287726Smarius}
208287726Smarius
209287726Smariusvoid
210287726Smariusofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset,
211287726Smarius    u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width)
212287726Smarius{
213287726Smarius	struct ofw_pci_softc *sc;
214287726Smarius	bus_space_handle_t bh;
215287726Smarius
216287726Smarius	sc = device_get_softc(dev);
217287726Smarius	if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
218287726Smarius	    slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax)
219287726Smarius		return;
220287726Smarius
221287726Smarius	bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
222287726Smarius	switch (width) {
223287726Smarius	case 1:
224287726Smarius		bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val);
225287726Smarius		break;
226287726Smarius	case 2:
227287726Smarius		bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val);
228287726Smarius		break;
229287726Smarius	case 4:
230287726Smarius		bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val);
231287726Smarius		break;
232287726Smarius	default:
233287726Smarius		panic("%s: bad width %d", __func__, width);
234287726Smarius		/* NOTREACHED */
235287726Smarius	}
236287726Smarius}
237287726Smarius
238287726Smariusofw_pci_intr_t
239287726Smariusofw_pci_route_interrupt_common(device_t bridge, device_t dev, int pin)
240287726Smarius{
241287726Smarius	struct ofw_pci_softc *sc;
242287726Smarius	struct ofw_pci_register reg;
243287726Smarius	ofw_pci_intr_t pintr, mintr;
244287726Smarius
245287726Smarius	sc = device_get_softc(bridge);
246287726Smarius	pintr = pin;
247287726Smarius	if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo,
248287726Smarius	    &reg, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
249287726Smarius	    NULL) != 0)
250287726Smarius		return (mintr);
251287726Smarius	return (PCI_INVALID_IRQ);
252287726Smarius}
253287726Smarius
254287726Smariusvoid
255287726Smariusofw_pci_dmamap_sync_stst_order_common(void)
256287726Smarius{
257287726Smarius	static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE);
258287726Smarius	register_t reg, s;
259287726Smarius
260287726Smarius	s = intr_disable();
261287726Smarius	reg = rd(fprs);
262287726Smarius	wr(fprs, reg | FPRS_FEF, 0);
263287726Smarius	__asm __volatile("stda %%f0, [%0] %1"
264287726Smarius	    : : "r" (buf), "n" (ASI_BLK_COMMIT_S));
265287726Smarius	membar(Sync);
266287726Smarius	wr(fprs, reg, 0);
267287726Smarius	intr_restore(s);
268287726Smarius}
269287726Smarius
270287726Smariusint
271287726Smariusofw_pci_read_ivar(device_t dev, device_t child __unused, int which,
272287726Smarius    uintptr_t *result)
273287726Smarius{
274287726Smarius	struct ofw_pci_softc *sc;
275287726Smarius
276287726Smarius	switch (which) {
277287726Smarius	case PCIB_IVAR_DOMAIN:
278287726Smarius		*result = device_get_unit(dev);
279287726Smarius		return (0);
280287726Smarius	case PCIB_IVAR_BUS:
281287726Smarius		sc = device_get_softc(dev);
282287726Smarius		*result = sc->sc_pci_secbus;
283287726Smarius		return (0);
284287726Smarius	}
285287726Smarius	return (ENOENT);
286287726Smarius}
287287726Smarius
288287726Smariusstruct resource *
289287726Smariusofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
290294883Sjhibbits    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
291287726Smarius{
292287726Smarius	struct ofw_pci_softc *sc;
293287726Smarius	struct resource *rv;
294287726Smarius	struct rman *rm;
295287726Smarius
296287726Smarius	sc = device_get_softc(bus);
297287726Smarius	switch (type) {
298287726Smarius	case SYS_RES_IRQ:
299287726Smarius		/*
300287726Smarius		 * XXX: Don't accept blank ranges for now, only single
301287726Smarius		 * interrupts.  The other case should not happen with
302287726Smarius		 * the MI PCI code ...
303287726Smarius		 * XXX: This may return a resource that is out of the
304287726Smarius		 * range that was specified.  Is this correct ...?
305287726Smarius		 */
306287726Smarius		if (start != end)
307287726Smarius			panic("%s: XXX: interrupt range", __func__);
308287726Smarius		return (bus_generic_alloc_resource(bus, child, type, rid,
309287726Smarius		    start, end, count, flags));
310287726Smarius	case SYS_RES_MEMORY:
311287726Smarius		rm = &sc->sc_pci_mem_rman;
312287726Smarius		break;
313287726Smarius	case SYS_RES_IOPORT:
314287726Smarius		rm = &sc->sc_pci_io_rman;
315287726Smarius		break;
316287726Smarius	default:
317287726Smarius		return (NULL);
318287726Smarius	}
319287726Smarius
320287726Smarius	rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
321287726Smarius	    child);
322287726Smarius	if (rv == NULL)
323287726Smarius		return (NULL);
324287726Smarius	rman_set_rid(rv, *rid);
325287726Smarius
326287726Smarius	if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type,
327287726Smarius	    *rid, rv) != 0) {
328287726Smarius		rman_release_resource(rv);
329287726Smarius		return (NULL);
330287726Smarius	}
331287726Smarius	return (rv);
332287726Smarius}
333287726Smarius
334287726Smariusint
335287726Smariusofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
336287726Smarius    struct resource *r)
337287726Smarius{
338287726Smarius	struct ofw_pci_softc *sc;
339287726Smarius	struct bus_space_tag *tag;
340287726Smarius
341287726Smarius	sc = device_get_softc(bus);
342287726Smarius	switch (type) {
343287726Smarius	case SYS_RES_IRQ:
344287726Smarius		return (bus_generic_activate_resource(bus, child, type, rid,
345287726Smarius		    r));
346287726Smarius	case SYS_RES_MEMORY:
347287726Smarius		tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE);
348287726Smarius		if (tag == NULL)
349287726Smarius			return (ENOMEM);
350287726Smarius		rman_set_bustag(r, tag);
351287726Smarius		rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] +
352287726Smarius		    rman_get_start(r));
353287726Smarius		break;
354287726Smarius	case SYS_RES_IOPORT:
355287726Smarius		rman_set_bustag(r, sc->sc_pci_iot);
356287726Smarius		rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] +
357287726Smarius		    rman_get_start(r));
358287726Smarius		break;
359287726Smarius	}
360287726Smarius	return (rman_activate_resource(r));
361287726Smarius}
362287726Smarius
363287726Smariusint
364287726Smariusofw_pci_adjust_resource(device_t bus, device_t child, int type,
365294883Sjhibbits    struct resource *r, rman_res_t start, rman_res_t end)
366287726Smarius{
367287726Smarius	struct ofw_pci_softc *sc;
368287726Smarius	struct rman *rm;
369287726Smarius
370287726Smarius	sc = device_get_softc(bus);
371287726Smarius	switch (type) {
372287726Smarius	case SYS_RES_IRQ:
373287726Smarius		return (bus_generic_adjust_resource(bus, child, type, r,
374287726Smarius		    start, end));
375287726Smarius	case SYS_RES_MEMORY:
376287726Smarius		rm = &sc->sc_pci_mem_rman;
377287726Smarius		break;
378287726Smarius	case SYS_RES_IOPORT:
379287726Smarius		rm = &sc->sc_pci_io_rman;
380287726Smarius		break;
381287726Smarius	default:
382287726Smarius		return (EINVAL);
383287726Smarius	}
384287726Smarius	if (rman_is_region_manager(r, rm) == 0)
385287726Smarius		return (EINVAL);
386287726Smarius	return (rman_adjust_resource(r, start, end));
387287726Smarius}
388287726Smarius
389287726Smariusbus_dma_tag_t
390287726Smariusofw_pci_get_dma_tag(device_t bus, device_t child __unused)
391287726Smarius{
392287726Smarius	struct ofw_pci_softc *sc;
393287726Smarius
394287726Smarius	sc = device_get_softc(bus);
395287726Smarius	return (sc->sc_pci_dmat);
396287726Smarius}
397287726Smarius
398287726Smariusphandle_t
399287726Smariusofw_pci_get_node(device_t bus, device_t child __unused)
400287726Smarius{
401287726Smarius	struct ofw_pci_softc *sc;
402287726Smarius
403287726Smarius	sc = device_get_softc(bus);
404287726Smarius	/* We only have one child, the PCI bus, which needs our own node. */
405287726Smarius	return (sc->sc_node);
406287726Smarius}
407