|
@@ -69,9 +69,11 @@
|
|
|
struct uart_amba_port {
|
|
|
struct uart_port port;
|
|
|
struct clk *clk;
|
|
|
- unsigned int im; /* interrupt mask */
|
|
|
+ unsigned int im; /* interrupt mask */
|
|
|
unsigned int old_status;
|
|
|
- unsigned int ifls; /* vendor-specific */
|
|
|
+ unsigned int ifls; /* vendor-specific */
|
|
|
+ unsigned int lcrh_tx; /* vendor-specific */
|
|
|
+ unsigned int lcrh_rx; /* vendor-specific */
|
|
|
bool autorts;
|
|
|
};
|
|
|
|
|
@@ -79,16 +81,22 @@ struct uart_amba_port {
|
|
|
struct vendor_data {
|
|
|
unsigned int ifls;
|
|
|
unsigned int fifosize;
|
|
|
+ unsigned int lcrh_tx;
|
|
|
+ unsigned int lcrh_rx;
|
|
|
};
|
|
|
|
|
|
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,
|
|
|
};
|
|
|
|
|
|
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,
|
|
|
};
|
|
|
|
|
|
static void pl011_stop_tx(struct uart_port *port)
|
|
@@ -327,12 +335,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
|
|
|
unsigned int lcr_h;
|
|
|
|
|
|
spin_lock_irqsave(&uap->port.lock, flags);
|
|
|
- lcr_h = readw(uap->port.membase + UART011_LCRH);
|
|
|
+ lcr_h = readw(uap->port.membase + uap->lcrh_tx);
|
|
|
if (break_state == -1)
|
|
|
lcr_h |= UART01x_LCRH_BRK;
|
|
|
else
|
|
|
lcr_h &= ~UART01x_LCRH_BRK;
|
|
|
- writew(lcr_h, uap->port.membase + UART011_LCRH);
|
|
|
+ writew(lcr_h, uap->port.membase + uap->lcrh_tx);
|
|
|
spin_unlock_irqrestore(&uap->port.lock, flags);
|
|
|
}
|
|
|
|
|
@@ -393,7 +401,17 @@ static int pl011_startup(struct uart_port *port)
|
|
|
writew(cr, uap->port.membase + UART011_CR);
|
|
|
writew(0, uap->port.membase + UART011_FBRD);
|
|
|
writew(1, uap->port.membase + UART011_IBRD);
|
|
|
- writew(0, uap->port.membase + UART011_LCRH);
|
|
|
+ writew(0, uap->port.membase + uap->lcrh_rx);
|
|
|
+ if (uap->lcrh_tx != uap->lcrh_rx) {
|
|
|
+ int i;
|
|
|
+ /*
|
|
|
+ * Wait 10 PCLKs before writing LCRH_TX register,
|
|
|
+ * to get this delay write read only register 10 times
|
|
|
+ */
|
|
|
+ for (i = 0; i < 10; ++i)
|
|
|
+ writew(0xff, uap->port.membase + UART011_MIS);
|
|
|
+ writew(0, uap->port.membase + uap->lcrh_tx);
|
|
|
+ }
|
|
|
writew(0, uap->port.membase + UART01x_DR);
|
|
|
while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
|
|
|
barrier();
|
|
@@ -422,10 +440,19 @@ static int pl011_startup(struct uart_port *port)
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
+static void pl011_shutdown_channel(struct uart_amba_port *uap,
|
|
|
+ unsigned int lcrh)
|
|
|
+{
|
|
|
+ unsigned long val;
|
|
|
+
|
|
|
+ val = readw(uap->port.membase + lcrh);
|
|
|
+ val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
|
|
|
+ writew(val, uap->port.membase + lcrh);
|
|
|
+}
|
|
|
+
|
|
|
static void pl011_shutdown(struct uart_port *port)
|
|
|
{
|
|
|
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
|
|
- unsigned long val;
|
|
|
|
|
|
/*
|
|
|
* disable all interrupts
|
|
@@ -450,9 +477,9 @@ static void pl011_shutdown(struct uart_port *port)
|
|
|
/*
|
|
|
* disable break condition and fifos
|
|
|
*/
|
|
|
- val = readw(uap->port.membase + UART011_LCRH);
|
|
|
- val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN);
|
|
|
- writew(val, uap->port.membase + UART011_LCRH);
|
|
|
+ pl011_shutdown_channel(uap, uap->lcrh_rx);
|
|
|
+ if (uap->lcrh_rx != uap->lcrh_tx)
|
|
|
+ pl011_shutdown_channel(uap, uap->lcrh_tx);
|
|
|
|
|
|
/*
|
|
|
* Shut down the clock producer
|
|
@@ -561,7 +588,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
* NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
|
|
|
* ----------^----------^----------^----------^-----
|
|
|
*/
|
|
|
- writew(lcr_h, port->membase + UART011_LCRH);
|
|
|
+ writew(lcr_h, port->membase + uap->lcrh_rx);
|
|
|
+ if (uap->lcrh_rx != uap->lcrh_tx) {
|
|
|
+ int i;
|
|
|
+ /*
|
|
|
+ * Wait 10 PCLKs before writing LCRH_TX register,
|
|
|
+ * to get this delay write read only register 10 times
|
|
|
+ */
|
|
|
+ for (i = 0; i < 10; ++i)
|
|
|
+ writew(0xff, uap->port.membase + UART011_MIS);
|
|
|
+ writew(lcr_h, port->membase + uap->lcrh_tx);
|
|
|
+ }
|
|
|
writew(old_cr, port->membase + UART011_CR);
|
|
|
|
|
|
spin_unlock_irqrestore(&port->lock, flags);
|
|
@@ -688,7 +725,7 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud,
|
|
|
if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) {
|
|
|
unsigned int lcr_h, ibrd, fbrd;
|
|
|
|
|
|
- lcr_h = readw(uap->port.membase + UART011_LCRH);
|
|
|
+ lcr_h = readw(uap->port.membase + uap->lcrh_tx);
|
|
|
|
|
|
*parity = 'n';
|
|
|
if (lcr_h & UART01x_LCRH_PEN) {
|
|
@@ -800,6 +837,8 @@ 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->port.dev = &dev->dev;
|
|
|
uap->port.mapbase = dev->res.start;
|
|
|
uap->port.membase = base;
|