AR933x CPU device improvements:
* Add baud rate and divisor programming code. See below for more information. * Flesh out ar933x_init() to disable interrupts and program the initial console setup. * Remove #if 0'ed code from ar933x_term(). * Explain what these functions do. Now, the baud rate and divisor code comes from Linux, as a submission to the OpenWRT project and Linux kernel from Gabor Juhos <juhosg@openwrt.org>. The original ticket for this code is https://dev.openwrt.org/ticket/12031 . I've contacted Gabor and asked for his permission to also licence the patch in question (which covers this code) to BSD lience and he's agreed. Hence why I'm including it here in FreeBSD. Tested: * AP121 (AR9330)
This commit is contained in:
parent
8eeea2945d
commit
a296efdeeb
@ -147,45 +147,94 @@ ar933x_flush(struct uart_bas *bas, int what)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
/*
|
||||||
|
* Calculate the baud from the given chip configuration parameters.
|
||||||
|
*/
|
||||||
|
static unsigned long
|
||||||
|
ar933x_uart_get_baud(unsigned int clk, unsigned int scale,
|
||||||
|
unsigned int step)
|
||||||
|
{
|
||||||
|
uint64_t t;
|
||||||
|
uint32_t div;
|
||||||
|
|
||||||
|
div = (2 << 16) * (scale + 1);
|
||||||
|
t = clk;
|
||||||
|
t *= step;
|
||||||
|
t += (div / 2);
|
||||||
|
t = t / div;
|
||||||
|
|
||||||
|
return (t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the scale/step with the lowest possible deviation from
|
||||||
|
* the target baudrate.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ar933x_uart_get_scale_step(struct uart_bas *bas, unsigned int baud,
|
||||||
|
unsigned int *scale, unsigned int *step)
|
||||||
|
{
|
||||||
|
unsigned int tscale;
|
||||||
|
uint32_t clk;
|
||||||
|
long min_diff;
|
||||||
|
|
||||||
|
clk = bas->rclk;
|
||||||
|
*scale = 0;
|
||||||
|
*step = 0;
|
||||||
|
|
||||||
|
min_diff = baud;
|
||||||
|
for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) {
|
||||||
|
uint64_t tstep;
|
||||||
|
int diff;
|
||||||
|
|
||||||
|
tstep = baud * (tscale + 1);
|
||||||
|
tstep *= (2 << 16);
|
||||||
|
tstep = tstep / clk;
|
||||||
|
|
||||||
|
if (tstep > AR933X_UART_MAX_STEP)
|
||||||
|
break;
|
||||||
|
|
||||||
|
diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud);
|
||||||
|
if (diff < min_diff) {
|
||||||
|
min_diff = diff;
|
||||||
|
*scale = tscale;
|
||||||
|
*step = tstep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ar933x_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
|
ar933x_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
|
||||||
int parity)
|
int parity)
|
||||||
{
|
{
|
||||||
int divisor;
|
/* UART always 8 bits */
|
||||||
uint8_t lcr;
|
|
||||||
|
|
||||||
lcr = 0;
|
/* UART always 1 stop bit */
|
||||||
if (databits >= 8)
|
|
||||||
lcr |= LCR_8BITS;
|
|
||||||
else if (databits == 7)
|
|
||||||
lcr |= LCR_7BITS;
|
|
||||||
else if (databits == 6)
|
|
||||||
lcr |= LCR_6BITS;
|
|
||||||
else
|
|
||||||
lcr |= LCR_5BITS;
|
|
||||||
if (stopbits > 1)
|
|
||||||
lcr |= LCR_STOPB;
|
|
||||||
lcr |= parity << 3;
|
|
||||||
|
|
||||||
/* Set baudrate. */
|
/* UART parity is controllable by bits 0:1, ignore for now */
|
||||||
|
|
||||||
|
/* Set baudrate if required. */
|
||||||
if (baudrate > 0) {
|
if (baudrate > 0) {
|
||||||
divisor = ar933x_divisor(bas->rclk, baudrate);
|
uint32_t clock_scale, clock_step;
|
||||||
if (divisor == 0)
|
|
||||||
return (EINVAL);
|
/* Find the best fit for the given baud rate */
|
||||||
uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
|
ar933x_uart_get_scale_step(bas, baudrate, &clock_scale,
|
||||||
uart_barrier(bas);
|
&clock_step);
|
||||||
uart_setreg(bas, REG_DLL, divisor & 0xff);
|
|
||||||
uart_setreg(bas, REG_DLH, (divisor >> 8) & 0xff);
|
/*
|
||||||
uart_barrier(bas);
|
* Program the clock register in its entirety - no need
|
||||||
|
* for Read-Modify-Write.
|
||||||
|
*/
|
||||||
|
ar933x_setreg(bas, AR933X_UART_CLOCK_REG,
|
||||||
|
((clock_scale & AR933X_UART_CLOCK_SCALE_M)
|
||||||
|
<< AR933X_UART_CLOCK_SCALE_S) |
|
||||||
|
(clock_step & AR933X_UART_CLOCK_STEP_M));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set LCR and clear DLAB. */
|
|
||||||
uart_setreg(bas, REG_LCR, lcr);
|
|
||||||
uart_barrier(bas);
|
uart_barrier(bas);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Low-level UART interface.
|
* Low-level UART interface.
|
||||||
@ -209,23 +258,8 @@ static struct uart_ops uart_ar933x_ops = {
|
|||||||
static int
|
static int
|
||||||
ar933x_probe(struct uart_bas *bas)
|
ar933x_probe(struct uart_bas *bas)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
u_char val;
|
|
||||||
|
|
||||||
/* Check known 0 bits that don't depend on DLAB. */
|
/* We always know this will be here */
|
||||||
val = uart_getreg(bas, REG_IIR);
|
|
||||||
if (val & 0x30)
|
|
||||||
return (ENXIO);
|
|
||||||
/*
|
|
||||||
* Bit 6 of the MCR (= 0x40) appears to be 1 for the Sun1699
|
|
||||||
* chip, but otherwise doesn't seem to have a function. In
|
|
||||||
* other words, uart(4) works regardless. Ignore that bit so
|
|
||||||
* the probe succeeds.
|
|
||||||
*/
|
|
||||||
val = uart_getreg(bas, REG_MCR);
|
|
||||||
if (val & 0xa0)
|
|
||||||
return (ENXIO);
|
|
||||||
#endif
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,43 +267,34 @@ static void
|
|||||||
ar933x_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
|
ar933x_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
|
||||||
int parity)
|
int parity)
|
||||||
{
|
{
|
||||||
#if 0
|
uint32_t reg;
|
||||||
u_char ier;
|
|
||||||
|
|
||||||
if (bas->rclk == 0)
|
/* Setup default parameters */
|
||||||
bas->rclk = DEFAULT_RCLK;
|
|
||||||
ar933x_param(bas, baudrate, databits, stopbits, parity);
|
ar933x_param(bas, baudrate, databits, stopbits, parity);
|
||||||
|
|
||||||
/* Disable all interrupt sources. */
|
/* XXX Force enable UART in case it was disabled */
|
||||||
/*
|
|
||||||
* We use 0xe0 instead of 0xf0 as the mask because the XScale PXA
|
/* Disable all interrupts */
|
||||||
* UARTs split the receive time-out interrupt bit out separately as
|
ar933x_setreg(bas, AR933X_UART_INT_EN_REG, 0x00000000);
|
||||||
* 0x10. This gets handled by ier_mask and ier_rxbits below.
|
|
||||||
*/
|
/* Disable the host interrupt */
|
||||||
ier = uart_getreg(bas, REG_IER) & 0xe0;
|
reg = ar933x_getreg(bas, AR933X_UART_CS_REG);
|
||||||
uart_setreg(bas, REG_IER, ier);
|
reg &= ~AR933X_UART_CS_HOST_INT_EN;
|
||||||
|
ar933x_setreg(bas, AR933X_UART_CS_REG, reg);
|
||||||
|
|
||||||
uart_barrier(bas);
|
uart_barrier(bas);
|
||||||
|
|
||||||
/* Disable the FIFO (if present). */
|
/* XXX Set RTS/DTR? */
|
||||||
uart_setreg(bas, REG_FCR, 0);
|
|
||||||
uart_barrier(bas);
|
|
||||||
|
|
||||||
/* Set RTS & DTR. */
|
|
||||||
uart_setreg(bas, REG_MCR, MCR_IE | MCR_RTS | MCR_DTR);
|
|
||||||
uart_barrier(bas);
|
|
||||||
|
|
||||||
ar933x_clrint(bas);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detach from console.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
ar933x_term(struct uart_bas *bas)
|
ar933x_term(struct uart_bas *bas)
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
/* Clear RTS & DTR. */
|
/* XXX TODO */
|
||||||
uart_setreg(bas, REG_MCR, MCR_IE);
|
|
||||||
uart_barrier(bas);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Loading…
x
Reference in New Issue
Block a user