xref: /freebsd/sys/dev/bhnd/bhndb/bhndb_pci.c (revision aa24f48b361effe51163877d84f1b70d32b77e04)
1 /*-
2  * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 /*
34  * PCI-specific implementation for the BHNDB bridge driver.
35  *
36  * Provides support for bridging from a PCI parent bus to a BHND-compatible
37  * bus (e.g. bcma or siba) via a Broadcom PCI core configured in end-point
38  * mode.
39  *
40  * This driver handles all initial generic host-level PCI interactions with a
41  * PCI/PCIe bridge core operating in endpoint mode. Once the bridged bhnd(4)
42  * bus has been enumerated, this driver works in tandem with a core-specific
43  * bhnd_pci_hostb driver to manage the PCI core.
44  */
45 
46 #include <sys/param.h>
47 #include <sys/kernel.h>
48 #include <sys/bus.h>
49 #include <sys/limits.h>
50 #include <sys/malloc.h>
51 #include <sys/module.h>
52 #include <sys/systm.h>
53 
54 #include <dev/pci/pcireg.h>
55 #include <dev/pci/pcivar.h>
56 
57 #include <dev/bhnd/bhnd.h>
58 
59 #include <dev/bhnd/cores/pci/bhnd_pcireg.h>
60 
61 #include "bhndb_pcireg.h"
62 #include "bhndb_pcivar.h"
63 #include "bhndb_private.h"
64 
65 static int		bhndb_pci_init_msi(struct bhndb_pci_softc *sc);
66 static int		bhndb_pci_add_children(struct bhndb_pci_softc *sc);
67 
68 static int		bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc);
69 static int		bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc);
70 
71 static int		bhndb_pci_compat_setregwin(struct bhndb_pci_softc *,
72 			    const struct bhndb_regwin *, bhnd_addr_t);
73 static int		bhndb_pci_fast_setregwin(struct bhndb_pci_softc *,
74 			    const struct bhndb_regwin *, bhnd_addr_t);
75 
76 static void		bhndb_init_sromless_pci_config(
77 			    struct bhndb_pci_softc *sc);
78 
79 static bus_addr_t	bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc);
80 static bus_size_t	bhndb_pci_sprom_size(struct bhndb_pci_softc *sc);
81 
82 #define	BHNDB_PCI_MSI_COUNT	1
83 
84 /**
85  * Default bhndb_pci implementation of device_probe().
86  *
87  * Verifies that the parent is a PCI/PCIe device.
88  */
89 static int
90 bhndb_pci_probe(device_t dev)
91 {
92 	device_t	parent;
93 	devclass_t	parent_bus;
94 	devclass_t	pci;
95 
96 	/* Our parent must be a PCI/PCIe device. */
97 	pci = devclass_find("pci");
98 	parent = device_get_parent(dev);
99 	parent_bus = device_get_devclass(device_get_parent(parent));
100 
101 	if (parent_bus != pci)
102 		return (ENXIO);
103 
104 	device_set_desc(dev, "PCI-BHND bridge");
105 
106 	return (BUS_PROBE_DEFAULT);
107 }
108 
109 /* Configure MSI interrupts */
110 static int
111 bhndb_pci_init_msi(struct bhndb_pci_softc *sc)
112 {
113 	int error;
114 
115 	/* Is MSI available? */
116 	if (pci_msi_count(sc->parent) < BHNDB_PCI_MSI_COUNT)
117 		return (ENXIO);
118 
119 	/* Allocate expected message count */
120 	sc->intr.msi_count = BHNDB_PCI_MSI_COUNT;
121 	if ((error = pci_alloc_msi(sc->parent, &sc->intr.msi_count))) {
122 		device_printf(sc->dev, "failed to allocate MSI interrupts: "
123 		    "%d\n", error);
124 		return (error);
125 	}
126 
127 	if (sc->intr.msi_count < BHNDB_PCI_MSI_COUNT)
128 		return (ENXIO);
129 
130 	/* MSI uses resource IDs starting at 1 */
131 	sc->intr.intr_rid = 1;
132 
133 	return (0);
134 }
135 
136 static int
137 bhndb_pci_attach(device_t dev)
138 {
139 	struct bhndb_pci_softc	*sc;
140 	int			 error, reg;
141 
142 	sc = device_get_softc(dev);
143 	sc->dev = dev;
144 	sc->parent = device_get_parent(dev);
145 	sc->set_regwin = bhndb_pci_compat_setregwin;
146 
147 	/* Enable PCI bus mastering */
148 	pci_enable_busmaster(sc->parent);
149 
150 	/* Set up interrupt handling */
151 	if (bhndb_pci_init_msi(sc) == 0) {
152 		device_printf(dev, "Using MSI interrupts on %s\n",
153 		    device_get_nameunit(sc->parent));
154 	} else {
155 		device_printf(dev, "Using INTx interrupts on %s\n",
156 		    device_get_nameunit(sc->parent));
157 		sc->intr.intr_rid = 0;
158 	}
159 
160 	/* Determine our bridge device class */
161 	sc->pci_devclass = BHND_DEVCLASS_PCI;
162 	if (pci_find_cap(sc->parent, PCIY_EXPRESS, &reg) == 0)
163 		sc->pci_devclass = BHND_DEVCLASS_PCIE;
164 	else
165 		sc->pci_devclass = BHND_DEVCLASS_PCI;
166 
167 	/* Enable clocks (if required by this hardware) */
168 	if ((error = bhndb_enable_pci_clocks(sc)))
169 		goto cleanup;
170 
171 	/* Perform bridge attach, fully initializing the bridge
172 	 * configuration. */
173 	if ((error = bhndb_attach(dev, sc->pci_devclass)))
174 		goto cleanup;
175 
176 	/* If supported, switch to faster regwin handling */
177 	if (sc->bhndb.chipid.chip_type != BHND_CHIPTYPE_SIBA) {
178 		atomic_store_rel_ptr((volatile void *) &sc->set_regwin,
179 		    (uintptr_t) &bhndb_pci_fast_setregwin);
180 	}
181 
182 	/* Enable PCI bus mastering */
183 	pci_enable_busmaster(sc->parent);
184 
185 	/* Fix-up power on defaults for SROM-less devices. */
186 	bhndb_init_sromless_pci_config(sc);
187 
188 	/* Add any additional child devices */
189 	if ((error = bhndb_pci_add_children(sc)))
190 		goto cleanup;
191 
192 	/* Probe and attach our children */
193 	if ((error = bus_generic_attach(dev)))
194 		goto cleanup;
195 
196 	return (0);
197 
198 cleanup:
199 	device_delete_children(dev);
200 	bhndb_disable_pci_clocks(sc);
201 	if (sc->intr.msi_count > 0)
202 		pci_release_msi(dev);
203 
204 	pci_disable_busmaster(sc->parent);
205 
206 	return (error);
207 }
208 
209 static int
210 bhndb_pci_detach(device_t dev)
211 {
212 	struct bhndb_pci_softc	*sc;
213 	int			 error;
214 
215 	sc = device_get_softc(dev);
216 
217 	/* Attempt to detach our children */
218 	if ((error = bus_generic_detach(dev)))
219 		return (error);
220 
221 	/* Perform generic bridge detach */
222 	if ((error = bhndb_generic_detach(dev)))
223 		return (error);
224 
225 	/* Disable clocks (if required by this hardware) */
226 	if ((error = bhndb_disable_pci_clocks(sc)))
227 		return (error);
228 
229 	/* Release MSI interrupts */
230 	if (sc->intr.msi_count > 0)
231 		pci_release_msi(dev);
232 
233 	/* Disable PCI bus mastering */
234 	pci_disable_busmaster(sc->parent);
235 
236 	return (0);
237 }
238 
239 static int
240 bhndb_pci_add_children(struct bhndb_pci_softc *sc)
241 {
242 	bus_size_t		 nv_sz;
243 	int			 error;
244 
245 	/**
246 	 * If SPROM is mapped directly into BAR0, add child NVRAM
247 	 * device.
248 	 */
249 	nv_sz = bhndb_pci_sprom_size(sc);
250 	if (nv_sz > 0) {
251 		struct bhndb_devinfo	*dinfo;
252 		device_t		 child;
253 
254 		if (bootverbose) {
255 			device_printf(sc->dev, "found SPROM (%ju bytes)\n",
256 			    (uintmax_t)nv_sz);
257 		}
258 
259 		/* Add sprom device, ordered early enough to be available
260 		 * before the bridged bhnd(4) bus is attached. */
261 		child = BUS_ADD_CHILD(sc->dev,
262 		    BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY, "bhnd_nvram", -1);
263 		if (child == NULL) {
264 			device_printf(sc->dev, "failed to add sprom device\n");
265 			return (ENXIO);
266 		}
267 
268 		/* Initialize device address space and resource covering the
269 		 * BAR0 SPROM shadow. */
270 		dinfo = device_get_ivars(child);
271 		dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE;
272 
273 		error = bus_set_resource(child, SYS_RES_MEMORY, 0,
274 		    bhndb_pci_sprom_addr(sc), nv_sz);
275 		if (error) {
276 			device_printf(sc->dev,
277 			    "failed to register sprom resources\n");
278 			return (error);
279 		}
280 	}
281 
282 	return (0);
283 }
284 
285 static const struct bhndb_regwin *
286 bhndb_pci_sprom_regwin(struct bhndb_pci_softc *sc)
287 {
288 	struct bhndb_resources		*bres;
289 	const struct bhndb_hwcfg	*cfg;
290 	const struct bhndb_regwin	*sprom_win;
291 
292 	bres = sc->bhndb.bus_res;
293 	cfg = bres->cfg;
294 
295 	sprom_win = bhndb_regwin_find_type(cfg->register_windows,
296 	    BHNDB_REGWIN_T_SPROM, BHNDB_PCI_V0_BAR0_SPROM_SIZE);
297 
298 	return (sprom_win);
299 }
300 
301 static bus_addr_t
302 bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc)
303 {
304 	const struct bhndb_regwin	*sprom_win;
305 	struct resource			*r;
306 
307 	/* Fetch the SPROM register window */
308 	sprom_win = bhndb_pci_sprom_regwin(sc);
309 	KASSERT(sprom_win != NULL, ("requested sprom address on PCI_V2+"));
310 
311 	/* Fetch the associated resource */
312 	r = bhndb_find_regwin_resource(sc->bhndb.bus_res, sprom_win);
313 	KASSERT(r != NULL, ("missing resource for sprom window\n"));
314 
315 	return (rman_get_start(r) + sprom_win->win_offset);
316 }
317 
318 static bus_size_t
319 bhndb_pci_sprom_size(struct bhndb_pci_softc *sc)
320 {
321 	const struct bhndb_regwin	*sprom_win;
322 	uint32_t			 sctl;
323 	bus_size_t			 sprom_sz;
324 
325 	sprom_win = bhndb_pci_sprom_regwin(sc);
326 
327 	/* PCI_V2 and later devices map SPROM/OTP via ChipCommon */
328 	if (sprom_win == NULL)
329 		return (0);
330 
331 	/* Determine SPROM size */
332 	sctl = pci_read_config(sc->parent, BHNDB_PCI_SPROM_CONTROL, 4);
333 	if (sctl & BHNDB_PCI_SPROM_BLANK)
334 		return (0);
335 
336 	switch (sctl & BHNDB_PCI_SPROM_SZ_MASK) {
337 	case BHNDB_PCI_SPROM_SZ_1KB:
338 		sprom_sz = (1 * 1024);
339 		break;
340 
341 	case BHNDB_PCI_SPROM_SZ_4KB:
342 		sprom_sz = (4 * 1024);
343 		break;
344 
345 	case BHNDB_PCI_SPROM_SZ_16KB:
346 		sprom_sz = (16 * 1024);
347 		break;
348 
349 	case BHNDB_PCI_SPROM_SZ_RESERVED:
350 	default:
351 		device_printf(sc->dev, "invalid PCI sprom size 0x%x\n", sctl);
352 		return (0);
353 	}
354 
355 	if (sprom_sz > sprom_win->win_size) {
356 		device_printf(sc->dev,
357 		    "PCI sprom size (0x%x) overruns defined register window\n",
358 		    sctl);
359 		return (0);
360 	}
361 
362 	return (sprom_sz);
363 }
364 
365 /*
366  * On devices without a SROM, the PCI(e) cores will be initialized with
367  * their Power-on-Reset defaults; this can leave two of the BAR0 PCI windows
368  * mapped to the wrong core.
369  *
370  * This function updates the SROM shadow to point the BAR0 windows at the
371  * current PCI core.
372  *
373  * Applies to all PCI/PCIe revisions.
374  */
375 static void
376 bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc)
377 {
378 	struct bhndb_resources		*bres;
379 	const struct bhndb_hwcfg	*cfg;
380 	const struct bhndb_regwin	*win;
381 	struct bhnd_core_info		 hostb_core;
382 	struct resource			*core_regs;
383 	bus_size_t			 srom_offset;
384 	u_int				 pci_cidx, sprom_cidx;
385 	uint16_t			 val;
386 	int				 error;
387 
388 	bres = sc->bhndb.bus_res;
389 	cfg = bres->cfg;
390 
391 	/* Find our hostb core */
392 	error = BHNDB_GET_HOSTB_CORE(sc->dev, sc->bhndb.bus_dev, &hostb_core);
393 	if (error) {
394 		device_printf(sc->dev, "no host bridge device found\n");
395 		return;
396 	}
397 
398 	if (hostb_core.vendor != BHND_MFGID_BCM)
399 		return;
400 
401 	switch (hostb_core.device) {
402 	case BHND_COREID_PCI:
403 		srom_offset = BHND_PCI_SRSH_PI_OFFSET;
404 		break;
405 	case BHND_COREID_PCIE:
406 		srom_offset = BHND_PCIE_SRSH_PI_OFFSET;
407 		break;
408 	default:
409 		device_printf(sc->dev, "unsupported PCI host bridge device\n");
410 		return;
411 	}
412 
413 	/* Locate the static register window mapping the PCI core */
414 	win = bhndb_regwin_find_core(cfg->register_windows, sc->pci_devclass,
415 	    0, BHND_PORT_DEVICE, 0, 0);
416 	if (win == NULL) {
417 		device_printf(sc->dev, "missing PCI core register window\n");
418 		return;
419 	}
420 
421 	/* Fetch the resource containing the register window */
422 	core_regs = bhndb_find_regwin_resource(bres, win);
423 	if (core_regs == NULL) {
424 		device_printf(sc->dev, "missing PCI core register resource\n");
425 		return;
426 	}
427 
428 	/* Fetch the SPROM's configured core index */
429 	val = bus_read_2(core_regs, win->win_offset + srom_offset);
430 	sprom_cidx = (val & BHND_PCI_SRSH_PI_MASK) >> BHND_PCI_SRSH_PI_SHIFT;
431 
432 	/* If it doesn't match host bridge's core index, update the index
433 	 * value */
434 	pci_cidx = hostb_core.core_idx;
435 	if (sprom_cidx != pci_cidx) {
436 		val &= ~BHND_PCI_SRSH_PI_MASK;
437 		val |= (pci_cidx << BHND_PCI_SRSH_PI_SHIFT);
438 		bus_write_2(core_regs,
439 		    win->win_offset + srom_offset, val);
440 	}
441 }
442 
443 static int
444 bhndb_pci_resume(device_t dev)
445 {
446 	struct bhndb_pci_softc	*sc;
447 	int			 error;
448 
449 	sc = device_get_softc(dev);
450 
451 	/* Enable clocks (if supported by this hardware) */
452 	if ((error = bhndb_enable_pci_clocks(sc)))
453 		return (error);
454 
455 	/* Perform resume */
456 	return (bhndb_generic_resume(dev));
457 }
458 
459 static int
460 bhndb_pci_suspend(device_t dev)
461 {
462 	struct bhndb_pci_softc	*sc;
463 	int			 error;
464 
465 	sc = device_get_softc(dev);
466 
467 	/* Disable clocks (if supported by this hardware) */
468 	if ((error = bhndb_disable_pci_clocks(sc)))
469 		return (error);
470 
471 	/* Perform suspend */
472 	return (bhndb_generic_suspend(dev));
473 }
474 
475 static int
476 bhndb_pci_set_window_addr(device_t dev, const struct bhndb_regwin *rw,
477     bhnd_addr_t addr)
478 {
479 	struct bhndb_pci_softc *sc = device_get_softc(dev);
480 	return (sc->set_regwin(sc, rw, addr));
481 }
482 
483 /**
484  * A siba(4) and bcma(4)-compatible bhndb_set_window_addr implementation.
485  *
486  * On siba(4) devices, it's possible that writing a PCI window register may
487  * not succeed; it's necessary to immediately read the configuration register
488  * and retry if not set to the desired value.
489  *
490  * This is not necessary on bcma(4) devices, but other than the overhead of
491  * validating the register, there's no harm in performing the verification.
492  */
493 static int
494 bhndb_pci_compat_setregwin(struct bhndb_pci_softc *sc,
495     const struct bhndb_regwin *rw, bhnd_addr_t addr)
496 {
497 	int		error;
498 	int		reg;
499 
500 	if (rw->win_type != BHNDB_REGWIN_T_DYN)
501 		return (ENODEV);
502 
503 	reg = rw->d.dyn.cfg_offset;
504 	for (u_int i = 0; i < BHNDB_PCI_BARCTRL_WRITE_RETRY; i++) {
505 		if ((error = bhndb_pci_fast_setregwin(sc, rw, addr)))
506 			return (error);
507 
508 		if (pci_read_config(sc->parent, reg, 4) == addr)
509 			return (0);
510 
511 		DELAY(10);
512 	}
513 
514 	/* Unable to set window */
515 	return (ENODEV);
516 }
517 
518 /**
519  * A bcma(4)-only bhndb_set_window_addr implementation.
520  */
521 static int
522 bhndb_pci_fast_setregwin(struct bhndb_pci_softc *sc,
523     const struct bhndb_regwin *rw, bhnd_addr_t addr)
524 {
525 	/* The PCI bridge core only supports 32-bit addressing, regardless
526 	 * of the bus' support for 64-bit addressing */
527 	if (addr > UINT32_MAX)
528 		return (ERANGE);
529 
530 	switch (rw->win_type) {
531 	case BHNDB_REGWIN_T_DYN:
532 		/* Addresses must be page aligned */
533 		if (addr % rw->win_size != 0)
534 			return (EINVAL);
535 
536 		pci_write_config(sc->parent, rw->d.dyn.cfg_offset, addr, 4);
537 		break;
538 	default:
539 		return (ENODEV);
540 	}
541 
542 	return (0);
543 }
544 
545 static int
546 bhndb_pci_populate_board_info(device_t dev, device_t child,
547     struct bhnd_board_info *info)
548 {
549 	struct bhndb_pci_softc	*sc;
550 
551 	sc = device_get_softc(dev);
552 
553 	/*
554 	 * On a subset of Apple BCM4360 modules, always prefer the
555 	 * PCI subdevice to the SPROM-supplied boardtype.
556 	 *
557 	 * TODO:
558 	 *
559 	 * Broadcom's own drivers implement this override, and then later use
560 	 * the remapped BCM4360 board type to determine the required
561 	 * board-specific workarounds.
562 	 *
563 	 * Without access to this hardware, it's unclear why this mapping
564 	 * is done, and we must do the same. If we can survey the hardware
565 	 * in question, it may be possible to replace this behavior with
566 	 * explicit references to the SPROM-supplied boardtype(s) in our
567 	 * quirk definitions.
568 	 */
569 	if (pci_get_subvendor(sc->parent) == PCI_VENDOR_APPLE) {
570 		switch (info->board_type) {
571 		case BHND_BOARD_BCM94360X29C:
572 		case BHND_BOARD_BCM94360X29CP2:
573 		case BHND_BOARD_BCM94360X51:
574 		case BHND_BOARD_BCM94360X51P2:
575 			info->board_type = 0;	/* allow override below */
576 			break;
577 		default:
578 			break;
579 		}
580 	}
581 
582 	/* If NVRAM did not supply vendor/type info, provide the PCI
583 	 * subvendor/subdevice values. */
584 	if (info->board_vendor == 0)
585 		info->board_vendor = pci_get_subvendor(sc->parent);
586 
587 	if (info->board_type == 0)
588 		info->board_type = pci_get_subdevice(sc->parent);
589 
590 	return (0);
591 }
592 
593 /**
594  * Enable externally managed clocks, if required.
595  *
596  * Some PCI chipsets (BCM4306, possibly others) chips do not support
597  * the idle low-power clock. Clocking must be bootstrapped at
598  * attach/resume by directly adjusting GPIO registers exposed in the
599  * PCI config space, and correspondingly, explicitly shutdown at
600  * detach/suspend.
601  *
602  * @param sc Bridge driver state.
603  */
604 static int
605 bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc)
606 {
607 	uint32_t		gpio_in, gpio_out, gpio_en;
608 	uint32_t		gpio_flags;
609 	uint16_t		pci_status;
610 
611 	/* Only supported and required on PCI devices */
612 	if (sc->pci_devclass != BHND_DEVCLASS_PCI)
613 		return (0);
614 
615 	/* Read state of XTAL pin */
616 	gpio_in = pci_read_config(sc->parent, BHNDB_PCI_GPIO_IN, 4);
617 	if (gpio_in & BHNDB_PCI_GPIO_XTAL_ON)
618 		return (0); /* already enabled */
619 
620 	/* Fetch current config */
621 	gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4);
622 	gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4);
623 
624 	/* Set PLL_OFF/XTAL_ON pins to HIGH and enable both pins */
625 	gpio_flags = (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON);
626 	gpio_out |= gpio_flags;
627 	gpio_en |= gpio_flags;
628 
629 	pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4);
630 	pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4);
631 	DELAY(1000);
632 
633 	/* Reset PLL_OFF */
634 	gpio_out &= ~BHNDB_PCI_GPIO_PLL_OFF;
635 	pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4);
636 	DELAY(5000);
637 
638 	/* Clear any PCI 'sent target-abort' flag. */
639 	pci_status = pci_read_config(sc->parent, PCIR_STATUS, 2);
640 	pci_status &= ~PCIM_STATUS_STABORT;
641 	pci_write_config(sc->parent, PCIR_STATUS, pci_status, 2);
642 
643 	return (0);
644 }
645 
646 /**
647  * Disable externally managed clocks, if required.
648  *
649  * @param sc Bridge driver state.
650  */
651 static int
652 bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc)
653 {
654 	uint32_t	gpio_out, gpio_en;
655 
656 	/* Only supported and required on PCI devices */
657 	if (sc->pci_devclass != BHND_DEVCLASS_PCI)
658 		return (0);
659 
660 	/* Fetch current config */
661 	gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4);
662 	gpio_en = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, 4);
663 
664 	/* Set PLL_OFF to HIGH, XTAL_ON to LOW. */
665 	gpio_out &= ~BHNDB_PCI_GPIO_XTAL_ON;
666 	gpio_out |= BHNDB_PCI_GPIO_PLL_OFF;
667 	pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4);
668 
669 	/* Enable both output pins */
670 	gpio_en |= (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON);
671 	pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4);
672 
673 	return (0);
674 }
675 
676 static bhnd_clksrc
677 bhndb_pci_pwrctl_get_clksrc(device_t dev, device_t child,
678 	bhnd_clock clock)
679 {
680 	struct bhndb_pci_softc	*sc;
681 	uint32_t		 gpio_out;
682 
683 	sc = device_get_softc(dev);
684 
685 	/* Only supported on PCI devices */
686 	if (sc->pci_devclass != BHND_DEVCLASS_PCI)
687 		return (ENODEV);
688 
689 	/* Only ILP is supported */
690 	if (clock != BHND_CLOCK_ILP)
691 		return (ENXIO);
692 
693 	gpio_out = pci_read_config(sc->parent, BHNDB_PCI_GPIO_OUT, 4);
694 	if (gpio_out & BHNDB_PCI_GPIO_SCS)
695 		return (BHND_CLKSRC_PCI);
696 	else
697 		return (BHND_CLKSRC_XTAL);
698 }
699 
700 static int
701 bhndb_pci_pwrctl_gate_clock(device_t dev, device_t child,
702 	bhnd_clock clock)
703 {
704 	struct bhndb_pci_softc *sc = device_get_softc(dev);
705 
706 	/* Only supported on PCI devices */
707 	if (sc->pci_devclass != BHND_DEVCLASS_PCI)
708 		return (ENODEV);
709 
710 	/* Only HT is supported */
711 	if (clock != BHND_CLOCK_HT)
712 		return (ENXIO);
713 
714 	return (bhndb_disable_pci_clocks(sc));
715 }
716 
717 static int
718 bhndb_pci_pwrctl_ungate_clock(device_t dev, device_t child,
719 	bhnd_clock clock)
720 {
721 	struct bhndb_pci_softc *sc = device_get_softc(dev);
722 
723 	/* Only supported on PCI devices */
724 	if (sc->pci_devclass != BHND_DEVCLASS_PCI)
725 		return (ENODEV);
726 
727 	/* Only HT is supported */
728 	if (clock != BHND_CLOCK_HT)
729 		return (ENXIO);
730 
731 	return (bhndb_enable_pci_clocks(sc));
732 }
733 
734 static int
735 bhndb_pci_assign_intr(device_t dev, device_t child, int rid)
736 {
737 	struct bhndb_pci_softc	*sc;
738 	rman_res_t		 start, count;
739 	int			 error;
740 
741 	sc = device_get_softc(dev);
742 
743 	/* Is the rid valid? */
744 	if (rid >= bhnd_get_intr_count(child))
745 		return (EINVAL);
746 
747 	/* Fetch our common PCI interrupt's start/count. */
748 	error = bus_get_resource(sc->parent, SYS_RES_IRQ, sc->intr.intr_rid,
749 	    &start, &count);
750 	if (error)
751 		return (error);
752 
753 	/* Add to child's resource list */
754         return (bus_set_resource(child, SYS_RES_IRQ, rid, start, count));
755 }
756 
757 static device_method_t bhndb_pci_methods[] = {
758 	/* Device interface */
759 	DEVMETHOD(device_probe,			bhndb_pci_probe),
760 	DEVMETHOD(device_attach,		bhndb_pci_attach),
761 	DEVMETHOD(device_resume,		bhndb_pci_resume),
762 	DEVMETHOD(device_suspend,		bhndb_pci_suspend),
763 	DEVMETHOD(device_detach,		bhndb_pci_detach),
764 
765 	/* BHND interface */
766 	DEVMETHOD(bhnd_bus_assign_intr,		bhndb_pci_assign_intr),
767 
768 	DEVMETHOD(bhnd_bus_pwrctl_get_clksrc,	bhndb_pci_pwrctl_get_clksrc),
769 	DEVMETHOD(bhnd_bus_pwrctl_gate_clock,	bhndb_pci_pwrctl_gate_clock),
770 	DEVMETHOD(bhnd_bus_pwrctl_ungate_clock,	bhndb_pci_pwrctl_ungate_clock),
771 
772 	/* BHNDB interface */
773 	DEVMETHOD(bhndb_set_window_addr,	bhndb_pci_set_window_addr),
774 	DEVMETHOD(bhndb_populate_board_info,	bhndb_pci_populate_board_info),
775 
776 	DEVMETHOD_END
777 };
778 
779 DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods,
780     sizeof(struct bhndb_pci_softc), bhndb_driver);
781 
782 MODULE_VERSION(bhndb_pci, 1);
783 MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1);
784 MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1);
785 MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1);
786 MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1);
787