Exemplo n.º 1
0
bool
spi_start_clock(sdioh_info_t *sd, uint16 div)
{
	spih_info_t *si = (spih_info_t *)sd->controller;
	osl_t *osh = si->osh;
	spih_regs_t *regs = si->regs;
	uint32 t, espr, disp;
	uint32 disp_xtal_freq;
	bool	ext_clock = FALSE;
	char disp_string[5];

	if (div > 2048) {
		sd_err(("%s: divisor %d too large; using max of 2048\n", __FUNCTION__, div));
		div = 2048;
	} else if (div & (div - 1)) {	
		
		while ((div + 1) & div)
			div |= div >> 1;
		div++;
	}

	
	if (si->rev >= 5) {
		uint32 clk_tick;
		
		if (!sdspi_switch_clock(sd, TRUE)) {
			sd_err(("%s: error switching to external clock\n", __FUNCTION__));
		}

		
		clk_tick = SPIPCI_RREG(osh, &regs->spih_clk_count);
		if (clk_tick == SPIPCI_RREG(osh, &regs->spih_clk_count)) {

			
			if (!sdspi_switch_clock(sd, FALSE)) {
				sd_err(("%s: error switching to external clock\n", __FUNCTION__));
			}
		} else {
			ext_clock = TRUE;
		}
	}

	
	if (div == 0) {
		ext_clock = FALSE;
		div = 2;

		
		if (!sdspi_switch_clock(sd, FALSE)) {
			sd_err(("%s: error switching to external clock\n", __FUNCTION__));
		}

		sd_err(("%s: Ok to hot-swap oscillators.\n", __FUNCTION__));
	}

	
	if (ext_clock == TRUE) {
		uint32 xtal_freq;

		OSL_DELAY(1000);
		xtal_freq = SPIPCI_RREG(osh, &regs->spih_xtal_freq) * 10000;

		sd_info(("%s: Oscillator is %dHz\n", __FUNCTION__, xtal_freq));


		disp_xtal_freq = xtal_freq / 10000;

		
		if ((disp_xtal_freq % 100) > 50) {
			disp_xtal_freq += 100;
		}

		disp_xtal_freq = (disp_xtal_freq / 100) * 100;
	} else {
		sd_err(("%s: no external oscillator installed, using PCI clock.\n", __FUNCTION__));
		disp_xtal_freq = 3333;
	}

	
	sprintf(disp_string, "%04d", disp_xtal_freq / div);

	disp  = (disp_string[0] - '0') << 12;
	disp |= (disp_string[1] - '0') << 8;
	disp |= (disp_string[2] - '0') << 4;
	disp |= (disp_string[3] - '0');

	
	switch (div) {
		case 1:		espr = 0x0; break;
		case 2:		espr = 0x1; break;
		case 4:		espr = 0x2; break;
		case 8:		espr = 0x5; break;
		case 16:	espr = 0x3; break;
		case 32:	espr = 0x4; break;
		case 64:	espr = 0x6; break;
		case 128:	espr = 0x7; break;
		case 256:	espr = 0x8; break;
		case 512:	espr = 0x9; break;
		case 1024:	espr = 0xa; break;
		case 2048:	espr = 0xb; break;
		default:	espr = 0x0; ASSERT(0); break;
	}

	t = SPIPCI_RREG(osh, &regs->spih_ctrl);
	t &= ~3;
	t |= espr & 3;
	SPIPCI_WREG(osh, &regs->spih_ctrl, t);

	t = SPIPCI_RREG(osh, &regs->spih_ext);
	t &= ~3;
	t |= (espr >> 2) & 3;
	SPIPCI_WREG(osh, &regs->spih_ext, t);

	SPIPCI_WREG(osh, &regs->spih_hex_disp, disp);

	
	if (si->rev < 8) {
		
		OSL_DELAY(5000);
	}

	sd_info(("%s: SPI_CTRL=0x%08x SPI_EXT=0x%08x\n",
	         __FUNCTION__,
	         SPIPCI_RREG(osh, &regs->spih_ctrl),
	         SPIPCI_RREG(osh, &regs->spih_ext)));

	return TRUE;
}
Exemplo n.º 2
0
/* Configure PCI-SPI Host Controller's SPI Clock rate as a divisor into the
 * base clock rate.  The base clock is either the PCI Clock (33MHz) or the
 * external clock oscillator at U17 on the PciSpiHost.
 */
bool
spi_start_clock(sdioh_info_t *sd, uint16 div)
{
	spih_info_t *si = (spih_info_t *)sd->controller;
	osl_t *osh = si->osh;
	spih_regs_t *regs = si->regs;
	uint32 t, espr, disp;
	uint32 disp_xtal_freq;
	bool	ext_clock = FALSE;
	char disp_string[5];

	if (div > 2048) {
		sd_err(("%s: divisor %d too large; using max of 2048\n", __FUNCTION__, div));
		div = 2048;
	} else if (div & (div - 1)) {	/* Not a power of 2? */
		/* Round up to a power of 2 */
		while ((div + 1) & div)
			div |= div >> 1;
		div++;
	}

	/* For FPGA Rev >= 5, the use of an external clock oscillator is supported.
	 * If the oscillator is populated, use it to provide the SPI base clock,
	 * otherwise, default to the PCI clock as the SPI base clock.
	 */
	if (si->rev >= 5) {
		uint32 clk_tick;
		/* Enable the External Clock Oscillator as PLL clock source. */
		if (!sdspi_switch_clock(sd, TRUE)) {
			sd_err(("%s: error switching to external clock\n", __FUNCTION__));
		}

		/* Check to make sure the external clock is running.  If not, then it
		 * is not populated on the card, so we will default to the PCI clock.
		 */
		clk_tick = SPIPCI_RREG(osh, &regs->spih_clk_count);
		if (clk_tick == SPIPCI_RREG(osh, &regs->spih_clk_count)) {

			/* Switch back to the PCI clock as the clock source. */
			if (!sdspi_switch_clock(sd, FALSE)) {
				sd_err(("%s: error switching to external clock\n", __FUNCTION__));
			}
		} else {
			ext_clock = TRUE;
		}
	}

	/* Hack to allow hot-swapping oscillators:
	 * 1. Force PCI clock as clock source, using sd_divisor of 0.
	 * 2. Swap oscillator
	 * 3. Set desired sd_divisor (will switch to external oscillator as clock source.
	 */
	if (div == 0) {
		ext_clock = FALSE;
		div = 2;

		/* Select PCI clock as the clock source. */
		if (!sdspi_switch_clock(sd, FALSE)) {
			sd_err(("%s: error switching to external clock\n", __FUNCTION__));
		}

		sd_err(("%s: Ok to hot-swap oscillators.\n", __FUNCTION__));
	}

	/* If using the external oscillator, read the clock frequency from the controller
	 * The value read is in units of 10000Hz, and it's not a nice round number because
	 * it is calculated by the FPGA.  So to make up for that, we round it off.
	 */
	if (ext_clock == TRUE) {
		uint32 xtal_freq;

		OSL_DELAY(1000);
		xtal_freq = SPIPCI_RREG(osh, &regs->spih_xtal_freq) * 10000;

		sd_info(("%s: Oscillator is %dHz\n", __FUNCTION__, xtal_freq));

		disp_xtal_freq = xtal_freq / 10000;

		/* Round it off to a nice number. */
		if ((disp_xtal_freq % 100) > 50) {
			disp_xtal_freq += 100;
		}

		disp_xtal_freq = (disp_xtal_freq / 100) * 100;
	} else {
		sd_err(("%s: no external oscillator installed, using PCI clock.\n", __FUNCTION__));
		disp_xtal_freq = 3333;
	}

	/* Convert the SPI Clock frequency to BCD format. */
	sprintf(disp_string, "%04d", disp_xtal_freq / div);

	disp  = (disp_string[0] - '0') << 12;
	disp |= (disp_string[1] - '0') << 8;
	disp |= (disp_string[2] - '0') << 4;
	disp |= (disp_string[3] - '0');

	/* Select the correct ESPR register value based on the divisor. */
	switch (div) {
		case 1:		espr = 0x0; break;
		case 2:		espr = 0x1; break;
		case 4:		espr = 0x2; break;
		case 8:		espr = 0x5; break;
		case 16:	espr = 0x3; break;
		case 32:	espr = 0x4; break;
		case 64:	espr = 0x6; break;
		case 128:	espr = 0x7; break;
		case 256:	espr = 0x8; break;
		case 512:	espr = 0x9; break;
		case 1024:	espr = 0xa; break;
		case 2048:	espr = 0xb; break;
		default:	espr = 0x0; ASSERT(0); break;
	}

	t = SPIPCI_RREG(osh, &regs->spih_ctrl);
	t &= ~3;
	t |= espr & 3;
	SPIPCI_WREG(osh, &regs->spih_ctrl, t);

	t = SPIPCI_RREG(osh, &regs->spih_ext);
	t &= ~3;
	t |= (espr >> 2) & 3;
	SPIPCI_WREG(osh, &regs->spih_ext, t);

	SPIPCI_WREG(osh, &regs->spih_hex_disp, disp);

	/* For Rev 8, writing to the PLL_CTRL register resets
	 * the PLL, and it can re-acquire in 200uS.  For
	 * Rev 7 and older, we use a software delay to allow
	 * the PLL to re-acquire, which takes more than 2mS.
	 */
	if (si->rev < 8) {
		/* Wait for clock to settle. */
		OSL_DELAY(5000);
	}

	sd_info(("%s: SPI_CTRL=0x%08x SPI_EXT=0x%08x\n",
	         __FUNCTION__,
	         SPIPCI_RREG(osh, &regs->spih_ctrl),
	         SPIPCI_RREG(osh, &regs->spih_ext)));

	return TRUE;
}