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:
Adrian Chadd 2013-03-30 04:31:29 +00:00
parent 8eeea2945d
commit a296efdeeb
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=248927

View File

@ -147,45 +147,94 @@ ar933x_flush(struct uart_bas *bas, int what)
}
#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
ar933x_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
int parity)
{
int divisor;
uint8_t lcr;
/* UART always 8 bits */
lcr = 0;
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;
/* UART always 1 stop bit */
/* Set baudrate. */
/* UART parity is controllable by bits 0:1, ignore for now */
/* Set baudrate if required. */
if (baudrate > 0) {
divisor = ar933x_divisor(bas->rclk, baudrate);
if (divisor == 0)
return (EINVAL);
uart_setreg(bas, REG_LCR, lcr | LCR_DLAB);
uart_barrier(bas);
uart_setreg(bas, REG_DLL, divisor & 0xff);
uart_setreg(bas, REG_DLH, (divisor >> 8) & 0xff);
uart_barrier(bas);
uint32_t clock_scale, clock_step;
/* Find the best fit for the given baud rate */
ar933x_uart_get_scale_step(bas, baudrate, &clock_scale,
&clock_step);
/*
* 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);
return (0);
}
#endif
/*
* Low-level UART interface.
@ -209,23 +258,8 @@ static struct uart_ops uart_ar933x_ops = {
static int
ar933x_probe(struct uart_bas *bas)
{
#if 0
u_char val;
/* Check known 0 bits that don't depend on DLAB. */
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
/* We always know this will be here */
return (0);
}
@ -233,43 +267,34 @@ static void
ar933x_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
int parity)
{
#if 0
u_char ier;
uint32_t reg;
if (bas->rclk == 0)
bas->rclk = DEFAULT_RCLK;
/* Setup default parameters */
ar933x_param(bas, baudrate, databits, stopbits, parity);
/* Disable all interrupt sources. */
/*
* We use 0xe0 instead of 0xf0 as the mask because the XScale PXA
* UARTs split the receive time-out interrupt bit out separately as
* 0x10. This gets handled by ier_mask and ier_rxbits below.
*/
ier = uart_getreg(bas, REG_IER) & 0xe0;
uart_setreg(bas, REG_IER, ier);
/* XXX Force enable UART in case it was disabled */
/* Disable all interrupts */
ar933x_setreg(bas, AR933X_UART_INT_EN_REG, 0x00000000);
/* Disable the host interrupt */
reg = ar933x_getreg(bas, AR933X_UART_CS_REG);
reg &= ~AR933X_UART_CS_HOST_INT_EN;
ar933x_setreg(bas, AR933X_UART_CS_REG, reg);
uart_barrier(bas);
/* Disable the FIFO (if present). */
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
/* XXX Set RTS/DTR? */
}
/*
* Detach from console.
*/
static void
ar933x_term(struct uart_bas *bas)
{
#if 0
/* Clear RTS & DTR. */
uart_setreg(bas, REG_MCR, MCR_IE);
uart_barrier(bas);
#endif
/* XXX TODO */
}
static void