Ejemplo n.º 1
0
/**
 * Return all quirks known to be applicable to the host bridge.
 * 
 * If the PCI bridge core has not yet been identified, no core-specific
 * quirk flags will be returned. This function may be called again to
 * rediscover applicable quirks after the host bridge core has been
 * identified.
 * 
 * @param sc bhndb PCI driver state.
 * @param id The host bridge core's identification table entry, or NULL
 * if the host bridge core has not yet been identified.
 * 
 * @return Returns the set of quirks applicable to the current hardware.
 */
static uint32_t 
bhndb_pci_discover_quirks(struct bhndb_pci_softc *sc,
    const struct bhndb_pci_id *id)
{
	struct bhnd_device_quirk	*qt;
	uint32_t			 quirks;
	uint8_t				 hwrev;

	quirks = BHNDB_PCI_QUIRK_NONE;

	/* Determine any device class-specific quirks */
	switch (sc->pci_devclass) {
	case BHND_DEVCLASS_PCI:
		/* All PCI devices require external clock gating */
		sc->quirks |= BHNDB_PCI_QUIRK_EXT_CLOCK_GATING;
		break;
	default:
		break;
	}

	// TODO: Additional quirk matching

	/* Determine any PCI core hwrev-specific device quirks */
	if (id != NULL) {
		hwrev = bhnd_get_hwrev(sc->bhndb.hostb_dev);
		for (qt = id->quirks; qt->quirks != 0; qt++) {
			if (bhnd_hwrev_matches(hwrev, &qt->hwrev))
				quirks |= qt->quirks;
		};
	}


	return (quirks);
}
Ejemplo n.º 2
0
/**
 * Default implementation of BUS_CHILD_PNPINFO_STR().
 */
static int
bhnd_child_pnpinfo_str(device_t dev, device_t child, char *buf,
    size_t buflen)
{
	if (device_get_parent(child) != dev) {
		return (BUS_CHILD_PNPINFO_STR(device_get_parent(dev), child,
		    buf, buflen));
	}

	snprintf(buf, buflen, "vendor=0x%hx device=0x%hx rev=0x%hhx",
	    bhnd_get_vendor(child), bhnd_get_device(child),
	    bhnd_get_hwrev(child));

	return (0);
}
Ejemplo n.º 3
0
/**
 * Distribute @p clock on backplane.
 * 
 * @param sc Driver instance state.
 * @param clock Clock to enable.
 * 
 * @retval 0 success
 * @retval ENODEV If @p clock is unsupported, or if the device does not
 * 		  support dynamic clock control.
 */
int
bhnd_pwrctl_setclk(struct bhnd_pwrctl_softc *sc, bhnd_clock clock)
{
	uint32_t	scc;

	PWRCTL_LOCK_ASSERT(sc, MA_OWNED);

	/* Is dynamic clock control supported? */
	if (PWRCTL_QUIRK(sc, FIXED_CLK))
		return (ENODEV);

	/* Chips with ccrev 10 are EOL and they don't have SYCC_HR used below */
	if (bhnd_get_hwrev(sc->chipc_dev) == 10)
		return (ENODEV);

	scc = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL);

	switch (clock) {
	case BHND_CLOCK_HT:
		/* fast (pll) clock */
		if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
			scc &= ~(CHIPC_SCC_XC | CHIPC_SCC_FS | CHIPC_SCC_IP);
			scc |= CHIPC_SCC_IP;

			/* force xtal back on before clearing SCC_DYN_XTAL.. */
			bhnd_pwrctl_ungate_clock(sc->chipc_dev, BHND_CLOCK_HT);
		} else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
			scc |= CHIPC_SYCC_HR;
		} else {
			return (ENODEV);
		}

		bhnd_bus_write_4(sc->res, CHIPC_PLL_SLOWCLK_CTL, scc);
		DELAY(CHIPC_PLL_DELAY);

		break;		

	case BHND_CLOCK_DYN:
		/* enable dynamic clock control */
		if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
			scc &= ~(CHIPC_SCC_FS | CHIPC_SCC_IP | CHIPC_SCC_XC);
			if ((scc & CHIPC_SCC_SS_MASK) != CHIPC_SCC_SS_XTAL)
				scc |= CHIPC_SCC_XC;
	
			bhnd_bus_write_4(sc->res, CHIPC_PLL_SLOWCLK_CTL, scc);

			/* for dynamic control, we have to release our xtal_pu
			 * "force on" */
			if (scc & CHIPC_SCC_XC) {
				bhnd_pwrctl_gate_clock(sc->chipc_dev,
				    BHND_CLOCK_HT);
			}
		} else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
			/* Instaclock */
			scc &= ~CHIPC_SYCC_HR;
			bhnd_bus_write_4(sc->res, CHIPC_SYS_CLK_CTL, scc);
		} else {
			return (ENODEV);
		}

		break;

	default:
		return (ENODEV);
	}

	return (0);
}