1210311Sjmallett/*-
2217254Sjmallett * Copyright (c) 2010-2011 Juli Mallett <jmallett@FreeBSD.org>
3210311Sjmallett * All rights reserved.
4210311Sjmallett *
5210311Sjmallett * Redistribution and use in source and binary forms, with or without
6210311Sjmallett * modification, are permitted provided that the following conditions
7210311Sjmallett * are met:
8210311Sjmallett * 1. Redistributions of source code must retain the above copyright
9210311Sjmallett *    notice, this list of conditions and the following disclaimer.
10210311Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
11210311Sjmallett *    notice, this list of conditions and the following disclaimer in the
12210311Sjmallett *    documentation and/or other materials provided with the distribution.
13210311Sjmallett *
14210311Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15210311Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16210311Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17210311Sjmallett * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18210311Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19210311Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20210311Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21210311Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22210311Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23210311Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24210311Sjmallett * SUCH DAMAGE.
25210311Sjmallett *
26210311Sjmallett * $FreeBSD$
27210311Sjmallett */
28210311Sjmallett
29210311Sjmallett#include <sys/cdefs.h>
30210311Sjmallett__FBSDID("$FreeBSD$");
31210311Sjmallett
32210311Sjmallett#include <sys/param.h>
33210311Sjmallett#include <sys/systm.h>
34210311Sjmallett
35210311Sjmallett#include <sys/bus.h>
36210311Sjmallett#include <sys/endian.h>
37210311Sjmallett#include <sys/interrupt.h>
38210311Sjmallett#include <sys/malloc.h>
39210311Sjmallett#include <sys/kernel.h>
40210311Sjmallett#include <sys/module.h>
41210311Sjmallett#include <sys/rman.h>
42210311Sjmallett
43210311Sjmallett#include <vm/vm.h>
44210311Sjmallett#include <vm/pmap.h>
45210311Sjmallett#include <vm/vm_extern.h>
46210311Sjmallett
47210311Sjmallett#include <machine/bus.h>
48210311Sjmallett#include <machine/cpu.h>
49210311Sjmallett#include <machine/pmap.h>
50210311Sjmallett
51210311Sjmallett#include <contrib/octeon-sdk/cvmx.h>
52210311Sjmallett#include <contrib/octeon-sdk/cvmx-interrupt.h>
53217254Sjmallett#include <contrib/octeon-sdk/cvmx-pcie.h>
54210311Sjmallett
55210311Sjmallett#include <dev/pci/pcireg.h>
56210311Sjmallett#include <dev/pci/pcivar.h>
57210311Sjmallett
58210311Sjmallett#include <dev/pci/pcib_private.h>
59210311Sjmallett
60210311Sjmallett#include <mips/cavium/octopcireg.h>
61210311Sjmallett#include <mips/cavium/octopcivar.h>
62210311Sjmallett
63210311Sjmallett#include "pcib_if.h"
64210311Sjmallett
65213089Sjmallett#define	NPI_WRITE(addr, value)	cvmx_write64_uint32((addr) ^ 4, (value))
66213089Sjmallett#define	NPI_READ(addr)		cvmx_read64_uint32((addr) ^ 4)
67213089Sjmallett
68210311Sjmallettstruct octopci_softc {
69210311Sjmallett	device_t sc_dev;
70210311Sjmallett
71210311Sjmallett	unsigned sc_domain;
72210311Sjmallett	unsigned sc_bus;
73210311Sjmallett
74217254Sjmallett	bus_addr_t sc_io_base;
75213089Sjmallett	unsigned sc_io_next;
76210311Sjmallett	struct rman sc_io;
77213089Sjmallett
78217254Sjmallett	bus_addr_t sc_mem1_base;
79213089Sjmallett	unsigned sc_mem1_next;
80210311Sjmallett	struct rman sc_mem1;
81210311Sjmallett};
82210311Sjmallett
83210311Sjmallettstatic void		octopci_identify(driver_t *, device_t);
84210311Sjmallettstatic int		octopci_probe(device_t);
85210311Sjmallettstatic int		octopci_attach(device_t);
86210311Sjmallettstatic int		octopci_read_ivar(device_t, device_t, int,
87210311Sjmallett					  uintptr_t *);
88210311Sjmallettstatic struct resource	*octopci_alloc_resource(device_t, device_t, int, int *,
89210311Sjmallett						u_long, u_long, u_long, u_int);
90210311Sjmallettstatic int		octopci_activate_resource(device_t, device_t, int, int,
91210311Sjmallett						  struct resource *);
92210311Sjmallettstatic int	octopci_maxslots(device_t);
93210311Sjmallettstatic uint32_t	octopci_read_config(device_t, u_int, u_int, u_int, u_int, int);
94210311Sjmallettstatic void	octopci_write_config(device_t, u_int, u_int, u_int, u_int,
95210311Sjmallett				     uint32_t, int);
96210311Sjmallettstatic int	octopci_route_interrupt(device_t, device_t, int);
97210311Sjmallett
98217254Sjmallettstatic unsigned	octopci_init_bar(device_t, unsigned, unsigned, unsigned, unsigned, uint8_t *);
99213089Sjmallettstatic unsigned	octopci_init_device(device_t, unsigned, unsigned, unsigned, unsigned);
100213089Sjmallettstatic unsigned	octopci_init_bus(device_t, unsigned);
101217254Sjmallettstatic void	octopci_init_pci(device_t);
102210311Sjmallettstatic uint64_t	octopci_cs_addr(unsigned, unsigned, unsigned, unsigned);
103210311Sjmallett
104210311Sjmallettstatic void
105210311Sjmallettoctopci_identify(driver_t *drv, device_t parent)
106210311Sjmallett{
107217254Sjmallett	/* XXX Check sysinfo flag.  */
108217254Sjmallett
109210311Sjmallett	BUS_ADD_CHILD(parent, 0, "pcib", 0);
110217254Sjmallett	if (octeon_has_feature(OCTEON_FEATURE_PCIE))
111217254Sjmallett		BUS_ADD_CHILD(parent, 0, "pcib", 1);
112210311Sjmallett}
113210311Sjmallett
114210311Sjmallettstatic int
115210311Sjmallettoctopci_probe(device_t dev)
116210311Sjmallett{
117217254Sjmallett	if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
118217254Sjmallett		device_set_desc(dev, "Cavium Octeon PCIe bridge");
119217254Sjmallett		return (0);
120217254Sjmallett	}
121217254Sjmallett
122210311Sjmallett	if (device_get_unit(dev) != 0)
123210311Sjmallett		return (ENXIO);
124217254Sjmallett
125210311Sjmallett	device_set_desc(dev, "Cavium Octeon PCI bridge");
126210311Sjmallett	return (0);
127210311Sjmallett}
128210311Sjmallett
129210311Sjmallettstatic int
130210311Sjmallettoctopci_attach(device_t dev)
131210311Sjmallett{
132210311Sjmallett	struct octopci_softc *sc;
133213089Sjmallett	unsigned subbus;
134210311Sjmallett	int error;
135210311Sjmallett
136217254Sjmallett	sc = device_get_softc(dev);
137217254Sjmallett	sc->sc_dev = dev;
138210311Sjmallett
139217254Sjmallett	if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
140217254Sjmallett		sc->sc_domain = device_get_unit(dev);
141213089Sjmallett
142217254Sjmallett		error = cvmx_pcie_rc_initialize(sc->sc_domain);
143217254Sjmallett		if (error != 0) {
144217254Sjmallett			device_printf(dev, "Failed to put PCIe bus in host mode.\n");
145217254Sjmallett			return (ENXIO);
146217254Sjmallett		}
147213089Sjmallett
148217254Sjmallett		/*
149217254Sjmallett		 * In RC mode, the Simple Executive programs the first bus to
150217254Sjmallett		 * be numbered as bus 1, because some IDT bridges used in
151217254Sjmallett		 * Octeon systems object to being attached to bus 0.
152217254Sjmallett		 */
153217254Sjmallett		sc->sc_bus = 1;
154213089Sjmallett
155217254Sjmallett		sc->sc_io_base = CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(sc->sc_domain));
156217254Sjmallett		sc->sc_io.rm_descr = "Cavium Octeon PCIe I/O Ports";
157213089Sjmallett
158217254Sjmallett		sc->sc_mem1_base = CVMX_ADD_IO_SEG(cvmx_pcie_get_mem_base_address(sc->sc_domain));
159217254Sjmallett		sc->sc_mem1.rm_descr = "Cavium Octeon PCIe Memory";
160213089Sjmallett	} else {
161217254Sjmallett		octopci_init_pci(dev);
162213089Sjmallett
163217254Sjmallett		sc->sc_domain = 0;
164217254Sjmallett		sc->sc_bus = 0;
165213089Sjmallett
166217254Sjmallett		sc->sc_io_base = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_IO));
167217254Sjmallett		sc->sc_io.rm_descr = "Cavium Octeon PCI I/O Ports";
168213089Sjmallett
169217254Sjmallett		sc->sc_mem1_base = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_MEM1));
170217254Sjmallett		sc->sc_mem1.rm_descr = "Cavium Octeon PCI Memory";
171213089Sjmallett	}
172213089Sjmallett
173210311Sjmallett	sc->sc_io.rm_type = RMAN_ARRAY;
174210311Sjmallett	error = rman_init(&sc->sc_io);
175210311Sjmallett	if (error != 0)
176210311Sjmallett		return (error);
177210311Sjmallett
178210311Sjmallett	error = rman_manage_region(&sc->sc_io, CVMX_OCT_PCI_IO_BASE,
179210311Sjmallett	    CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE);
180210311Sjmallett	if (error != 0)
181210311Sjmallett		return (error);
182210311Sjmallett
183210311Sjmallett	sc->sc_mem1.rm_type = RMAN_ARRAY;
184210311Sjmallett	error = rman_init(&sc->sc_mem1);
185210311Sjmallett	if (error != 0)
186210311Sjmallett		return (error);
187210311Sjmallett
188210311Sjmallett	error = rman_manage_region(&sc->sc_mem1, CVMX_OCT_PCI_MEM1_BASE,
189210311Sjmallett	    CVMX_OCT_PCI_MEM1_BASE + CVMX_OCT_PCI_MEM1_SIZE);
190210311Sjmallett	if (error != 0)
191210311Sjmallett		return (error);
192210311Sjmallett
193213089Sjmallett	/*
194213089Sjmallett	 * Next offsets for resource allocation in octopci_init_bar.
195213089Sjmallett	 */
196213089Sjmallett	sc->sc_io_next = 0;
197213089Sjmallett	sc->sc_mem1_next = 0;
198213089Sjmallett
199213089Sjmallett	/*
200213089Sjmallett	 * Configure devices.
201213089Sjmallett	 */
202217254Sjmallett	octopci_write_config(dev, sc->sc_bus, 0, 0, PCIR_SUBBUS_1, 0xff, 1);
203217254Sjmallett	subbus = octopci_init_bus(dev, sc->sc_bus);
204217254Sjmallett	octopci_write_config(dev, sc->sc_bus, 0, 0, PCIR_SUBBUS_1, subbus, 1);
205213089Sjmallett
206217254Sjmallett	device_add_child(dev, "pci", device_get_unit(dev));
207210311Sjmallett
208210311Sjmallett	return (bus_generic_attach(dev));
209210311Sjmallett}
210210311Sjmallett
211210311Sjmallettstatic int
212210311Sjmallettoctopci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
213210311Sjmallett{
214210311Sjmallett	struct octopci_softc *sc;
215210311Sjmallett
216210311Sjmallett	sc = device_get_softc(dev);
217210311Sjmallett
218210311Sjmallett	switch (which) {
219210311Sjmallett	case PCIB_IVAR_DOMAIN:
220210311Sjmallett		*result = sc->sc_domain;
221210311Sjmallett		return (0);
222210311Sjmallett	case PCIB_IVAR_BUS:
223210311Sjmallett		*result = sc->sc_bus;
224210311Sjmallett		return (0);
225210311Sjmallett
226210311Sjmallett	}
227210311Sjmallett	return (ENOENT);
228210311Sjmallett}
229210311Sjmallett
230210311Sjmallettstatic struct resource *
231210311Sjmallettoctopci_alloc_resource(device_t bus, device_t child, int type, int *rid,
232210311Sjmallett    u_long start, u_long end, u_long count, u_int flags)
233210311Sjmallett{
234210311Sjmallett	struct octopci_softc *sc;
235210311Sjmallett	struct resource *res;
236210311Sjmallett	struct rman *rm;
237210311Sjmallett	int error;
238210311Sjmallett
239210311Sjmallett	sc = device_get_softc(bus);
240210311Sjmallett
241210311Sjmallett	switch (type) {
242210311Sjmallett	case SYS_RES_IRQ:
243210311Sjmallett		res = bus_generic_alloc_resource(bus, child, type, rid, start,
244210311Sjmallett		    end, count, flags);
245210311Sjmallett		if (res != NULL)
246210311Sjmallett			return (res);
247210311Sjmallett		return (NULL);
248210311Sjmallett	case SYS_RES_MEMORY:
249210311Sjmallett		rm = &sc->sc_mem1;
250210311Sjmallett		break;
251210311Sjmallett	case SYS_RES_IOPORT:
252210311Sjmallett		rm = &sc->sc_io;
253210311Sjmallett		break;
254210311Sjmallett	default:
255210311Sjmallett		return (NULL);
256210311Sjmallett	}
257210311Sjmallett
258210311Sjmallett	res = rman_reserve_resource(rm, start, end, count, flags, child);
259210311Sjmallett	if (res == NULL)
260210311Sjmallett		return (NULL);
261210311Sjmallett
262210311Sjmallett	rman_set_rid(res, *rid);
263210311Sjmallett	rman_set_bustag(res, octopci_bus_space);
264210311Sjmallett
265210311Sjmallett	switch (type) {
266210311Sjmallett	case SYS_RES_MEMORY:
267217254Sjmallett		rman_set_bushandle(res, sc->sc_mem1_base + rman_get_start(res));
268210311Sjmallett		break;
269210311Sjmallett	case SYS_RES_IOPORT:
270217254Sjmallett		rman_set_bushandle(res, sc->sc_io_base + rman_get_start(res));
271213228Sjmallett#if __mips_n64
272213228Sjmallett		rman_set_virtual(res, (void *)rman_get_bushandle(res));
273213228Sjmallett#else
274210311Sjmallett		/*
275210311Sjmallett		 * XXX
276213228Sjmallett		 * We can't access ports via a 32-bit pointer.
277210311Sjmallett		 */
278213228Sjmallett		rman_set_virtual(res, NULL);
279210311Sjmallett#endif
280210311Sjmallett		break;
281210311Sjmallett	}
282210311Sjmallett
283210311Sjmallett	if ((flags & RF_ACTIVE) != 0) {
284210311Sjmallett		error = bus_activate_resource(child, type, *rid, res);
285210311Sjmallett		if (error != 0) {
286210311Sjmallett			rman_release_resource(res);
287210311Sjmallett			return (NULL);
288210311Sjmallett		}
289210311Sjmallett	}
290210311Sjmallett
291210311Sjmallett	return (res);
292210311Sjmallett}
293210311Sjmallett
294210311Sjmallettstatic int
295210311Sjmallettoctopci_activate_resource(device_t bus, device_t child, int type, int rid,
296210311Sjmallett    struct resource *res)
297210311Sjmallett{
298210311Sjmallett	bus_space_handle_t bh;
299210311Sjmallett	int error;
300210311Sjmallett
301210311Sjmallett	switch (type) {
302210311Sjmallett	case SYS_RES_IRQ:
303210311Sjmallett		error = bus_generic_activate_resource(bus, child, type, rid,
304210311Sjmallett						      res);
305210311Sjmallett		if (error != 0)
306210311Sjmallett			return (error);
307210311Sjmallett		return (0);
308210311Sjmallett	case SYS_RES_MEMORY:
309210311Sjmallett	case SYS_RES_IOPORT:
310210311Sjmallett		error = bus_space_map(rman_get_bustag(res),
311210311Sjmallett		    rman_get_bushandle(res), rman_get_size(res), 0, &bh);
312210311Sjmallett		if (error != 0)
313210311Sjmallett			return (error);
314210311Sjmallett		rman_set_bushandle(res, bh);
315210311Sjmallett		break;
316210311Sjmallett	default:
317210311Sjmallett		return (ENXIO);
318210311Sjmallett	}
319210311Sjmallett
320210311Sjmallett	error = rman_activate_resource(res);
321210311Sjmallett	if (error != 0)
322210311Sjmallett		return (error);
323210311Sjmallett	return (0);
324210311Sjmallett}
325210311Sjmallett
326210311Sjmallettstatic int
327210311Sjmallettoctopci_maxslots(device_t dev)
328210311Sjmallett{
329210311Sjmallett	return (PCI_SLOTMAX);
330210311Sjmallett}
331210311Sjmallett
332210311Sjmallettstatic uint32_t
333210311Sjmallettoctopci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
334210311Sjmallett    int bytes)
335210311Sjmallett{
336210311Sjmallett	struct octopci_softc *sc;
337210311Sjmallett	uint64_t addr;
338210311Sjmallett	uint32_t data;
339210311Sjmallett
340210311Sjmallett	sc = device_get_softc(dev);
341210311Sjmallett
342217254Sjmallett	if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
343217254Sjmallett		if (bus == 0 && slot == 0 && func == 0)
344217254Sjmallett			return ((uint32_t)-1);
345217254Sjmallett
346217254Sjmallett		switch (bytes) {
347217254Sjmallett		case 4:
348217254Sjmallett			return (cvmx_pcie_config_read32(sc->sc_domain, bus, slot, func, reg));
349217254Sjmallett		case 2:
350217254Sjmallett			return (cvmx_pcie_config_read16(sc->sc_domain, bus, slot, func, reg));
351217254Sjmallett		case 1:
352217254Sjmallett			return (cvmx_pcie_config_read8(sc->sc_domain, bus, slot, func, reg));
353217254Sjmallett		default:
354217254Sjmallett			return ((uint32_t)-1);
355217254Sjmallett		}
356217254Sjmallett	}
357217254Sjmallett
358210311Sjmallett	addr = octopci_cs_addr(bus, slot, func, reg);
359210311Sjmallett
360210311Sjmallett	switch (bytes) {
361210311Sjmallett	case 4:
362210311Sjmallett		data = le32toh(cvmx_read64_uint32(addr));
363210311Sjmallett		return (data);
364210311Sjmallett	case 2:
365210311Sjmallett		data = le16toh(cvmx_read64_uint16(addr));
366210311Sjmallett		return (data);
367210311Sjmallett	case 1:
368210311Sjmallett		data = cvmx_read64_uint8(addr);
369210311Sjmallett		return (data);
370210311Sjmallett	default:
371210311Sjmallett		return ((uint32_t)-1);
372210311Sjmallett	}
373210311Sjmallett}
374210311Sjmallett
375210311Sjmallettstatic void
376210311Sjmallettoctopci_write_config(device_t dev, u_int bus, u_int slot, u_int func,
377210311Sjmallett    u_int reg, uint32_t data, int bytes)
378210311Sjmallett{
379210311Sjmallett	struct octopci_softc *sc;
380210311Sjmallett	uint64_t addr;
381210311Sjmallett
382210311Sjmallett	sc = device_get_softc(dev);
383210311Sjmallett
384217254Sjmallett	if (octeon_has_feature(OCTEON_FEATURE_PCIE)) {
385217254Sjmallett		switch (bytes) {
386217254Sjmallett		case 4:
387217254Sjmallett			cvmx_pcie_config_write32(sc->sc_domain, bus, slot, func, reg, data);
388217254Sjmallett			return;
389217254Sjmallett		case 2:
390217254Sjmallett			cvmx_pcie_config_write16(sc->sc_domain, bus, slot, func, reg, data);
391217254Sjmallett			return;
392217254Sjmallett		case 1:
393217254Sjmallett			cvmx_pcie_config_write8(sc->sc_domain, bus, slot, func, reg, data);
394217254Sjmallett			return;
395217254Sjmallett		default:
396217254Sjmallett			return;
397217254Sjmallett		}
398217254Sjmallett	}
399217254Sjmallett
400210311Sjmallett	addr = octopci_cs_addr(bus, slot, func, reg);
401210311Sjmallett
402210311Sjmallett	switch (bytes) {
403210311Sjmallett	case 4:
404210311Sjmallett		cvmx_write64_uint32(addr, htole32(data));
405210311Sjmallett		return;
406210311Sjmallett	case 2:
407210311Sjmallett		cvmx_write64_uint16(addr, htole16(data));
408210311Sjmallett		return;
409210311Sjmallett	case 1:
410210311Sjmallett		cvmx_write64_uint8(addr, data);
411210311Sjmallett		return;
412210311Sjmallett	default:
413210311Sjmallett		return;
414210311Sjmallett	}
415210311Sjmallett}
416210311Sjmallett
417210311Sjmallettstatic int
418210311Sjmallettoctopci_route_interrupt(device_t dev, device_t child, int pin)
419210311Sjmallett{
420210311Sjmallett	struct octopci_softc *sc;
421210311Sjmallett	unsigned bus, slot, func;
422210311Sjmallett	unsigned irq;
423210311Sjmallett
424210311Sjmallett	sc = device_get_softc(dev);
425210311Sjmallett
426217254Sjmallett	if (octeon_has_feature(OCTEON_FEATURE_PCIE))
427217254Sjmallett		return (CVMX_IRQ_PCI_INT0 + pin - 1);
428217254Sjmallett
429210311Sjmallett        bus = pci_get_bus(child);
430210311Sjmallett        slot = pci_get_slot(child);
431210311Sjmallett        func = pci_get_function(child);
432210311Sjmallett
433213228Sjmallett	/*
434213228Sjmallett	 * Board types we have to know at compile-time.
435213228Sjmallett	 */
436213228Sjmallett#if defined(OCTEON_BOARD_CAPK_0100ND)
437213228Sjmallett	if (bus == 0 && slot == 12 && func == 0)
438213228Sjmallett		return (CVMX_IRQ_PCI_INT2);
439213228Sjmallett#endif
440213228Sjmallett
441213228Sjmallett	/*
442213228Sjmallett	 * For board types we can determine at runtime.
443213228Sjmallett	 */
444213228Sjmallett	switch (cvmx_sysinfo_get()->board_type) {
445210311Sjmallett#if defined(OCTEON_VENDOR_LANNER)
446213089Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
447213089Sjmallett		return (CVMX_IRQ_PCI_INT0 + pin - 1);
448213089Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
449213089Sjmallett		if (slot < 32) {
450213089Sjmallett			if (slot == 3 || slot == 9)
451213089Sjmallett				irq = pin;
452213089Sjmallett			else
453213089Sjmallett				irq = pin - 1;
454213089Sjmallett			return (CVMX_IRQ_PCI_INT0 + (irq & 3));
455213089Sjmallett		}
456213089Sjmallett		break;
457213228Sjmallett#endif
458213089Sjmallett	default:
459213089Sjmallett		break;
460210311Sjmallett	}
461210311Sjmallett
462210311Sjmallett	irq = slot + pin - 3;
463210311Sjmallett
464210311Sjmallett	return (CVMX_IRQ_PCI_INT0 + (irq & 3));
465210311Sjmallett}
466210311Sjmallett
467217254Sjmallettstatic unsigned
468213228Sjmallettoctopci_init_bar(device_t dev, unsigned b, unsigned s, unsigned f, unsigned barnum, uint8_t *commandp)
469213089Sjmallett{
470213089Sjmallett	struct octopci_softc *sc;
471217254Sjmallett	uint64_t bar;
472213089Sjmallett	unsigned size;
473217254Sjmallett	int barsize;
474213089Sjmallett
475213089Sjmallett	sc = device_get_softc(dev);
476213089Sjmallett
477213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), 0xffffffff, 4);
478213089Sjmallett	bar = octopci_read_config(dev, b, s, f, PCIR_BAR(barnum), 4);
479213089Sjmallett
480213089Sjmallett	if (bar == 0) {
481217254Sjmallett		/* Bar not implemented; got to next bar.  */
482217254Sjmallett		return (barnum + 1);
483213089Sjmallett	}
484213089Sjmallett
485213089Sjmallett	if (PCI_BAR_IO(bar)) {
486213089Sjmallett		size = ~(bar & PCIM_BAR_IO_BASE) + 1;
487213089Sjmallett
488213089Sjmallett		sc->sc_io_next = (sc->sc_io_next + size - 1) & ~(size - 1);
489213089Sjmallett		if (sc->sc_io_next + size > CVMX_OCT_PCI_IO_SIZE) {
490213089Sjmallett			device_printf(dev, "%02x.%02x:%02x: no ports for BAR%u.\n",
491213089Sjmallett			    b, s, f, barnum);
492217254Sjmallett			return (barnum + 1);
493213089Sjmallett		}
494213089Sjmallett		octopci_write_config(dev, b, s, f, PCIR_BAR(barnum),
495213089Sjmallett		    CVMX_OCT_PCI_IO_BASE + sc->sc_io_next, 4);
496213089Sjmallett		sc->sc_io_next += size;
497213228Sjmallett
498213228Sjmallett		/*
499213228Sjmallett		 * Enable I/O ports.
500213228Sjmallett		 */
501213228Sjmallett		*commandp |= PCIM_CMD_PORTEN;
502217254Sjmallett
503217254Sjmallett		return (barnum + 1);
504213089Sjmallett	} else {
505217254Sjmallett		if (PCIR_BAR(barnum) == PCIR_BIOS) {
506217254Sjmallett			/*
507217254Sjmallett			 * ROM BAR is always 32-bit.
508217254Sjmallett			 */
509217254Sjmallett			barsize = 1;
510217254Sjmallett		} else {
511217254Sjmallett			switch (bar & PCIM_BAR_MEM_TYPE) {
512217254Sjmallett			case PCIM_BAR_MEM_64:
513217254Sjmallett				/*
514217254Sjmallett				 * XXX
515217254Sjmallett				 * High 32 bits are all zeroes for now.
516217254Sjmallett				 */
517217254Sjmallett				octopci_write_config(dev, b, s, f, PCIR_BAR(barnum + 1), 0, 4);
518217254Sjmallett				barsize = 2;
519217254Sjmallett				break;
520217254Sjmallett			default:
521217254Sjmallett				barsize = 1;
522217254Sjmallett				break;
523217254Sjmallett			}
524217254Sjmallett		}
525217254Sjmallett
526213089Sjmallett		size = ~(bar & (uint32_t)PCIM_BAR_MEM_BASE) + 1;
527213089Sjmallett
528213089Sjmallett		sc->sc_mem1_next = (sc->sc_mem1_next + size - 1) & ~(size - 1);
529213089Sjmallett		if (sc->sc_mem1_next + size > CVMX_OCT_PCI_MEM1_SIZE) {
530213089Sjmallett			device_printf(dev, "%02x.%02x:%02x: no memory for BAR%u.\n",
531213089Sjmallett			    b, s, f, barnum);
532217254Sjmallett			return (barnum + barsize);
533213089Sjmallett		}
534213089Sjmallett		octopci_write_config(dev, b, s, f, PCIR_BAR(barnum),
535213089Sjmallett		    CVMX_OCT_PCI_MEM1_BASE + sc->sc_mem1_next, 4);
536213089Sjmallett		sc->sc_mem1_next += size;
537213228Sjmallett
538213228Sjmallett		/*
539213228Sjmallett		 * Enable memory access.
540213228Sjmallett		 */
541213228Sjmallett		*commandp |= PCIM_CMD_MEMEN;
542217254Sjmallett
543217254Sjmallett		return (barnum + barsize);
544213089Sjmallett	}
545213089Sjmallett}
546213089Sjmallett
547213089Sjmallettstatic unsigned
548213089Sjmallettoctopci_init_device(device_t dev, unsigned b, unsigned s, unsigned f, unsigned secbus)
549213089Sjmallett{
550213089Sjmallett	unsigned barnum, bars;
551213089Sjmallett	uint8_t brctl;
552213089Sjmallett	uint8_t class, subclass;
553213089Sjmallett	uint8_t command;
554213089Sjmallett	uint8_t hdrtype;
555213089Sjmallett
556213089Sjmallett	/* Read header type (again.)  */
557213089Sjmallett	hdrtype = octopci_read_config(dev, b, s, f, PCIR_HDRTYPE, 1);
558213089Sjmallett
559213228Sjmallett	/*
560213228Sjmallett	 * Disable memory and I/O while programming BARs.
561213228Sjmallett	 */
562213228Sjmallett	command = octopci_read_config(dev, b, s, f, PCIR_COMMAND, 1);
563213228Sjmallett	command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN);
564213228Sjmallett	octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1);
565213228Sjmallett
566213230Sjmallett	DELAY(10000);
567213230Sjmallett
568213089Sjmallett	/* Program BARs.  */
569213089Sjmallett	switch (hdrtype & PCIM_HDRTYPE) {
570213089Sjmallett	case PCIM_HDRTYPE_NORMAL:
571213089Sjmallett		bars = 6;
572213089Sjmallett		break;
573213089Sjmallett	case PCIM_HDRTYPE_BRIDGE:
574213089Sjmallett		bars = 2;
575213089Sjmallett		break;
576213089Sjmallett	case PCIM_HDRTYPE_CARDBUS:
577213089Sjmallett		bars = 0;
578213089Sjmallett		break;
579213089Sjmallett	default:
580213089Sjmallett		device_printf(dev, "%02x.%02x:%02x: invalid header type %#x\n",
581213089Sjmallett		    b, s, f, hdrtype);
582213089Sjmallett		return (secbus);
583213089Sjmallett	}
584213089Sjmallett
585217254Sjmallett	barnum = 0;
586217254Sjmallett	while (barnum < bars)
587217254Sjmallett		barnum = octopci_init_bar(dev, b, s, f, barnum, &command);
588213089Sjmallett
589213089Sjmallett	/* Enable bus mastering.  */
590213089Sjmallett	command |= PCIM_CMD_BUSMASTEREN;
591213228Sjmallett
592213228Sjmallett	/* Enable whatever facilities the BARs require.  */
593213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1);
594213089Sjmallett
595213230Sjmallett	DELAY(10000);
596213230Sjmallett
597213090Sjmallett	/*
598213090Sjmallett	 * Set cache line size.  On Octeon it should be 128 bytes,
599213090Sjmallett	 * but according to Linux some Intel bridges have trouble
600213090Sjmallett	 * with values over 64 bytes, so use 64 bytes.
601213090Sjmallett	 */
602213090Sjmallett	octopci_write_config(dev, b, s, f, PCIR_CACHELNSZ, 16, 1);
603213090Sjmallett
604213090Sjmallett	/* Set latency timer.  */
605213090Sjmallett	octopci_write_config(dev, b, s, f, PCIR_LATTIMER, 48, 1);
606213090Sjmallett
607213228Sjmallett	/* Board-specific or device-specific fixups and workarounds.  */
608213228Sjmallett	switch (cvmx_sysinfo_get()->board_type) {
609213228Sjmallett#if defined(OCTEON_VENDOR_LANNER)
610213228Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
611213228Sjmallett		if (b == 1 && s == 7 && f == 0) {
612213228Sjmallett			bus_addr_t busaddr, unitbusaddr;
613213228Sjmallett			uint32_t bar;
614213228Sjmallett			uint32_t tmp;
615213228Sjmallett			unsigned unit;
616213228Sjmallett
617213228Sjmallett			/*
618213228Sjmallett			 * Set Tx DMA power.
619213228Sjmallett			 */
620213228Sjmallett			bar = octopci_read_config(dev, b, s, f,
621213228Sjmallett			    PCIR_BAR(3), 4);
622213228Sjmallett			busaddr = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI,
623213228Sjmallett			    CVMX_OCT_SUBDID_PCI_MEM1));
624213228Sjmallett			busaddr += (bar & (uint32_t)PCIM_BAR_MEM_BASE);
625213228Sjmallett			for (unit = 0; unit < 4; unit++) {
626213228Sjmallett				unitbusaddr = busaddr + 0x430 + (unit << 8);
627213228Sjmallett				tmp = le32toh(cvmx_read64_uint32(unitbusaddr));
628213228Sjmallett				tmp &= ~0x700;
629213228Sjmallett				tmp |= 0x300;
630213228Sjmallett				cvmx_write64_uint32(unitbusaddr, htole32(tmp));
631213228Sjmallett			}
632213228Sjmallett		}
633213228Sjmallett		break;
634213228Sjmallett#endif
635213228Sjmallett	default:
636213228Sjmallett		break;
637213228Sjmallett	}
638213228Sjmallett
639213089Sjmallett	/* Configure PCI-PCI bridges.  */
640213089Sjmallett	class = octopci_read_config(dev, b, s, f, PCIR_CLASS, 1);
641213089Sjmallett	if (class != PCIC_BRIDGE)
642213089Sjmallett		return (secbus);
643213089Sjmallett
644213089Sjmallett	subclass = octopci_read_config(dev, b, s, f, PCIR_SUBCLASS, 1);
645213089Sjmallett	if (subclass != PCIS_BRIDGE_PCI)
646213089Sjmallett		return (secbus);
647213089Sjmallett
648213228Sjmallett	/* Enable memory and I/O access.  */
649213228Sjmallett	command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
650213228Sjmallett	octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1);
651213228Sjmallett
652213089Sjmallett	/* Enable errors and parity checking.  Do a bus reset.  */
653213089Sjmallett	brctl = octopci_read_config(dev, b, s, f, PCIR_BRIDGECTL_1, 1);
654213089Sjmallett	brctl |= PCIB_BCR_PERR_ENABLE | PCIB_BCR_SERR_ENABLE;
655213089Sjmallett
656213089Sjmallett	/* Perform a secondary bus reset.  */
657213089Sjmallett	brctl |= PCIB_BCR_SECBUS_RESET;
658213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1);
659213089Sjmallett	DELAY(100000);
660213089Sjmallett	brctl &= ~PCIB_BCR_SECBUS_RESET;
661213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1);
662213089Sjmallett
663213089Sjmallett	secbus++;
664213089Sjmallett
665213089Sjmallett	/* Program memory and I/O ranges.  */
666213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_MEMBASE_1,
667213089Sjmallett	    CVMX_OCT_PCI_MEM1_BASE >> 16, 2);
668213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_MEMLIMIT_1,
669213089Sjmallett	    (CVMX_OCT_PCI_MEM1_BASE + CVMX_OCT_PCI_MEM1_SIZE - 1) >> 16, 2);
670213089Sjmallett
671213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_IOBASEL_1,
672213089Sjmallett	    CVMX_OCT_PCI_IO_BASE >> 8, 1);
673213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_IOBASEH_1,
674213089Sjmallett	    CVMX_OCT_PCI_IO_BASE >> 16, 2);
675213089Sjmallett
676213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_IOLIMITL_1,
677213089Sjmallett	    (CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE - 1) >> 8, 1);
678213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_IOLIMITH_1,
679213089Sjmallett	    (CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE - 1) >> 16, 2);
680213089Sjmallett
681213089Sjmallett	/* Program prefetchable memory decoder.  */
682213089Sjmallett	/* XXX */
683213089Sjmallett
684213089Sjmallett	/* Probe secondary/subordinate buses.  */
685213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_PRIBUS_1, b, 1);
686213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_SECBUS_1, secbus, 1);
687213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_SUBBUS_1, 0xff, 1);
688213089Sjmallett
689213089Sjmallett	/* Perform a secondary bus reset.  */
690213089Sjmallett	brctl |= PCIB_BCR_SECBUS_RESET;
691213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1);
692213089Sjmallett	DELAY(100000);
693213089Sjmallett	brctl &= ~PCIB_BCR_SECBUS_RESET;
694213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1);
695213089Sjmallett
696213089Sjmallett	/* Give the bus time to settle now before reading configspace.  */
697213089Sjmallett	DELAY(100000);
698213089Sjmallett
699213089Sjmallett	secbus = octopci_init_bus(dev, secbus);
700213089Sjmallett
701213089Sjmallett	octopci_write_config(dev, b, s, f, PCIR_SUBBUS_1, secbus, 1);
702213089Sjmallett
703213089Sjmallett	return (secbus);
704213089Sjmallett}
705213089Sjmallett
706213089Sjmallettstatic unsigned
707213089Sjmallettoctopci_init_bus(device_t dev, unsigned b)
708213089Sjmallett{
709213089Sjmallett	unsigned s, f;
710213089Sjmallett	uint8_t hdrtype;
711213089Sjmallett	unsigned secbus;
712213089Sjmallett
713213089Sjmallett	secbus = b;
714213089Sjmallett
715213089Sjmallett	for (s = 0; s <= PCI_SLOTMAX; s++) {
716213089Sjmallett		for (f = 0; f <= PCI_FUNCMAX; f++) {
717213089Sjmallett			hdrtype = octopci_read_config(dev, b, s, f, PCIR_HDRTYPE, 1);
718213089Sjmallett
719213089Sjmallett			if (hdrtype == 0xff) {
720213089Sjmallett				if (f == 0)
721213089Sjmallett					break; /* Next slot.  */
722213089Sjmallett				continue; /* Next function.  */
723213089Sjmallett			}
724213089Sjmallett
725213089Sjmallett			secbus = octopci_init_device(dev, b, s, f, secbus);
726213089Sjmallett
727213089Sjmallett			if (f == 0 && (hdrtype & PCIM_MFDEV) == 0)
728213089Sjmallett				break; /* Next slot.  */
729213089Sjmallett		}
730213089Sjmallett	}
731213089Sjmallett
732213089Sjmallett	return (secbus);
733213089Sjmallett}
734213089Sjmallett
735210311Sjmallettstatic uint64_t
736210311Sjmallettoctopci_cs_addr(unsigned bus, unsigned slot, unsigned func, unsigned reg)
737210311Sjmallett{
738210311Sjmallett	octeon_pci_config_space_address_t pci_addr;
739210311Sjmallett
740210311Sjmallett	pci_addr.u64 = 0;
741210311Sjmallett	pci_addr.s.upper = 2;
742210311Sjmallett	pci_addr.s.io = 1;
743210311Sjmallett	pci_addr.s.did = 3;
744210311Sjmallett	pci_addr.s.subdid = CVMX_OCT_SUBDID_PCI_CFG;
745210311Sjmallett	pci_addr.s.endian_swap = 1;
746210311Sjmallett	pci_addr.s.bus = bus;
747210311Sjmallett	pci_addr.s.dev = slot;
748210311Sjmallett	pci_addr.s.func = func;
749210311Sjmallett	pci_addr.s.reg = reg;
750210311Sjmallett
751210311Sjmallett	return (pci_addr.u64);
752210311Sjmallett}
753210311Sjmallett
754217254Sjmallettstatic void
755217254Sjmallettoctopci_init_pci(device_t dev)
756217254Sjmallett{
757217254Sjmallett	cvmx_npi_mem_access_subid_t npi_mem_access_subid;
758217254Sjmallett	cvmx_npi_pci_int_arb_cfg_t npi_pci_int_arb_cfg;
759217254Sjmallett	cvmx_npi_ctl_status_t npi_ctl_status;
760217254Sjmallett	cvmx_pci_ctl_status_2_t pci_ctl_status_2;
761217254Sjmallett	cvmx_pci_cfg56_t pci_cfg56;
762217254Sjmallett	cvmx_pci_cfg22_t pci_cfg22;
763217254Sjmallett	cvmx_pci_cfg16_t pci_cfg16;
764217254Sjmallett	cvmx_pci_cfg19_t pci_cfg19;
765217254Sjmallett	cvmx_pci_cfg01_t pci_cfg01;
766217254Sjmallett	unsigned i;
767217254Sjmallett
768217254Sjmallett	/*
769217254Sjmallett	 * Reset the PCI bus.
770217254Sjmallett	 */
771217254Sjmallett	cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x1);
772217254Sjmallett	cvmx_read_csr(CVMX_CIU_SOFT_PRST);
773217254Sjmallett
774217254Sjmallett	DELAY(2000);
775217254Sjmallett
776217254Sjmallett	npi_ctl_status.u64 = 0;
777217254Sjmallett	npi_ctl_status.s.max_word = 1;
778217254Sjmallett	npi_ctl_status.s.timer = 1;
779217254Sjmallett	cvmx_write_csr(CVMX_NPI_CTL_STATUS, npi_ctl_status.u64);
780217254Sjmallett
781217254Sjmallett	/*
782217254Sjmallett	 * Set host mode.
783217254Sjmallett	 */
784217254Sjmallett	switch (cvmx_sysinfo_get()->board_type) {
785217254Sjmallett#if defined(OCTEON_VENDOR_LANNER)
786217254Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
787217254Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
788217254Sjmallett		/* 32-bit PCI-X */
789217254Sjmallett		cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x0);
790217254Sjmallett		break;
791217254Sjmallett#endif
792217254Sjmallett	default:
793217254Sjmallett		/* 64-bit PCI-X */
794217254Sjmallett		cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x4);
795217254Sjmallett		break;
796217254Sjmallett	}
797217254Sjmallett	cvmx_read_csr(CVMX_CIU_SOFT_PRST);
798217254Sjmallett
799217254Sjmallett	DELAY(2000);
800217254Sjmallett
801217254Sjmallett	/*
802217254Sjmallett	 * Enable BARs and configure big BAR mode.
803217254Sjmallett	 */
804217254Sjmallett	pci_ctl_status_2.u32 = 0;
805217254Sjmallett	pci_ctl_status_2.s.bb1_hole = 5; /* 256MB hole in BAR1 */
806217254Sjmallett	pci_ctl_status_2.s.bb1_siz = 1; /* BAR1 is 2GB */
807217254Sjmallett	pci_ctl_status_2.s.bb_ca = 1; /* Bypass cache for big BAR */
808217254Sjmallett	pci_ctl_status_2.s.bb_es = 1; /* Do big BAR byte-swapping */
809217254Sjmallett	pci_ctl_status_2.s.bb1 = 1; /* BAR1 is big */
810217254Sjmallett	pci_ctl_status_2.s.bb0 = 1; /* BAR0 is big */
811217254Sjmallett	pci_ctl_status_2.s.bar2pres = 1; /* BAR2 present */
812217254Sjmallett	pci_ctl_status_2.s.pmo_amod = 1; /* Round-robin priority */
813217254Sjmallett	pci_ctl_status_2.s.tsr_hwm = 1;
814217254Sjmallett	pci_ctl_status_2.s.bar2_enb = 1; /* Enable BAR2 */
815217254Sjmallett	pci_ctl_status_2.s.bar2_esx = 1; /* Do BAR2 byte-swapping */
816217254Sjmallett	pci_ctl_status_2.s.bar2_cax = 1; /* Bypass cache for BAR2 */
817217254Sjmallett
818217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CTL_STATUS_2, pci_ctl_status_2.u32);
819217254Sjmallett
820217254Sjmallett	DELAY(2000);
821217254Sjmallett
822217254Sjmallett	pci_ctl_status_2.u32 = NPI_READ(CVMX_NPI_PCI_CTL_STATUS_2);
823217254Sjmallett
824217254Sjmallett	device_printf(dev, "%u-bit PCI%s bus.\n",
825217254Sjmallett	    pci_ctl_status_2.s.ap_64ad ? 64 : 32,
826217254Sjmallett	    pci_ctl_status_2.s.ap_pcix ? "-X" : "");
827217254Sjmallett
828217254Sjmallett	/*
829217254Sjmallett	 * Set up transaction splitting, etc., parameters.
830217254Sjmallett	 */
831217254Sjmallett	pci_cfg19.u32 = 0;
832217254Sjmallett	pci_cfg19.s.mrbcm = 1;
833217254Sjmallett	if (pci_ctl_status_2.s.ap_pcix) {
834217254Sjmallett		pci_cfg19.s.mdrrmc = 0;
835217254Sjmallett		pci_cfg19.s.tdomc = 4;
836217254Sjmallett	} else {
837217254Sjmallett		pci_cfg19.s.mdrrmc = 2;
838217254Sjmallett		pci_cfg19.s.tdomc = 1;
839217254Sjmallett	}
840217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CFG19, pci_cfg19.u32);
841217254Sjmallett	NPI_READ(CVMX_NPI_PCI_CFG19);
842217254Sjmallett
843217254Sjmallett	/*
844217254Sjmallett	 * Set up PCI error handling and memory access.
845217254Sjmallett	 */
846217254Sjmallett	pci_cfg01.u32 = 0;
847217254Sjmallett	pci_cfg01.s.fbbe = 1;
848217254Sjmallett	pci_cfg01.s.see = 1;
849217254Sjmallett	pci_cfg01.s.pee = 1;
850217254Sjmallett	pci_cfg01.s.me = 1;
851217254Sjmallett	pci_cfg01.s.msae = 1;
852217254Sjmallett	if (pci_ctl_status_2.s.ap_pcix) {
853217254Sjmallett		pci_cfg01.s.fbb = 0;
854217254Sjmallett	} else {
855217254Sjmallett		pci_cfg01.s.fbb = 1;
856217254Sjmallett	}
857217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CFG01, pci_cfg01.u32);
858217254Sjmallett	NPI_READ(CVMX_NPI_PCI_CFG01);
859217254Sjmallett
860217254Sjmallett	/*
861217254Sjmallett	 * Enable the Octeon bus arbiter.
862217254Sjmallett	 */
863217254Sjmallett	npi_pci_int_arb_cfg.u64 = 0;
864217254Sjmallett	npi_pci_int_arb_cfg.s.en = 1;
865217254Sjmallett	cvmx_write_csr(CVMX_NPI_PCI_INT_ARB_CFG, npi_pci_int_arb_cfg.u64);
866217254Sjmallett
867217254Sjmallett	/*
868217254Sjmallett	 * Disable master latency timer.
869217254Sjmallett	 */
870217254Sjmallett	pci_cfg16.u32 = 0;
871217254Sjmallett	pci_cfg16.s.mltd = 1;
872217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CFG16, pci_cfg16.u32);
873217254Sjmallett	NPI_READ(CVMX_NPI_PCI_CFG16);
874217254Sjmallett
875217254Sjmallett	/*
876217254Sjmallett	 * Configure master arbiter.
877217254Sjmallett	 */
878217254Sjmallett	pci_cfg22.u32 = 0;
879217254Sjmallett	pci_cfg22.s.flush = 1;
880217254Sjmallett	pci_cfg22.s.mrv = 255;
881217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CFG22, pci_cfg22.u32);
882217254Sjmallett	NPI_READ(CVMX_NPI_PCI_CFG22);
883217254Sjmallett
884217254Sjmallett	/*
885217254Sjmallett	 * Set up PCI-X capabilities.
886217254Sjmallett	 */
887217254Sjmallett	if (pci_ctl_status_2.s.ap_pcix) {
888217254Sjmallett		pci_cfg56.u32 = 0;
889217254Sjmallett		pci_cfg56.s.most = 3;
890217254Sjmallett		pci_cfg56.s.roe = 1; /* Enable relaxed ordering */
891217254Sjmallett		pci_cfg56.s.dpere = 1;
892217254Sjmallett		pci_cfg56.s.ncp = 0xe8;
893217254Sjmallett		pci_cfg56.s.pxcid = 7;
894217254Sjmallett		NPI_WRITE(CVMX_NPI_PCI_CFG56, pci_cfg56.u32);
895217254Sjmallett		NPI_READ(CVMX_NPI_PCI_CFG56);
896217254Sjmallett	}
897217254Sjmallett
898217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_READ_CMD_6, 0x22);
899217254Sjmallett	NPI_READ(CVMX_NPI_PCI_READ_CMD_6);
900217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_READ_CMD_C, 0x33);
901217254Sjmallett	NPI_READ(CVMX_NPI_PCI_READ_CMD_C);
902217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_READ_CMD_E, 0x33);
903217254Sjmallett	NPI_READ(CVMX_NPI_PCI_READ_CMD_E);
904217254Sjmallett
905217254Sjmallett	/*
906217254Sjmallett	 * Configure MEM1 sub-DID access.
907217254Sjmallett	 */
908217254Sjmallett	npi_mem_access_subid.u64 = 0;
909217254Sjmallett	npi_mem_access_subid.s.esr = 1; /* Byte-swap on read */
910217254Sjmallett	npi_mem_access_subid.s.esw = 1; /* Byte-swap on write */
911217254Sjmallett	switch (cvmx_sysinfo_get()->board_type) {
912217254Sjmallett#if defined(OCTEON_VENDOR_LANNER)
913217254Sjmallett	case CVMX_BOARD_TYPE_CUST_LANNER_MR955:
914217254Sjmallett		npi_mem_access_subid.s.shortl = 1;
915217254Sjmallett		break;
916217254Sjmallett#endif
917217254Sjmallett	default:
918217254Sjmallett		break;
919217254Sjmallett	}
920217254Sjmallett	cvmx_write_csr(CVMX_NPI_MEM_ACCESS_SUBID3, npi_mem_access_subid.u64);
921217254Sjmallett
922217254Sjmallett	/*
923217254Sjmallett	 * Configure BAR2.  Linux says this has to come first.
924217254Sjmallett	 */
925217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CFG08, 0x00000000);
926217254Sjmallett	NPI_READ(CVMX_NPI_PCI_CFG08);
927217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CFG09, 0x00000080);
928217254Sjmallett	NPI_READ(CVMX_NPI_PCI_CFG09);
929217254Sjmallett
930217254Sjmallett	/*
931217254Sjmallett	 * Disable BAR1 IndexX.
932217254Sjmallett	 */
933217254Sjmallett	for (i = 0; i < 32; i++) {
934217254Sjmallett		NPI_WRITE(CVMX_NPI_PCI_BAR1_INDEXX(i), 0);
935217254Sjmallett		NPI_READ(CVMX_NPI_PCI_BAR1_INDEXX(i));
936217254Sjmallett	}
937217254Sjmallett
938217254Sjmallett	/*
939217254Sjmallett	 * Configure BAR0 and BAR1.
940217254Sjmallett	 */
941217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CFG04, 0x00000000);
942217254Sjmallett	NPI_READ(CVMX_NPI_PCI_CFG04);
943217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CFG05, 0x00000000);
944217254Sjmallett	NPI_READ(CVMX_NPI_PCI_CFG05);
945217254Sjmallett
946217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CFG06, 0x80000000);
947217254Sjmallett	NPI_READ(CVMX_NPI_PCI_CFG06);
948217254Sjmallett	NPI_WRITE(CVMX_NPI_PCI_CFG07, 0x00000000);
949217254Sjmallett	NPI_READ(CVMX_NPI_PCI_CFG07);
950217254Sjmallett
951217254Sjmallett	/*
952217254Sjmallett	 * Clear PCI interrupts.
953217254Sjmallett	 */
954217254Sjmallett	cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, 0xffffffffffffffffull);
955217254Sjmallett}
956217254Sjmallett
957210311Sjmallettstatic device_method_t octopci_methods[] = {
958210311Sjmallett	/* Device interface */
959210311Sjmallett	DEVMETHOD(device_identify,	octopci_identify),
960210311Sjmallett	DEVMETHOD(device_probe,		octopci_probe),
961210311Sjmallett	DEVMETHOD(device_attach,	octopci_attach),
962210311Sjmallett
963210311Sjmallett	/* Bus interface */
964210311Sjmallett	DEVMETHOD(bus_read_ivar,	octopci_read_ivar),
965210311Sjmallett	DEVMETHOD(bus_alloc_resource,	octopci_alloc_resource),
966210311Sjmallett	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
967210311Sjmallett	DEVMETHOD(bus_activate_resource,octopci_activate_resource),
968210311Sjmallett	DEVMETHOD(bus_deactivate_resource,bus_generic_deactivate_resource),
969210311Sjmallett	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
970213090Sjmallett	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
971210311Sjmallett
972212843Sjmallett	DEVMETHOD(bus_add_child,	bus_generic_add_child),
973212843Sjmallett
974210311Sjmallett	/* pcib interface */
975210311Sjmallett	DEVMETHOD(pcib_maxslots,	octopci_maxslots),
976210311Sjmallett	DEVMETHOD(pcib_read_config,	octopci_read_config),
977210311Sjmallett	DEVMETHOD(pcib_write_config,	octopci_write_config),
978210311Sjmallett	DEVMETHOD(pcib_route_interrupt,	octopci_route_interrupt),
979210311Sjmallett
980229093Shselasky	DEVMETHOD_END
981210311Sjmallett};
982210311Sjmallett
983210311Sjmallettstatic driver_t octopci_driver = {
984210311Sjmallett	"pcib",
985210311Sjmallett	octopci_methods,
986210311Sjmallett	sizeof(struct octopci_softc),
987210311Sjmallett};
988210311Sjmallettstatic devclass_t octopci_devclass;
989210311SjmallettDRIVER_MODULE(octopci, ciu, octopci_driver, octopci_devclass, 0, 0);
990