コード例 #1
0
ファイル: board_tsc4370.c プロジェクト: ChristosKa/freebsd
/*
 * Allow the master clock frequency to be changed from whatever the bootloader
 * set up, because sometimes it's harder to change/update a bootloader than it
 * is to change/update the kernel once a product is in the field.
 */
static void
master_clock_init(void)
{
	uint32_t mckr = RD4HW(AT91RM92_PMC_BASE, PMC_MCKR);
	int hintvalue = 0;
	int newmckr = 0;

	 /*
	 * If there's a hint that specifies the contents of MCKR, use it
	 * without question (it had better be right).
	 *
	 * If there's a "mckfreq" hint it might be in hertz or mhz (convert the
	 * latter to hz).  Calculate the new MCK divider.  If the CPU frequency
	 * is not a sane multiple of the hinted MCK frequency this is likely to
	 * behave badly.  The moral is: don't hint at impossibilities.
	 */

	if (resource_int_value("at91", 0, "mckr", &hintvalue) == 0) {
		newmckr = hintvalue;
	} else {
		hintvalue = 90; /* Default to 90mhz if not specified. */
		resource_int_value("at91", 0, "mckfreq", &hintvalue);
		if (hintvalue != 0) {
			if (hintvalue < 1000)
				hintvalue *= 1000000;
			if (hintvalue != at91_master_clock) {
				uint32_t divider;
				struct at91_pmc_clock * cpuclk;
				cpuclk = at91_pmc_clock_ref("cpu");
				divider = (cpuclk->hz / hintvalue) - 1;
				newmckr = (mckr & 0xFFFFFCFF) | ((divider & 0x03) << 8);
				at91_pmc_clock_deref(cpuclk);
			}
		}
	}

	/* If the new mckr value is different than what's in the register now,
	 * make the change and wait for the clocks to settle (MCKRDY status).
	 *
	 * MCKRDY will never be asserted unless either the selected clock or the
	 * prescaler value changes (but not both at once) [this is detailed in
	 * the rm9200 errata]. This code assumes the prescaler value is always
	 * zero and that by time we get to here we're running on something other
	 * than the slow clock, so to change the mckr divider we first change
	 * back to the slow clock (keeping prescaler and divider unchanged),
	 * then go back to the original selected clock with the new divider.
	 *
	 * After changing MCK, go re-init everything clock-related, and reset
	 * the baud rate generator for the console (doing this here is kind of a
	 * rude hack, but hey, you do what you have to to run MCK faster).
	 */

	if (newmckr != 0 && newmckr != mckr) {
		if (mckr & 0x03)
			change_mckr(mckr & ~0x03);
		change_mckr(newmckr);
		at91_pmc_init_clock();
		WR4HW(AT91RM92_DBGU_BASE, USART_BRGR, BAUD2DIVISOR(115200));
	}
}
コード例 #2
0
static int
at91_usart_param(struct uart_bas *bas, int baudrate, int databits,
    int stopbits, int parity)
{
	uint32_t mr;

	/*
	 * Assume 3-wire RS-232 configuration.
	 * XXX Not sure how uart will present the other modes to us, so
	 * XXX they are unimplemented.  maybe ioctl?
	 */
	mr = USART_MR_MODE_NORMAL;
	mr |= USART_MR_USCLKS_MCK;	/* Assume MCK */

	/*
	 * Or in the databits requested
	 */
	if (databits < 9)
		mr &= ~USART_MR_MODE9;
	switch (databits) {
	case 5:
		mr |= USART_MR_CHRL_5BITS;
		break;
	case 6:
		mr |= USART_MR_CHRL_6BITS;
		break;
	case 7:
		mr |= USART_MR_CHRL_7BITS;
		break;
	case 8:
		mr |= USART_MR_CHRL_8BITS;
		break;
	case 9:
		mr |= USART_MR_CHRL_8BITS | USART_MR_MODE9;
		break;
	default:
		return (EINVAL);
	}

	/*
	 * Or in the parity
	 */
	switch (parity) {
	case UART_PARITY_NONE:
		mr |= USART_MR_PAR_NONE;
		break;
	case UART_PARITY_ODD:
		mr |= USART_MR_PAR_ODD;
		break;
	case UART_PARITY_EVEN:
		mr |= USART_MR_PAR_EVEN;
		break;
	case UART_PARITY_MARK:
		mr |= USART_MR_PAR_MARK;
		break;
	case UART_PARITY_SPACE:
		mr |= USART_MR_PAR_SPACE;
		break;
	default:
		return (EINVAL);
	}

	/*
	 * Or in the stop bits.  Note: The hardware supports 1.5 stop
	 * bits in async mode, but there's no way to specify that
	 * AFAICT.  Instead, rely on the convention documented at
	 * http://www.lammertbies.nl/comm/info/RS-232_specs.html which
	 * states that 1.5 stop bits are used for 5 bit bytes and
	 * 2 stop bits only for longer bytes.
	 */
	if (stopbits == 1)
		mr |= USART_MR_NBSTOP_1;
	else if (databits > 5)
		mr |= USART_MR_NBSTOP_2;
	else
		mr |= USART_MR_NBSTOP_1_5;

	/*
	 * We want normal plumbing mode too, none of this fancy
	 * loopback or echo mode.
	 */
	mr |= USART_MR_CHMODE_NORMAL;

	mr &= ~USART_MR_MSBF;	/* lsb first */
	mr &= ~USART_MR_CKLO_SCK;	/* Don't drive SCK */

	WR4(bas, USART_MR, mr);

	/*
	 * Set the baud rate (only if we know our master clock rate)
	 */
	if (DEFAULT_RCLK != 0)
		WR4(bas, USART_BRGR, BAUD2DIVISOR(baudrate));

	/*
	 * Set the receive timeout based on the baud rate.  The idea is to
	 * compromise between being responsive on an interactive connection and
	 * giving a bulk data sender a bit of time to queue up a new buffer
	 * without mistaking it for a stopping point in the transmission.  For
	 * 19.2kbps and below, use 20 * bit time (2 characters).  For faster
	 * connections use 500 microseconds worth of bits.
	 */
	if (baudrate <= 19200)
		WR4(bas, USART_RTOR, 20);
	else 
		WR4(bas, USART_RTOR, baudrate / 2000);
	WR4(bas, USART_CR, USART_CR_STTTO);

	/* XXX Need to take possible synchronous mode into account */
	return (0);
}
コード例 #3
0
ファイル: uart_dev_at91usart.c プロジェクト: AhmadTux/freebsd
static int
at91_usart_param(struct uart_bas *bas, int baudrate, int databits,
    int stopbits, int parity)
{
	uint32_t mr;

	/*
	 * Assume 3-wire RS-232 configuration.
	 * XXX Not sure how uart will present the other modes to us, so
	 * XXX they are unimplemented.  maybe ioctl?
	 */
	mr = USART_MR_MODE_NORMAL;
	mr |= USART_MR_USCLKS_MCK;	/* Assume MCK */

	/*
	 * Or in the databits requested
	 */
	if (databits < 9)
		mr &= ~USART_MR_MODE9;
	switch (databits) {
	case 5:
		mr |= USART_MR_CHRL_5BITS;
		break;
	case 6:
		mr |= USART_MR_CHRL_6BITS;
		break;
	case 7:
		mr |= USART_MR_CHRL_7BITS;
		break;
	case 8:
		mr |= USART_MR_CHRL_8BITS;
		break;
	case 9:
		mr |= USART_MR_CHRL_8BITS | USART_MR_MODE9;
		break;
	default:
		return (EINVAL);
	}

	/*
	 * Or in the parity
	 */
	switch (parity) {
	case UART_PARITY_NONE:
		mr |= USART_MR_PAR_NONE;
		break;
	case UART_PARITY_ODD:
		mr |= USART_MR_PAR_ODD;
		break;
	case UART_PARITY_EVEN:
		mr |= USART_MR_PAR_EVEN;
		break;
	case UART_PARITY_MARK:
		mr |= USART_MR_PAR_MARK;
		break;
	case UART_PARITY_SPACE:
		mr |= USART_MR_PAR_SPACE;
		break;
	default:
		return (EINVAL);
	}

	/*
	 * Or in the stop bits.  Note: The hardware supports 1.5 stop
	 * bits in async mode, but there's no way to specify that
	 * AFAICT.  Instead, rely on the convention documented at
	 * http://www.lammertbies.nl/comm/info/RS-232_specs.html which
	 * states that 1.5 stop bits are used for 5 bit bytes and
	 * 2 stop bits only for longer bytes.
	 */
	if (stopbits == 1)
		mr |= USART_MR_NBSTOP_1;
	else if (databits > 5)
		mr |= USART_MR_NBSTOP_2;
	else
		mr |= USART_MR_NBSTOP_1_5;

	/*
	 * We want normal plumbing mode too, none of this fancy
	 * loopback or echo mode.
	 */
	mr |= USART_MR_CHMODE_NORMAL;

	mr &= ~USART_MR_MSBF;	/* lsb first */
	mr &= ~USART_MR_CKLO_SCK;	/* Don't drive SCK */

	WR4(bas, USART_MR, mr);

	/*
	 * Set the baud rate (only if we know our master clock rate)
	 */
	if (DEFAULT_RCLK != 0)
		WR4(bas, USART_BRGR, BAUD2DIVISOR(baudrate));

	/* XXX Need to take possible synchronous mode into account */
	return (0);
}