1183371Simp/*-
2183371Simp * Copyright (c) 2007 Bruce M. Simpson.
3183371Simp * All rights reserved.
4183371Simp *
5183371Simp * Redistribution and use in source and binary forms, with or without
6183371Simp * modification, are permitted provided that the following conditions
7183371Simp * are met:
8183371Simp * 1. Redistributions of source code must retain the above copyright
9183371Simp *    notice, this list of conditions and the following disclaimer.
10183371Simp * 2. Redistributions in binary form must reproduce the above copyright
11183371Simp *    notice, this list of conditions and the following disclaimer in the
12183371Simp *    documentation and/or other materials provided with the distribution.
13183371Simp *
14183371Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15183371Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16183371Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17183371Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18183371Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19183371Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20183371Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21183371Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22183371Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23183371Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24183371Simp * SUCH DAMAGE.
25183371Simp */
26183371Simp
27183371Simp/*
28183371Simp * Child driver for PCI host bridge core.
29183371Simp */
30183371Simp
31183371Simp#include <sys/cdefs.h>
32183371Simp__FBSDID("$FreeBSD$");
33183371Simp
34183371Simp#include <sys/param.h>
35183371Simp#include <sys/systm.h>
36183371Simp#include <sys/bus.h>
37183371Simp#include <sys/kernel.h>
38183371Simp#include <sys/module.h>
39183371Simp#include <sys/rman.h>
40183371Simp#include <sys/malloc.h>
41183371Simp#include <sys/endian.h>
42183371Simp
43183371Simp#include <vm/vm.h>
44183371Simp#include <vm/pmap.h>
45183371Simp#include <vm/vm_extern.h>
46183371Simp
47183371Simp#include <machine/bus.h>
48183371Simp#include <machine/cpu.h>
49183371Simp#include <machine/pcb.h>
50183371Simp#include <machine/pmap.h>
51183371Simp
52183371Simp#include <dev/pci/pcireg.h>
53183371Simp#include <dev/pci/pcivar.h>
54183371Simp#include <dev/pci/pcib_private.h>
55183371Simp
56183371Simp#include "pcib_if.h"
57183371Simp
58203319Sweongyo#include <dev/siba/siba_ids.h>
59203319Sweongyo#include <dev/siba/sibareg.h>
60183371Simp#include <dev/siba/sibavar.h>
61183371Simp#include <dev/siba/siba_pcibvar.h>
62183371Simp
63183371Simp#ifndef MIPS_MEM_RID
64183371Simp#define MIPS_MEM_RID 0x20
65183371Simp#endif
66183371Simp
67183371Simp#define SBPCI_SLOTMAX 15
68183371Simp
69183371Simp#define SBPCI_READ_4(sc, reg)					\
70183371Simp	bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, (reg))
71183371Simp
72183371Simp#define SBPCI_WRITE_4(sc, reg, val)					\
73183371Simp	bus_space_write_4((sc)->sc_bt, (sc)->sc_bh, (reg), (val))
74183371Simp
75183371Simp/*
76183371Simp * PCI Configuration space window (64MB).
77183371Simp * contained in SBTOPCI1 window.
78183371Simp */
79183371Simp#define SBPCI_CFGBASE			0x0C000000
80183371Simp#define SBPCI_CFGSIZE			0x01000000
81183371Simp
82183371Simp/*
83183371Simp * TODO: implement type 1 config space access (ie beyond bus 0)
84183371Simp * we may need to tweak the windows to do this
85183371Simp * TODO: interrupt routing.
86183371Simp * TODO: fully implement bus allocation.
87183371Simp * TODO: implement resource managers.
88183371Simp * TODO: code cleanup.
89183371Simp */
90183371Simp
91183371Simpstatic int	siba_pcib_activate_resource(device_t, device_t, int,
92183371Simp		    int, struct resource *);
93183371Simpstatic struct resource *
94183371Simp		siba_pcib_alloc_resource(device_t, device_t, int, int *,
95183371Simp		    u_long , u_long, u_long, u_int);
96183371Simpstatic int	siba_pcib_attach(device_t);
97183371Simpstatic int	siba_pcib_deactivate_resource(device_t, device_t, int,
98183371Simp		    int, struct resource *);
99183371Simpstatic int	siba_pcib_maxslots(device_t);
100183371Simpstatic int	siba_pcib_probe(device_t);
101183371Simpstatic u_int32_t
102183371Simp		siba_pcib_read_config(device_t, u_int, u_int, u_int, u_int,
103183371Simp		    int);
104183371Simpstatic int	siba_pcib_read_ivar(device_t, device_t, int, uintptr_t *);
105183371Simpstatic int	siba_pcib_release_resource(device_t, device_t, int, int,
106183371Simp		    struct resource *);
107183371Simpstatic int	siba_pcib_route_interrupt(device_t, device_t, int);
108183371Simpstatic int	siba_pcib_setup_intr(device_t, device_t, struct resource *,
109183371Simp		    int, driver_filter_t *, driver_intr_t *, void *, void **);
110183371Simpstatic int	siba_pcib_teardown_intr(device_t, device_t, struct resource *,
111183371Simp		    void *);
112183371Simpstatic void	siba_pcib_write_config(device_t, u_int, u_int, u_int, u_int,
113183371Simp		    u_int32_t, int);
114183371Simpstatic int	siba_pcib_write_ivar(device_t, device_t, int, uintptr_t);
115183371Simp
116183371Simpstatic int
117183371Simpsiba_pcib_probe(device_t dev)
118183371Simp{
119183371Simp
120183371Simp	/* TODO: support earlier cores. */
121183371Simp	/* TODO: Check if PCI host mode is enabled in the SPROM. */
122183371Simp	if (siba_get_vendor(dev) == SIBA_VID_BROADCOM &&
123183371Simp	    siba_get_device(dev) == SIBA_DEVID_PCI) {
124183371Simp		device_set_desc(dev, "SiBa-to-PCI host bridge");
125183371Simp		return (BUS_PROBE_DEFAULT);
126183371Simp	}
127183371Simp
128183371Simp	return (ENXIO);
129183371Simp}
130183371Simp
131183371Simp//extern int rman_debug;
132183371Simp
133183371Simpstatic int
134183371Simpsiba_pcib_attach(device_t dev)
135183371Simp{
136183371Simp	struct siba_pcib_softc *sc = device_get_softc(dev);
137183371Simp	int rid;
138183371Simp
139183371Simp	/*
140183371Simp	 * Allocate the resources which the parent bus has already
141183371Simp	 * determined for us.
142183371Simp	 */
143183371Simp	rid = MIPS_MEM_RID;	/* XXX */
144183371Simp	//rman_debug = 1;
145183371Simp	sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
146183371Simp	    RF_ACTIVE);
147183371Simp	if (sc->sc_mem == NULL) {
148183371Simp		device_printf(dev, "unable to allocate memory\n");
149183371Simp		return (ENXIO);
150183371Simp	}
151183371Simp
152183371Simp	sc->sc_bt = rman_get_bustag(sc->sc_mem);
153183371Simp	sc->sc_bh = rman_get_bushandle(sc->sc_mem);
154183371Simp
155183371Simp	device_printf(dev, "bridge registers addr 0x%08x vaddr %p\n",
156183377Simp	    (uint32_t)sc->sc_bh, rman_get_virtual(sc->sc_mem));
157183371Simp
158183371Simp	SBPCI_WRITE_4(sc, 0x0000, 0x05);
159183371Simp	SBPCI_WRITE_4(sc, 0x0000, 0x0D);
160183371Simp	DELAY(150);
161183371Simp	SBPCI_WRITE_4(sc, 0x0000, 0x0F);
162183371Simp	SBPCI_WRITE_4(sc, 0x0010, 0x01);
163183371Simp	DELAY(1);
164183371Simp
165183371Simp	bus_space_handle_t sc_cfg_hand;
166183371Simp	int error;
167183371Simp
168183371Simp	/*
169183371Simp	 * XXX this doesn't actually do anything on mips; however... should
170183371Simp	 * we not be mapping to KSEG1? we need to wire down the range.
171183371Simp	 */
172183371Simp	error = bus_space_map(sc->sc_bt, SBPCI_CFGBASE, SBPCI_CFGSIZE,
173183371Simp	    0, &sc_cfg_hand);
174183371Simp	if (error) {
175183371Simp		device_printf(dev, "cannot map PCI configuration space\n");
176183371Simp		return (ENXIO);
177183371Simp	}
178183377Simp	device_printf(dev, "mapped pci config space at 0x%08x\n",
179183377Simp	    (uint32_t)sc_cfg_hand);
180183371Simp
181183371Simp	/*
182183371Simp	 * Setup configuration, io, and dma space windows.
183183371Simp	 * XXX we need to be able to do type 1 too.
184183371Simp	 * we probably don't need to be able to do i/o cycles.
185183371Simp	 */
186203319Sweongyo
187203319Sweongyo	/* I/O read/write window */
188203319Sweongyo	SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI0, 1);
189203319Sweongyo	/* type 0 configuration only */
190203319Sweongyo	SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2);
191203319Sweongyo	SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI2, 1 << 30); /* memory only */
192183371Simp	DELAY(500);
193183371Simp
194183371Simp	/* XXX resource managers */
195183371Simp
196183371Simp	device_add_child(dev, "pci", -1);
197183371Simp	return (bus_generic_attach(dev));
198183371Simp}
199183371Simp
200183371Simp/* bus functions */
201183371Simp
202183371Simpstatic int
203183371Simpsiba_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
204183371Simp{
205183371Simp	struct siba_pcib_softc *sc;
206183371Simp
207183371Simp	sc = device_get_softc(dev);
208183371Simp	switch (which) {
209183371Simp	case PCIB_IVAR_BUS:
210183371Simp		*result = sc->sc_bus;
211183371Simp		return (0);
212183371Simp	}
213183371Simp
214183371Simp	return (ENOENT);
215183371Simp}
216183371Simp
217183371Simpstatic int
218183371Simpsiba_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
219183371Simp{
220183371Simp	struct siba_pcib_softc *sc;
221183371Simp
222183371Simp	sc = device_get_softc(dev);
223183371Simp	switch (which) {
224183371Simp	case PCIB_IVAR_BUS:
225183371Simp		sc->sc_bus = value;
226183371Simp		return (0);
227183371Simp	}
228183371Simp
229183371Simp	return (ENOENT);
230183371Simp}
231183371Simp
232183371Simpstatic int
233183371Simpsiba_pcib_setup_intr(device_t dev, device_t child, struct resource *ires,
234183371Simp    int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
235183371Simp    void **cookiep)
236183371Simp{
237183371Simp
238183371Simp	return (BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
239183371Simp	    filt, intr, arg, cookiep));
240183371Simp}
241183371Simp
242183371Simpstatic int
243183371Simpsiba_pcib_teardown_intr(device_t dev, device_t child, struct resource *vec,
244183371Simp     void *cookie)
245183371Simp{
246183371Simp
247183371Simp	return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec, cookie));
248183371Simp}
249183371Simp
250183371Simpstatic struct resource *
251183371Simpsiba_pcib_alloc_resource(device_t bus, device_t child, int type, int *rid,
252183371Simp    u_long start, u_long end, u_long count, u_int flags)
253183371Simp{
254183371Simp#if 1
255183371Simp
256183371Simp	//device_printf(bus, "%s: not yet implemented\n", __func__);
257183371Simp	return (NULL);
258183371Simp#else
259183371Simp	bus_space_tag_t tag;
260183371Simp	struct siba_pcib_softc *sc = device_get_softc(bus);
261183371Simp	struct rman *rmanp;
262183371Simp	struct resource *rv;
263183371Simp
264183371Simp	tag = 0;
265183371Simp	rv = NULL;
266183371Simp	switch (type) {
267183371Simp	case SYS_RES_IRQ:
268183371Simp		rmanp = &sc->sc_irq_rman;
269183371Simp		break;
270183371Simp
271183371Simp	case SYS_RES_MEMORY:
272183371Simp		rmanp = &sc->sc_mem_rman;
273183371Simp		tag = &sc->sc_pci_memt;
274183371Simp		break;
275183371Simp
276183371Simp	default:
277183371Simp		return (rv);
278183371Simp	}
279183371Simp
280183371Simp	rv = rman_reserve_resource(rmanp, start, end, count, flags, child);
281183371Simp	if (rv != NULL) {
282183371Simp		rman_set_rid(rv, *rid);
283183371Simp		if (type == SYS_RES_MEMORY) {
284183371Simp#if 0
285183371Simp			rman_set_bustag(rv, tag);
286183371Simp			rman_set_bushandle(rv, rman_get_bushandle(sc->sc_mem) +
287183371Simp			    (rman_get_start(rv) - IXP425_PCI_MEM_HWBASE));
288183371Simp#endif
289183371Simp		}
290183371Simp	}
291183371Simp
292183371Simp	return (rv);
293183371Simp#endif
294183371Simp}
295183371Simp
296183371Simpstatic int
297183371Simpsiba_pcib_activate_resource(device_t bus, device_t child, int type, int rid,
298183371Simp    struct resource *r)
299183371Simp{
300183371Simp
301183371Simp	device_printf(bus, "%s: not yet implemented\n", __func__);
302183371Simp	device_printf(bus, "%s called activate_resource\n",
303183371Simp	    device_get_nameunit(child));
304183371Simp	return (ENXIO);
305183371Simp}
306183371Simp
307183371Simpstatic int
308183371Simpsiba_pcib_deactivate_resource(device_t bus, device_t child, int type, int rid,
309183371Simp    struct resource *r)
310183371Simp{
311183371Simp
312183371Simp	device_printf(bus, "%s: not yet implemented\n", __func__);
313183371Simp	device_printf(bus, "%s called deactivate_resource\n",
314183371Simp	    device_get_nameunit(child));
315183371Simp	return (ENXIO);
316183371Simp}
317183371Simp
318183371Simpstatic int
319183371Simpsiba_pcib_release_resource(device_t bus, device_t child, int type, int rid,
320183371Simp    struct resource *r)
321183371Simp{
322183371Simp
323183371Simp	device_printf(bus, "%s: not yet implemented\n", __func__);
324183371Simp	device_printf(bus, "%s called release_resource\n",
325183371Simp	    device_get_nameunit(child));
326183371Simp	return (ENXIO);
327183371Simp}
328183371Simp
329183371Simp/* pcib interface functions */
330183371Simp
331183371Simpstatic int
332183371Simpsiba_pcib_maxslots(device_t dev)
333183371Simp{
334183371Simp
335183371Simp	return (SBPCI_SLOTMAX);
336183371Simp}
337183371Simp
338183371Simp/*
339183371Simp * This needs hacking and fixery. It is currently broke and hangs.
340183371Simp * Debugging it will be tricky; there seems to be no way to enable
341183371Simp * a target abort which would cause a nice target abort.
342183371Simp * Look at linux again?
343183371Simp */
344183371Simpstatic u_int32_t
345183371Simpsiba_pcib_read_config(device_t dev, u_int bus, u_int slot, u_int func,
346183371Simp    u_int reg, int bytes)
347183371Simp{
348183371Simp	struct siba_pcib_softc *sc = device_get_softc(dev);
349183371Simp	bus_addr_t cfgaddr;
350183371Simp	uint32_t cfgtag;
351183371Simp	uint32_t val;
352183371Simp
353183371Simp	/* XXX anything higher than slot 2 currently seems to hang the bus.
354183371Simp	 * not sure why this is; look at linux again
355183371Simp	 */
356183371Simp	if (bus != 0 || slot > 2) {
357183371Simp		printf("%s: bad b/s/f %d/%d/%d\n", __func__, bus, slot, func);
358183371Simp		return 0xffffffff;	// XXX
359183371Simp	}
360183371Simp
361183371Simp	device_printf(dev, "requested %d bytes from b/s/f %d/%d/%d reg %d\n",
362183371Simp	    bytes, bus, slot, func, reg);
363183371Simp
364183371Simp	/*
365183371Simp	 * The configuration tag on the broadcom is weird.
366183371Simp	 */
367203319Sweongyo	SBPCI_WRITE_4(sc, SIBA_PCICORE_SBTOPCI1, 2);	/* XXX again??? */
368183371Simp	cfgtag = ((1 << slot) << 16) | (func << 8);
369183371Simp	cfgaddr = SBPCI_CFGBASE | cfgtag | (reg & ~3);
370183371Simp
371183371Simp	/* cfg space i/o is always 32 bits on this bridge */
372183371Simp	printf("reading 4 bytes from %08x\n", cfgaddr);
373183371Simp	val = *(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(cfgaddr); /* XXX MIPS */
374183371Simp
375183371Simp	val = bswap32(val);	/* XXX seems to be needed for now */
376183371Simp
377183371Simp	/* swizzle and return what was asked for */
378183371Simp	val &= 0xffffffff >> ((4 - bytes) * 8);
379183371Simp
380183371Simp	return (val);
381183371Simp}
382183371Simp
383183371Simpstatic void
384183371Simpsiba_pcib_write_config(device_t dev, u_int bus, u_int slot,
385183371Simp    u_int func, u_int reg, u_int32_t val, int bytes)
386183371Simp{
387183371Simp
388183371Simp	/* write to pci configuration space */
389183371Simp	//device_printf(dev, "%s: not yet implemented\n", __func__);
390183371Simp}
391183371Simp
392183371Simpstatic int
393183371Simpsiba_pcib_route_interrupt(device_t bridge, device_t device, int pin)
394183371Simp{
395183371Simp
396183371Simp	//device_printf(bridge, "%s: not yet implemented\n", __func__);
397183371Simp	return (-1);
398183371Simp}
399183371Simp
400183371Simpstatic device_method_t siba_pcib_methods[] = {
401183371Simp	/* Device interface */
402183371Simp	DEVMETHOD(device_attach,	siba_pcib_attach),
403183371Simp	DEVMETHOD(device_probe,		siba_pcib_probe),
404183371Simp
405183371Simp	/* Bus interface */
406183371Simp	DEVMETHOD(bus_read_ivar,	siba_pcib_read_ivar),
407183371Simp	DEVMETHOD(bus_write_ivar,	siba_pcib_write_ivar),
408183371Simp	DEVMETHOD(bus_setup_intr,	siba_pcib_setup_intr),
409183371Simp	DEVMETHOD(bus_teardown_intr,	siba_pcib_teardown_intr),
410183371Simp	DEVMETHOD(bus_alloc_resource,	siba_pcib_alloc_resource),
411183371Simp	DEVMETHOD(bus_activate_resource,	siba_pcib_activate_resource),
412183371Simp	DEVMETHOD(bus_deactivate_resource,	siba_pcib_deactivate_resource),
413183371Simp	DEVMETHOD(bus_release_resource,	siba_pcib_release_resource),
414183371Simp
415183371Simp	/* pcib interface */
416183371Simp	DEVMETHOD(pcib_maxslots,	siba_pcib_maxslots),
417183371Simp	DEVMETHOD(pcib_read_config,	siba_pcib_read_config),
418183371Simp	DEVMETHOD(pcib_write_config,	siba_pcib_write_config),
419183371Simp	DEVMETHOD(pcib_route_interrupt,	siba_pcib_route_interrupt),
420183371Simp
421227843Smarius	DEVMETHOD_END
422183371Simp};
423183371Simp
424183371Simpstatic driver_t siba_pcib_driver = {
425183371Simp	"pcib",
426183371Simp	siba_pcib_methods,
427183371Simp	sizeof(struct siba_softc),
428183371Simp};
429183371Simpstatic devclass_t siba_pcib_devclass;
430183371Simp
431183371SimpDRIVER_MODULE(siba_pcib, siba, siba_pcib_driver, siba_pcib_devclass, 0, 0);
432