1208747Sraj/*-
2208747Sraj * Copyright (c) 2010 The FreeBSD Foundation
3208747Sraj * All rights reserved.
4208747Sraj *
5208747Sraj * This software was developed by Semihalf under sponsorship from
6208747Sraj * the FreeBSD Foundation.
7208747Sraj *
8208747Sraj * Redistribution and use in source and binary forms, with or without
9208747Sraj * modification, are permitted provided that the following conditions
10208747Sraj * are met:
11208747Sraj * 1. Redistributions of source code must retain the above copyright
12208747Sraj *    notice, this list of conditions and the following disclaimer.
13208747Sraj * 2. Redistributions in binary form must reproduce the above copyright
14208747Sraj *    notice, this list of conditions and the following disclaimer in the
15208747Sraj *    documentation and/or other materials provided with the distribution.
16208747Sraj *
17208747Sraj * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18208747Sraj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19208747Sraj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20208747Sraj * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21208747Sraj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22208747Sraj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23208747Sraj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24208747Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25208747Sraj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26208747Sraj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27208747Sraj * SUCH DAMAGE.
28208747Sraj */
29208747Sraj
30208747Sraj#include <sys/cdefs.h>
31208747Sraj__FBSDID("$FreeBSD$");
32208747Sraj
33208747Sraj#include <sys/param.h>
34208747Sraj#include <sys/systm.h>
35208747Sraj#include <sys/ktr.h>
36208747Sraj#include <sys/kernel.h>
37208747Sraj#include <sys/bus.h>
38208747Sraj#include <sys/rman.h>
39208747Sraj#include <sys/malloc.h>
40208747Sraj
41208747Sraj#include <dev/fdt/fdt_common.h>
42218077Smarcel#include <dev/pci/pcireg.h>
43208747Sraj
44208747Sraj#include <machine/fdt.h>
45208747Sraj
46208747Sraj#include "ofw_bus_if.h"
47218077Smarcel#include "pcib_if.h"
48208747Sraj
49208747Sraj#define DEBUG
50208747Sraj#undef DEBUG
51208747Sraj
52208747Sraj#ifdef DEBUG
53208747Sraj#define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
54208747Sraj    printf(fmt,##args); } while (0)
55208747Sraj#else
56208747Sraj#define debugf(fmt, args...)
57208747Sraj#endif
58208747Sraj
59208747Sraj#define FDT_RANGES_CELLS	((3 + 3 + 2) * 2)
60208747Sraj
61208747Srajstatic void
62208747Srajfdt_pci_range_dump(struct fdt_pci_range *range)
63208747Sraj{
64208747Sraj#ifdef DEBUG
65208747Sraj	printf("\n");
66208747Sraj	printf("  base_pci = 0x%08lx\n", range->base_pci);
67208747Sraj	printf("  base_par = 0x%08lx\n", range->base_parent);
68208747Sraj	printf("  len      = 0x%08lx\n", range->len);
69208747Sraj#endif
70208747Sraj}
71208747Sraj
72208747Srajint
73208747Srajfdt_pci_ranges_decode(phandle_t node, struct fdt_pci_range *io_space,
74208747Sraj    struct fdt_pci_range *mem_space)
75208747Sraj{
76208747Sraj	pcell_t ranges[FDT_RANGES_CELLS];
77208747Sraj	struct fdt_pci_range *pci_space;
78208747Sraj	pcell_t addr_cells, size_cells, par_addr_cells;
79208747Sraj	pcell_t *rangesptr;
80208747Sraj	pcell_t cell0, cell1, cell2;
81208747Sraj	int tuple_size, tuples, i, rv, offset_cells, len;
82208747Sraj
83208747Sraj	/*
84208747Sraj	 * Retrieve 'ranges' property.
85208747Sraj	 */
86208747Sraj	if ((fdt_addrsize_cells(node, &addr_cells, &size_cells)) != 0)
87208747Sraj		return (EINVAL);
88208747Sraj	if (addr_cells != 3 || size_cells != 2)
89208747Sraj		return (ERANGE);
90208747Sraj
91208747Sraj	par_addr_cells = fdt_parent_addr_cells(node);
92208747Sraj	if (par_addr_cells > 3)
93208747Sraj		return (ERANGE);
94208747Sraj
95208747Sraj	len = OF_getproplen(node, "ranges");
96208747Sraj	if (len > sizeof(ranges))
97208747Sraj		return (ENOMEM);
98208747Sraj
99208747Sraj	if (OF_getprop(node, "ranges", ranges, sizeof(ranges)) <= 0)
100208747Sraj		return (EINVAL);
101208747Sraj
102208747Sraj	tuple_size = sizeof(pcell_t) * (addr_cells + par_addr_cells +
103208747Sraj	    size_cells);
104208747Sraj	tuples = len / tuple_size;
105208747Sraj
106208747Sraj	rangesptr = &ranges[0];
107208747Sraj	offset_cells = 0;
108208747Sraj	for (i = 0; i < tuples; i++) {
109208747Sraj		cell0 = fdt_data_get((void *)rangesptr, 1);
110208747Sraj		rangesptr++;
111208747Sraj		cell1 = fdt_data_get((void *)rangesptr, 1);
112208747Sraj		rangesptr++;
113208747Sraj		cell2 = fdt_data_get((void *)rangesptr, 1);
114208747Sraj		rangesptr++;
115208747Sraj
116208747Sraj		if (cell0 & 0x02000000) {
117208747Sraj			pci_space = mem_space;
118208747Sraj		} else if (cell0 & 0x01000000) {
119208747Sraj			pci_space = io_space;
120208747Sraj		} else {
121208747Sraj			rv = ERANGE;
122208747Sraj			goto out;
123208747Sraj		}
124208747Sraj
125208747Sraj		if (par_addr_cells == 3) {
126208747Sraj			/*
127208747Sraj			 * This is a PCI subnode 'ranges'. Skip cell0 and
128208747Sraj			 * cell1 of this entry and only use cell2.
129208747Sraj			 */
130208747Sraj			offset_cells = 2;
131208747Sraj			rangesptr += offset_cells;
132208747Sraj		}
133208747Sraj
134208747Sraj		if (fdt_data_verify((void *)rangesptr, par_addr_cells -
135208747Sraj		    offset_cells)) {
136208747Sraj			rv = ERANGE;
137208747Sraj			goto out;
138208747Sraj		}
139208747Sraj		pci_space->base_parent = fdt_data_get((void *)rangesptr,
140208747Sraj		    par_addr_cells - offset_cells);
141208747Sraj		rangesptr += par_addr_cells - offset_cells;
142208747Sraj
143208747Sraj		if (fdt_data_verify((void *)rangesptr, size_cells)) {
144208747Sraj			rv = ERANGE;
145208747Sraj			goto out;
146208747Sraj		}
147208747Sraj		pci_space->len = fdt_data_get((void *)rangesptr, size_cells);
148208747Sraj		rangesptr += size_cells;
149208747Sraj
150208747Sraj		pci_space->base_pci = cell2;
151208747Sraj	}
152208747Sraj	rv = 0;
153208747Srajout:
154208747Sraj	return (rv);
155208747Sraj}
156208747Sraj
157208747Srajint
158208747Srajfdt_pci_ranges(phandle_t node, struct fdt_pci_range *io_space,
159208747Sraj    struct fdt_pci_range *mem_space)
160208747Sraj{
161208747Sraj	int err;
162208747Sraj
163218077Smarcel	debugf("Processing PCI node: %x\n", node);
164218077Smarcel	if ((err = fdt_pci_ranges_decode(node, io_space, mem_space)) != 0) {
165208747Sraj		debugf("could not decode parent PCI node 'ranges'\n");
166208747Sraj		return (err);
167208747Sraj	}
168208747Sraj
169208747Sraj	debugf("Post fixup dump:\n");
170208747Sraj	fdt_pci_range_dump(io_space);
171208747Sraj	fdt_pci_range_dump(mem_space);
172208747Sraj	return (0);
173208747Sraj}
174208747Sraj
175208747Srajstatic int
176208747Srajfdt_addr_cells(phandle_t node, int *addr_cells)
177208747Sraj{
178208747Sraj	pcell_t cell;
179208747Sraj	int cell_size;
180208747Sraj
181208747Sraj	cell_size = sizeof(cell);
182208747Sraj	if (OF_getprop(node, "#address-cells", &cell, cell_size) < cell_size)
183208747Sraj		return (EINVAL);
184208747Sraj	*addr_cells = fdt32_to_cpu((int)cell);
185208747Sraj
186208747Sraj	if (*addr_cells > 3)
187208747Sraj		return (ERANGE);
188208747Sraj	return (0);
189208747Sraj}
190208747Sraj
191208747Srajstatic int
192208747Srajfdt_interrupt_cells(phandle_t node)
193208747Sraj{
194208747Sraj	pcell_t intr_cells;
195208747Sraj
196208747Sraj	if (OF_getprop(node, "#interrupt-cells", &intr_cells,
197208747Sraj	    sizeof(intr_cells)) <= 0) {
198208747Sraj		debugf("no intr-cells defined, defaulting to 1\n");
199208747Sraj		intr_cells = 1;
200208747Sraj	}
201208747Sraj	intr_cells = fdt32_to_cpu(intr_cells);
202208747Sraj
203208747Sraj	return ((int)intr_cells);
204208747Sraj}
205208747Sraj
206208747Srajint
207208747Srajfdt_pci_intr_info(phandle_t node, struct fdt_pci_intr *intr_info)
208208747Sraj{
209208747Sraj	void *map, *mask;
210218077Smarcel	int acells, icells;
211218077Smarcel	int error, len;
212208747Sraj
213218077Smarcel	error = fdt_addr_cells(node, &acells);
214218077Smarcel	if (error)
215218077Smarcel		return (error);
216208747Sraj
217218077Smarcel	icells = fdt_interrupt_cells(node);
218208747Sraj
219208747Sraj	/*
220208747Sraj	 * Retrieve the interrupt map and mask properties.
221208747Sraj	 */
222218077Smarcel	len = OF_getprop_alloc(node, "interrupt-map-mask", 1, &mask);
223218077Smarcel	if (len / sizeof(pcell_t) != (acells + icells)) {
224208747Sraj		debugf("bad mask len = %d\n", len);
225208747Sraj		goto err;
226208747Sraj	}
227208747Sraj
228218077Smarcel	len = OF_getprop_alloc(node, "interrupt-map", 1, &map);
229208747Sraj	if (len <= 0) {
230208747Sraj		debugf("bad map len = %d\n", len);
231208747Sraj		goto err;
232208747Sraj	}
233208747Sraj
234208747Sraj	intr_info->map_len = len;
235208747Sraj	intr_info->map = map;
236208747Sraj	intr_info->mask = mask;
237218077Smarcel	intr_info->addr_cells = acells;
238218077Smarcel	intr_info->intr_cells = icells;
239218077Smarcel
240218077Smarcel	debugf("acells=%u, icells=%u, map_len=%u\n", acells, icells, len);
241208747Sraj	return (0);
242208747Sraj
243208747Srajerr:
244208747Sraj	free(mask, M_OFWPROP);
245208747Sraj	return (ENXIO);
246208747Sraj}
247208747Sraj
248208747Srajint
249208747Srajfdt_pci_route_intr(int bus, int slot, int func, int pin,
250208747Sraj    struct fdt_pci_intr *intr_info, int *interrupt)
251208747Sraj{
252208747Sraj	pcell_t child_spec[4], masked[4];
253208747Sraj	ihandle_t iph;
254208747Sraj	pcell_t intr_par;
255208747Sraj	pcell_t *map_ptr;
256208747Sraj	uint32_t addr;
257208747Sraj	int i, j, map_len;
258208747Sraj	int par_intr_cells, par_addr_cells, child_spec_cells, row_cells;
259208747Sraj	int par_idx, spec_idx, err, trig, pol;
260208747Sraj
261208747Sraj	child_spec_cells = intr_info->addr_cells + intr_info->intr_cells;
262208747Sraj	if (child_spec_cells > sizeof(child_spec) / sizeof(pcell_t))
263208747Sraj		return (ENOMEM);
264208747Sraj
265208747Sraj	addr = (bus << 16) | (slot << 11) | (func << 8);
266208747Sraj	child_spec[0] = addr;
267208747Sraj	child_spec[1] = 0;
268208747Sraj	child_spec[2] = 0;
269208747Sraj	child_spec[3] = pin;
270208747Sraj
271208747Sraj	map_len = intr_info->map_len;
272208747Sraj	map_ptr = intr_info->map;
273208747Sraj
274208747Sraj	par_idx = child_spec_cells;
275208747Sraj	i = 0;
276208747Sraj	while (i < map_len) {
277208747Sraj		iph = fdt32_to_cpu(map_ptr[par_idx]);
278208747Sraj		intr_par = OF_instance_to_package(iph);
279208747Sraj
280208747Sraj		err = fdt_addr_cells(intr_par, &par_addr_cells);
281208747Sraj		if (err != 0) {
282208747Sraj			debugf("could not retrieve intr parent #addr-cells\n");
283208747Sraj			return (err);
284208747Sraj		}
285208747Sraj		par_intr_cells = fdt_interrupt_cells(intr_par);
286208747Sraj
287208747Sraj		row_cells = child_spec_cells + 1 + par_addr_cells +
288208747Sraj		    par_intr_cells;
289208747Sraj
290208747Sraj		/*
291208747Sraj		 * Apply mask and look up the entry in interrupt map.
292208747Sraj		 */
293208747Sraj		for (j = 0; j < child_spec_cells; j++) {
294208747Sraj			masked[j] = child_spec[j] &
295208747Sraj			    fdt32_to_cpu(intr_info->mask[j]);
296208747Sraj
297208747Sraj			if (masked[j] != fdt32_to_cpu(map_ptr[j]))
298208747Sraj				goto next;
299208747Sraj		}
300208747Sraj
301208747Sraj		/*
302208747Sraj		 * Decode interrupt of the parent intr controller.
303208747Sraj		 */
304208747Sraj		spec_idx = child_spec_cells + 1 + par_addr_cells;
305208747Sraj		err = fdt_intr_decode(intr_par, &map_ptr[spec_idx],
306208747Sraj		    interrupt, &trig, &pol);
307208747Sraj		if (err != 0) {
308208747Sraj			debugf("could not decode interrupt\n");
309208747Sraj			return (err);
310208747Sraj		}
311208747Sraj		debugf("decoded intr = %d, trig = %d, pol = %d\n", *interrupt,
312208747Sraj		    trig, pol);
313208747Sraj
314209908Sraj#if defined(__powerpc__)
315218077Smarcel		powerpc_config_intr(FDT_MAP_IRQ(intr_par, *interrupt), trig,
316218077Smarcel		    pol);
317209908Sraj#endif
318208747Sraj		return (0);
319208747Sraj
320208747Srajnext:
321208747Sraj		map_ptr += row_cells;
322208747Sraj		i += (row_cells * sizeof(pcell_t));
323208747Sraj	}
324208747Sraj
325208747Sraj	return (ENXIO);
326208747Sraj}
327208747Sraj
328208747Sraj#if defined(__arm__)
329208747Srajint
330208747Srajfdt_pci_devmap(phandle_t node, struct pmap_devmap *devmap, vm_offset_t io_va,
331208747Sraj    vm_offset_t mem_va)
332208747Sraj{
333208747Sraj	struct fdt_pci_range io_space, mem_space;
334208747Sraj	int error;
335208747Sraj
336208747Sraj	if ((error = fdt_pci_ranges_decode(node, &io_space, &mem_space)) != 0)
337208747Sraj		return (error);
338208747Sraj
339208747Sraj	devmap->pd_va = io_va;
340208747Sraj	devmap->pd_pa = io_space.base_parent;
341208747Sraj	devmap->pd_size = io_space.len;
342208747Sraj	devmap->pd_prot = VM_PROT_READ | VM_PROT_WRITE;
343208747Sraj	devmap->pd_cache = PTE_NOCACHE;
344208747Sraj	devmap++;
345208747Sraj
346208747Sraj	devmap->pd_va = mem_va;
347208747Sraj	devmap->pd_pa = mem_space.base_parent;
348208747Sraj	devmap->pd_size = mem_space.len;
349208747Sraj	devmap->pd_prot = VM_PROT_READ | VM_PROT_WRITE;
350208747Sraj	devmap->pd_cache = PTE_NOCACHE;
351208747Sraj	return (0);
352208747Sraj}
353208747Sraj#endif
354218077Smarcel
355218077Smarcel#if 0
356218077Smarcelstatic int
357218077Smarcelfdt_pci_config_bar(device_t dev, int bus, int slot, int func, int bar)
358218077Smarcel{
359218077Smarcel}
360218077Smarcel
361218077Smarcelstatic int
362218077Smarcelfdt_pci_config_normal(device_t dev, int bus, int slot, int func)
363218077Smarcel{
364218077Smarcel	int bar;
365218077Smarcel	uint8_t command, intline, intpin;
366218077Smarcel
367218077Smarcel	command = PCIB_READ_CONFIG(dev, bus, slot, func, PCIR_COMMAND, 1);
368218077Smarcel	command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN);
369218077Smarcel	PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_COMMAND, command, 1);
370218077Smarcel
371218077Smarcel	/* Program the base address registers. */
372218077Smarcel	bar = 0;
373218077Smarcel	while (bar <= PCIR_MAX_BAR_0)
374218077Smarcel		bar += fdt_pci_config_bar(dev, bus, slot, func, bar);
375218077Smarcel
376218077Smarcel	/* Perform interrupt routing. */
377218077Smarcel	intpin = PCIB_READ_CONFIG(dev, bus, slot, func, PCIR_INTPIN, 1);
378218077Smarcel	intline = fsl_pcib_route_int(dev, bus, slot, func, intpin);
379218077Smarcel	PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_INTLINE, intline, 1);
380218077Smarcel
381218077Smarcel	command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
382218077Smarcel	PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_COMMAND, command, 1);
383218077Smarcel}
384218077Smarcel
385218077Smarcelstatic int
386218077Smarcelfdt_pci_config_bridge(device_t dev, int bus, int secbus, int slot, int func)
387218077Smarcel{
388218077Smarcel	int maxbar;
389218077Smarcel	uint8_t command;
390218077Smarcel
391218077Smarcel	command = PCIB_READ_CONFIG(dev, bus, slot, func, PCIR_COMMAND, 1);
392218077Smarcel	command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN);
393218077Smarcel	PCIB_WRITE_CONFIG(dev, bus, slot, func, PCIR_COMMAND, command, 1);
394218077Smarcel
395218077Smarcel	/* Program the base address registers. */
396218077Smarcel                        maxbar = (hdrtype & PCIM_HDRTYPE) ? 1 : 6;
397218077Smarcel                        bar = 0;
398218077Smarcel                        while (bar < maxbar)
399218077Smarcel                                bar += fsl_pcib_init_bar(sc, bus, slot, func,
400218077Smarcel                                    bar);
401218077Smarcel
402218077Smarcel                        /* Perform interrupt routing. */
403218077Smarcel                        intpin = fsl_pcib_read_config(sc->sc_dev, bus, slot,
404218077Smarcel                            func, PCIR_INTPIN, 1);
405218077Smarcel                        intline = fsl_pcib_route_int(sc, bus, slot, func,
406218077Smarcel                            intpin);
407218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
408218077Smarcel                            PCIR_INTLINE, intline, 1);
409218077Smarcel
410218077Smarcel                        command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN;
411218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
412218077Smarcel                            PCIR_COMMAND, command, 1);
413218077Smarcel
414218077Smarcel                        /*
415218077Smarcel                         * Handle PCI-PCI bridges
416218077Smarcel                         */
417218077Smarcel                        class = fsl_pcib_read_config(sc->sc_dev, bus, slot,
418218077Smarcel                            func, PCIR_CLASS, 1);
419218077Smarcel                        subclass = fsl_pcib_read_config(sc->sc_dev, bus, slot,
420218077Smarcel                            func, PCIR_SUBCLASS, 1);
421218077Smarcel
422218077Smarcel                        /* Allow only proper PCI-PCI briges */
423218077Smarcel                        if (class != PCIC_BRIDGE)
424218077Smarcel                                continue;
425218077Smarcel                        if (subclass != PCIS_BRIDGE_PCI)
426218077Smarcel                                continue;
427218077Smarcel
428218077Smarcel                        secbus++;
429218077Smarcel
430218077Smarcel                        /* Program I/O decoder. */
431218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
432218077Smarcel                            PCIR_IOBASEL_1, sc->sc_ioport.rm_start >> 8, 1);
433218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
434218077Smarcel                            PCIR_IOLIMITL_1, sc->sc_ioport.rm_end >> 8, 1);
435218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
436218077Smarcel                            PCIR_IOBASEH_1, sc->sc_ioport.rm_start >> 16, 2);
437218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
438218077Smarcel                            PCIR_IOLIMITH_1, sc->sc_ioport.rm_end >> 16, 2);
439218077Smarcel
440218077Smarcel                        /* Program (non-prefetchable) memory decoder. */
441218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
442218077Smarcel                            PCIR_MEMBASE_1, sc->sc_iomem.rm_start >> 16, 2);
443218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
444218077Smarcel                            PCIR_MEMLIMIT_1, sc->sc_iomem.rm_end >> 16, 2);
445218077Smarcel
446218077Smarcel                        /* Program prefetchable memory decoder. */
447218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
448218077Smarcel                            PCIR_PMBASEL_1, 0x0010, 2);
449218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
450218077Smarcel                            PCIR_PMLIMITL_1, 0x000f, 2);
451218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
452218077Smarcel                            PCIR_PMBASEH_1, 0x00000000, 4);
453218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
454218077Smarcel                            PCIR_PMLIMITH_1, 0x00000000, 4);
455218077Smarcel
456218077Smarcel                        /* Read currect bus register configuration */
457218077Smarcel                        old_pribus = fsl_pcib_read_config(sc->sc_dev, bus,
458218077Smarcel                            slot, func, PCIR_PRIBUS_1, 1);
459218077Smarcel                        old_secbus = fsl_pcib_read_config(sc->sc_dev, bus,
460218077Smarcel                            slot, func, PCIR_SECBUS_1, 1);
461218077Smarcel                        old_subbus = fsl_pcib_read_config(sc->sc_dev, bus,
462218077Smarcel                            slot, func, PCIR_SUBBUS_1, 1);
463218077Smarcel
464218077Smarcel                        if (bootverbose)
465218077Smarcel                                printf("PCI: reading firmware bus numbers for "
466218077Smarcel                                    "secbus = %d (bus/sec/sub) = (%d/%d/%d)\n",
467218077Smarcel                                    secbus, old_pribus, old_secbus, old_subbus);
468218077Smarcel
469218077Smarcel                        new_pribus = bus;
470218077Smarcel                        new_secbus = secbus;
471218077Smarcel
472218077Smarcel                        secbus = fsl_pcib_init(sc, secbus,
473218077Smarcel                            (subclass == PCIS_BRIDGE_PCI) ? PCI_SLOTMAX : 0);
474218077Smarcel
475218077Smarcel                        new_subbus = secbus;
476218077Smarcel
477218077Smarcel                        if (bootverbose)
478218077Smarcel                                printf("PCI: translate firmware bus numbers "
479218077Smarcel                                    "for secbus %d (%d/%d/%d) -> (%d/%d/%d)\n",
480218077Smarcel                                    secbus, old_pribus, old_secbus, old_subbus,
481218077Smarcel                                    new_pribus, new_secbus, new_subbus);
482218077Smarcel
483218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
484218077Smarcel                            PCIR_PRIBUS_1, new_pribus, 1);
485218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
486218077Smarcel                            PCIR_SECBUS_1, new_secbus, 1);
487218077Smarcel                        fsl_pcib_write_config(sc->sc_dev, bus, slot, func,
488218077Smarcel                            PCIR_SUBBUS_1, new_subbus, 1);
489218077Smarcel
490218077Smarcel}
491218077Smarcel
492218077Smarcelstatic int
493218077Smarcelfdt_pci_config_slot(device_t dev, int bus, int secbus, int slot)
494218077Smarcel{
495218077Smarcel	int func, maxfunc;
496218077Smarcel	uint16_t vendor;
497218077Smarcel	uint8_t hdrtype;
498218077Smarcel
499218077Smarcel	maxfunc = 0;
500218077Smarcel	for (func = 0; func <= maxfunc; func++) {
501218077Smarcel		hdrtype = PCIB_READ_CONFIG(dev, bus, slot, func,
502218077Smarcel		    PCIR_HDRTYPE, 1);
503218077Smarcel		if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
504218077Smarcel			continue;
505218077Smarcel		if (func == 0 && (hdrtype & PCIM_MFDEV))
506218077Smarcel			maxfunc = PCI_FUNCMAX;
507218077Smarcel
508218077Smarcel		vendor = PCIB_READ_CONFIG(dev, bus, slot, func,
509218077Smarcel		    PCIR_VENDOR, 2);
510218077Smarcel		if (vendor == 0xffff)
511218077Smarcel			continue;
512218077Smarcel
513218077Smarcel		if ((hdrtype & PCIM_HDRTYPE) == PCIM_HDRTYPE_NORMAL)
514218077Smarcel			fdt_pci_config_normal(dev, bus, slot, func);
515218077Smarcel		else
516218077Smarcel			secbus = fdt_pci_config_bridge(dev, bus, secbus,
517218077Smarcel			    slot, func);
518218077Smarcel	}
519218077Smarcel
520218077Smarcel	return (secbus);
521218077Smarcel}
522218077Smarcel
523218077Smarcelstatic int
524218077Smarcelfdt_pci_config_bus(device_t dev, int bus, int maxslot)
525218077Smarcel{
526218077Smarcel	int func, maxfunc, secbus, slot;
527218077Smarcel
528218077Smarcel	secbus = bus;
529218077Smarcel	for (slot = 0; slot <= maxslot; slot++)
530218077Smarcel		secbus = fdt_pci_config_slot(dev, bus, secbus, slot);
531218077Smarcel
532218077Smarcel	return (secbus);
533218077Smarcel}
534218077Smarcel
535218077Smarcelint
536218077Smarcelfdt_pci_config_domain(device_t dev)
537218077Smarcel{
538218077Smarcel	pcell_t bus_range[2];
539218077Smarcel	phandle_t root;
540218077Smarcel	int bus, error, maxslot;
541218077Smarcel
542218077Smarcel	root = ofw_bus_get_node(dev);
543218077Smarcel	if (root == 0)
544218077Smarcel		return (EINVAL);
545218077Smarcel	if (!fdt_is_type(root, "pci"))
546218077Smarcel		return (EINVAL);
547218077Smarcel
548218077Smarcel	/*
549218077Smarcel	 * Determine the bus number of the root in this domain.
550218077Smarcel	 * Lacking any information, this will be bus 0.
551218077Smarcel	 * Write the bus number to the bus device, using the IVAR.
552218077Smarcel	 */
553218077Smarcel	if ((OF_getprop(root, "bus-range", bus_range, sizeof(bus_range)) <= 0)
554218077Smarcel		bus = 0;
555218077Smarcel	else
556218077Smarcel		bus = fdt32_to_cpu(bus_range[0]);
557218077Smarcel
558218077Smarcel	error = BUS_WRITE_IVAR(dev, NULL, PCIB_IVAR_BUS, bus);
559218077Smarcel	if (error)
560218077Smarcel		return (error);
561218077Smarcel
562218077Smarcel	/* Get the maximum slot number for bus-enumeration. */
563218077Smarcel	maxslot = PCIB_MAXSLOTS(dev);
564218077Smarcel
565218077Smarcel	bus = fdt_pci_config_bus(dev, bus, maxslot);
566218077Smarcel	return (0);
567218077Smarcel}
568218077Smarcel#endif
569