Skip to content

Commit

Permalink
ARM: 6158/2: PL011 baudrate extension for ST-Ericssons derivative
Browse files Browse the repository at this point in the history
Implementation of the ST-Ericsson baudrate extension in the PL011
block. In this modified variant it is possible to change the
sampling factor from 16 to 8, and thanks to this we can get higher
baudrates while still using the same peripheral clock.

Also replace the simple division to determine the baud divisor
with DIV_ROUND_CLOSEST() rather than a simple integer division.

Cc: Alessandro Rubini <rubini@unipv.it>
Cc: Jerzy Kasenberg <jerzy.kasenberg@tieto.com>
Signed-off-by: Marcin Mielczarczyk <marcin.mielczarczyk@tieto.com>
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Linus Walleij authored and Russell King committed Jul 27, 2010
1 parent ec489aa commit ac3e3fb
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
27 changes: 25 additions & 2 deletions drivers/serial/amba-pl011.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ struct uart_amba_port {
unsigned int ifls; /* vendor-specific */
unsigned int lcrh_tx; /* vendor-specific */
unsigned int lcrh_rx; /* vendor-specific */
bool oversampling; /* vendor-specific */
bool autorts;
};

Expand All @@ -83,20 +84,23 @@ struct vendor_data {
unsigned int fifosize;
unsigned int lcrh_tx;
unsigned int lcrh_rx;
bool oversampling;
};

static struct vendor_data vendor_arm = {
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
.fifosize = 16,
.lcrh_tx = UART011_LCRH,
.lcrh_rx = UART011_LCRH,
.oversampling = false,
};

static struct vendor_data vendor_st = {
.ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
.fifosize = 64,
.lcrh_tx = ST_UART011_LCRH_TX,
.lcrh_rx = ST_UART011_LCRH_RX,
.oversampling = true,
};

static void pl011_stop_tx(struct uart_port *port)
Expand Down Expand Up @@ -499,8 +503,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = port->uartclk * 4 / baud;
baud = uart_get_baud_rate(port, termios, old, 0,
port->uartclk/(uap->oversampling ? 8 : 16));

if (baud > port->uartclk/16)
quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
else
quot = DIV_ROUND_CLOSEST(port->uartclk * 4, baud);

switch (termios->c_cflag & CSIZE) {
case CS5:
Expand Down Expand Up @@ -579,6 +588,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
uap->autorts = false;
}

if (uap->oversampling) {
if (baud > port->uartclk/16)
old_cr |= ST_UART011_CR_OVSFACT;
else
old_cr &= ~ST_UART011_CR_OVSFACT;
}

/* Set baud rate */
writew(quot & 0x3f, port->membase + UART011_FBRD);
writew(quot >> 6, port->membase + UART011_IBRD);
Expand Down Expand Up @@ -744,6 +760,12 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
fbrd = readw(uap->port.membase + UART011_FBRD);

*baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd);

if (uap->oversampling) {
if (readw(uap->port.membase + UART011_CR)
& ST_UART011_CR_OVSFACT)
*baud *= 2;
}
}
}

Expand Down Expand Up @@ -839,6 +861,7 @@ static int pl011_probe(struct amba_device *dev, struct amba_id *id)
uap->ifls = vendor->ifls;
uap->lcrh_rx = vendor->lcrh_rx;
uap->lcrh_tx = vendor->lcrh_tx;
uap->oversampling = vendor->oversampling;
uap->port.dev = &dev->dev;
uap->port.mapbase = dev->res.start;
uap->port.membase = base;
Expand Down
1 change: 1 addition & 0 deletions include/linux/amba/serial.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
#define UART010_CR_TIE 0x0020
#define UART010_CR_RIE 0x0010
#define UART010_CR_MSIE 0x0008
#define ST_UART011_CR_OVSFACT 0x0008 /* Oversampling factor */
#define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */
#define UART01x_CR_SIREN 0x0002 /* SIR enable */
#define UART01x_CR_UARTEN 0x0001 /* UART enable */
Expand Down

0 comments on commit ac3e3fb

Please sign in to comment.