Пример #1
0
/**
 * If required by this device, revert any GPIO/pin configuration applied
 * to allow SPROM access.
 * 
 * @param sc chipc driver state.
 */
static void
chipc_disable_sprom_pins(struct chipc_softc *sc)
{
	uint32_t		 cctrl;

	/* Nothing to do? */
	if (!CHIPC_QUIRK(sc, MUX_SPROM))
		return;

	CHIPC_LOCK_ASSERT(sc, MA_OWNED);
	KASSERT(sc->sprom_refcnt != 0, ("sprom pins already disabled"));
	KASSERT(sc->sprom_refcnt == 1, ("sprom pins in use"));

	cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);

	/* 4331 devices */
	if (CHIPC_QUIRK(sc, 4331_EXTPA_MUX_SPROM)) {
		cctrl |= CHIPC_CCTRL4331_EXTPA_EN;

		if (CHIPC_QUIRK(sc, 4331_GPIO2_5_MUX_SPROM))
			cctrl |= CHIPC_CCTRL4331_EXTPA_ON_GPIO2_5;

		if (CHIPC_QUIRK(sc, 4331_EXTPA2_MUX_SPROM))
			cctrl |= CHIPC_CCTRL4331_EXTPA_EN2;

		bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
		return;
	}

	/* 4360 devices */
	if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) {
		/* Unimplemented */
	}
}
Пример #2
0
/**
 * Determine the preferred NVRAM data source.
 */
static bhnd_nvram_src_t
chipc_nvram_src(device_t dev)
{
	struct chipc_softc	*sc;
	uint32_t		 srom_ctrl;

	sc = device_get_softc(dev);

	/* Very early devices always included a SPROM */
	if (CHIPC_QUIRK(sc, ALWAYS_HAS_SPROM))
		return (BHND_NVRAM_SRC_SPROM);

	/* Most other early devices require checking ChipStatus flags */
	if (CHIPC_QUIRK(sc, SPROM_CHECK_CHIPST))
		return (chipc_nvram_src_chipst(sc));

	/*
	 * Later chipset revisions standardized the NVRAM capability flags and
	 * register interfaces.
	 * 
	 * We check for hardware presence in order of precedence. For example,
	 * SPROM is is always used in preference to internal OTP if found.
	 */
	if (CHIPC_CAP(sc, CAP_SPROM)) {
		srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL);
		if (srom_ctrl & CHIPC_SRC_PRESENT)
			return (BHND_NVRAM_SRC_SPROM);
	}

	/* Check for OTP */
	if (CHIPC_CAP(sc, CAP_OTP_SIZE))
		return (BHND_NVRAM_SRC_OTP);

	/*
	 * Finally, Northstar chipsets (and possibly other chipsets?) support
	 * external NAND flash. 
	 */
	if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH))
		return (BHND_NVRAM_SRC_NFLASH);

	/* No NVRAM hardware capability declared */
	return (BHND_NVRAM_SRC_NONE);
}
Пример #3
0
/**
 * If required by this device, enable access to the SPROM.
 * 
 * @param sc chipc driver state.
 */
static int
chipc_enable_sprom_pins(struct chipc_softc *sc)
{
	uint32_t		 cctrl;

	CHIPC_LOCK_ASSERT(sc, MA_OWNED);
	KASSERT(sc->sprom_refcnt == 0, ("sprom pins already enabled"));

	/* Nothing to do? */
	if (!CHIPC_QUIRK(sc, MUX_SPROM))
		return (0);

	/* Check whether bus is busy */
	if (!chipc_should_enable_muxed_sprom(sc))
		return (EBUSY);

	cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);

	/* 4331 devices */
	if (CHIPC_QUIRK(sc, 4331_EXTPA_MUX_SPROM)) {
		cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN;

		if (CHIPC_QUIRK(sc, 4331_GPIO2_5_MUX_SPROM))
			cctrl &= ~CHIPC_CCTRL4331_EXTPA_ON_GPIO2_5;

		if (CHIPC_QUIRK(sc, 4331_EXTPA2_MUX_SPROM))
			cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN2;

		bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
		return (0);
	}

	/* 4360 devices */
	if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) {
		/* Unimplemented */
	}

	/* Refuse to proceed on unsupported devices with muxed SPROM pins */
	device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
	return (ENXIO);
}
Пример #4
0
/**
 * Use device-specific ChipStatus flags to determine the preferred NVRAM
 * data source.
 */
static bhnd_nvram_src_t
chipc_nvram_src_chipst(struct chipc_softc *sc)
{
	uint8_t		nvram_sel;

	CHIPC_ASSERT_QUIRK(sc, SPROM_CHECK_CHIPST);

	if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R22)) {
		// TODO: On these devices, the official driver code always
		// assumes SPROM availability if CHIPC_CST_OTP_SEL is not
		// set; we must review against the actual behavior of our
		// BCM4312 hardware
		nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R22);
	} else if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R23)) {
		nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R23);
	} else {
		panic("invalid CST OTP/SPROM chipc quirk flags");
	}
	device_printf(sc->dev, "querying chipst for 0x%x, 0x%x\n", sc->ccid.chip_id, sc->cst);

	switch (nvram_sel) {
	case CHIPC_CST_DEFCIS_SEL:
		return (BHND_NVRAM_SRC_CIS);

	case CHIPC_CST_SPROM_SEL:
	case CHIPC_CST_OTP_PWRDN:
		return (BHND_NVRAM_SRC_SPROM);

	case CHIPC_CST_OTP_SEL:
		return (BHND_NVRAM_SRC_OTP);

	default:
		device_printf(sc->dev, "unrecognized OTP/SPROM type 0x%hhx",
		    nvram_sel);
		return (BHND_NVRAM_SRC_NONE);
	}
}
Пример #5
0
/**
 * Determine the NVRAM data source for this device.
 * 
 * The SPROM, OTP, and flash capability flags must be fully populated in
 * @p caps.
 *
 * @param sc chipc driver state.
 * @param caps capability flags to be used to derive NVRAM configuration.
 */
static bhnd_nvram_src
chipc_find_nvram_src(struct chipc_softc *sc, struct chipc_caps *caps)
{
	uint32_t		 otp_st, srom_ctrl;

	/*
	 * We check for hardware presence in order of precedence. For example,
	 * SPROM is is always used in preference to internal OTP if found.
	 */
	if (CHIPC_QUIRK(sc, SUPPORTS_SPROM) && caps->sprom) {
		srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL);
		if (srom_ctrl & CHIPC_SRC_PRESENT)
			return (BHND_NVRAM_SRC_SPROM);
	}

	/* Check for programmed OTP H/W subregion (contains SROM data) */
	if (CHIPC_QUIRK(sc, SUPPORTS_OTP) && caps->otp_size > 0) {
		/* TODO: need access to HND-OTP device */
		if (!CHIPC_QUIRK(sc, OTP_HND)) {
			device_printf(sc->dev,
			    "NVRAM unavailable: unsupported OTP controller.\n");
			return (BHND_NVRAM_SRC_UNKNOWN);
		}

		otp_st = bhnd_bus_read_4(sc->core, CHIPC_OTPST);
		if (otp_st & CHIPC_OTPS_GUP_HW)
			return (BHND_NVRAM_SRC_OTP);
	}

	/* Check for flash */
	if (caps->flash_type != CHIPC_FLASH_NONE)
		return (BHND_NVRAM_SRC_FLASH);

	/* No NVRAM hardware capability declared */
	return (BHND_NVRAM_SRC_UNKNOWN);
}
Пример #6
0
/**
 * Examine bus state and make a best effort determination of whether it's
 * likely safe to enable the muxed SPROM pins.
 * 
 * On devices that do not use SPROM pin muxing, always returns true.
 * 
 * @param sc chipc driver state.
 */
static bool
chipc_should_enable_muxed_sprom(struct chipc_softc *sc)
{
	device_t	*devs;
	device_t	 hostb;
	device_t	 parent;
	int		 devcount;
	int		 error;
	bool		 result;

	/* Nothing to do? */
	if (!CHIPC_QUIRK(sc, MUX_SPROM))
		return (true);

	mtx_lock(&Giant);	/* for newbus */

	parent = device_get_parent(sc->dev);
	hostb = bhnd_find_hostb_device(parent);

	if ((error = device_get_children(parent, &devs, &devcount))) {
		mtx_unlock(&Giant);
		return (false);
	}

	/* Reject any active devices other than ChipCommon, or the
	 * host bridge (if any). */
	result = true;
	for (int i = 0; i < devcount; i++) {
		if (devs[i] == hostb || devs[i] == sc->dev)
			continue;

		if (!device_is_attached(devs[i]))
			continue;

		if (device_is_suspended(devs[i]))
			continue;

		/* Active device; assume SPROM is busy */
		result = false;
		break;
	}

	free(devs, M_TEMP);
	mtx_unlock(&Giant);
	return (result);
}
Пример #7
0
/* Read and parse chipc capabilities */
static int
chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps)
{
	uint32_t	cap_reg;
	uint32_t	cap_ext_reg;
	uint32_t	regval;

	/* Fetch cap registers */
	cap_reg = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
	cap_ext_reg = 0;
	if (CHIPC_QUIRK(sc, SUPPORTS_CAP_EXT))
		cap_ext_reg = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES_EXT);

	/* Extract values */
	caps->num_uarts		= CHIPC_GET_BITS(cap_reg, CHIPC_CAP_NUM_UART);
	caps->mipseb		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_MIPSEB);
	caps->uart_gpio		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_UARTGPIO);
	caps->uart_clock	= CHIPC_GET_BITS(cap_reg, CHIPC_CAP_UCLKSEL);

	caps->extbus_type	= CHIPC_GET_BITS(cap_reg, CHIPC_CAP_EXTBUS);
	caps->pwr_ctrl		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PWR_CTL);
	caps->jtag_master	= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_JTAGP);

	caps->pll_type		= CHIPC_GET_BITS(cap_reg, CHIPC_CAP_PLL);
	caps->backplane_64	= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_BKPLN64);
	caps->boot_rom		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_ROM);
	caps->pmu		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PMU);
	caps->eci		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_ECI);
	caps->sprom		= CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_SPROM);
	caps->otp_size		= CHIPC_GET_BITS(cap_reg, CHIPC_CAP_OTP_SIZE);

	caps->seci		= CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_SECI);
	caps->gsio		= CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_GSIO);
	caps->aob		= CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_AOB);

	/* Fetch OTP size for later IPX controller revisions */
	if (CHIPC_QUIRK(sc, IPX_OTPL_SIZE)) {
		regval = bhnd_bus_read_4(sc->core, CHIPC_OTPLAYOUT);
		caps->otp_size = CHIPC_GET_BITS(regval, CHIPC_OTPL_SIZE);
	}

	/* Determine flash type and parameters */
	caps->cfi_width = 0;
	switch (CHIPC_GET_BITS(cap_reg, CHIPC_CAP_FLASH)) {
	case CHIPC_CAP_SFLASH_ST:
		caps->flash_type = CHIPC_SFLASH_ST;
		break;
	case CHIPC_CAP_SFLASH_AT:
		caps->flash_type = CHIPC_SFLASH_AT;
		break;
	case CHIPC_CAP_NFLASH:
		/* unimplemented */
		caps->flash_type = CHIPC_NFLASH;
		break;
	case CHIPC_CAP_PFLASH:
		caps->flash_type = CHIPC_PFLASH_CFI;

		/* determine cfi width */
		regval = bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG);
		if (CHIPC_GET_FLAG(regval, CHIPC_FLASH_CFG_DS))
			caps->cfi_width = 2;
		else
			caps->cfi_width = 1;

		break;
	case CHIPC_CAP_FLASH_NONE:
		caps->flash_type = CHIPC_FLASH_NONE;
		break;
			
	}

	/* Handle 4706_NFLASH fallback */
	if (CHIPC_QUIRK(sc, 4706_NFLASH) &&
	    CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_4706_NFLASH))
	{
		caps->flash_type = CHIPC_NFLASH_4706;
	}


	/* Determine NVRAM source. Must occur after the SPROM/OTP/flash
	 * capability flags have been populated. */
	caps->nvram_src = chipc_find_nvram_src(sc, caps);

	/* Determine the SPROM offset within OTP (if any). SPROM-formatted
	 * data is placed within the OTP general use region. */
	caps->sprom_offset = 0;
	if (caps->nvram_src == BHND_NVRAM_SRC_OTP) {
		CHIPC_ASSERT_QUIRK(sc, OTP_IPX);

		/* Bit offset to GUP HW subregion containing SPROM data */
		regval = bhnd_bus_read_4(sc->core, CHIPC_OTPLAYOUT);
		caps->sprom_offset = CHIPC_GET_BITS(regval, CHIPC_OTPL_GUP);

		/* Convert to bytes */
		caps->sprom_offset /= 8;
	}

	return (0);
}