/* * 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)); } }
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); }
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); }