提交 a3ae0fc3 编写于 作者: J Jamie Iles 提交者: Greg Kroah-Hartman

8250: add a UPIO_DWAPB32 for 32 bit accesses

Some platforms contain a Synopsys DesignWare APB UART that is attached
to a 32-bit APB bus where sub-word accesses are not allowed. Add a new
IO type (UPIO_DWAPB32) that performs 32 bit acccesses to the UART.

v2:
	- don't test for 32 bit in the output fast path, provide a
	  separate dwabp32_serial_out() function. Refactor
	  dwabp_serial_out() so that we can reuse the LCR saving
	  code.
v3:
	- rebased on top of "8250: use container_of() instead of
	  casting"
Signed-off-by: NJamie Iles <jamie@jamieiles.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
上级 49d5741b
...@@ -454,22 +454,40 @@ static void tsi_serial_out(struct uart_port *p, int offset, int value) ...@@ -454,22 +454,40 @@ static void tsi_serial_out(struct uart_port *p, int offset, int value)
writeb(value, p->membase + offset); writeb(value, p->membase + offset);
} }
static void dwapb_serial_out(struct uart_port *p, int offset, int value) /* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */
static inline void dwapb_save_out_value(struct uart_port *p, int offset,
int value)
{ {
int save_offset = offset;
offset = map_8250_out_reg(p, offset) << p->regshift;
/* Save the LCR value so it can be re-written when a
* Busy Detect interrupt occurs. */
if (save_offset == UART_LCR) {
struct uart_8250_port *up = struct uart_8250_port *up =
container_of(p, struct uart_8250_port, port); container_of(p, struct uart_8250_port, port);
if (offset == UART_LCR)
up->lcr = value; up->lcr = value;
} }
/* Read the IER to ensure any interrupt is cleared before returning from ISR. */
static inline void dwapb_check_clear_ier(struct uart_port *p, int offset)
{
if (offset == UART_TX || offset == UART_IER)
p->serial_in(p, UART_IER);
}
static void dwapb_serial_out(struct uart_port *p, int offset, int value)
{
int save_offset = offset;
offset = map_8250_out_reg(p, offset) << p->regshift;
dwapb_save_out_value(p, save_offset, value);
writeb(value, p->membase + offset); writeb(value, p->membase + offset);
/* Read the IER to ensure any interrupt is cleared before dwapb_check_clear_ier(p, save_offset);
* returning from ISR. */ }
if (save_offset == UART_TX || save_offset == UART_IER)
value = p->serial_in(p, UART_IER); static void dwapb32_serial_out(struct uart_port *p, int offset, int value)
{
int save_offset = offset;
offset = map_8250_out_reg(p, offset) << p->regshift;
dwapb_save_out_value(p, save_offset, value);
writel(value, p->membase + offset);
dwapb_check_clear_ier(p, save_offset);
} }
static unsigned int io_serial_in(struct uart_port *p, int offset) static unsigned int io_serial_in(struct uart_port *p, int offset)
...@@ -520,6 +538,11 @@ static void set_io_from_upio(struct uart_port *p) ...@@ -520,6 +538,11 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = dwapb_serial_out; p->serial_out = dwapb_serial_out;
break; break;
case UPIO_DWAPB32:
p->serial_in = mem32_serial_in;
p->serial_out = dwapb32_serial_out;
break;
default: default:
p->serial_in = io_serial_in; p->serial_in = io_serial_in;
p->serial_out = io_serial_out; p->serial_out = io_serial_out;
...@@ -538,6 +561,7 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value) ...@@ -538,6 +561,7 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)
case UPIO_MEM32: case UPIO_MEM32:
case UPIO_AU: case UPIO_AU:
case UPIO_DWAPB: case UPIO_DWAPB:
case UPIO_DWAPB32:
p->serial_out(p, offset, value); p->serial_out(p, offset, value);
p->serial_in(p, UART_LCR); /* safe, no side-effects */ p->serial_in(p, UART_LCR); /* safe, no side-effects */
break; break;
...@@ -1587,7 +1611,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) ...@@ -1587,7 +1611,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
handled = 1; handled = 1;
end = NULL; end = NULL;
} else if (up->port.iotype == UPIO_DWAPB && } else if ((up->port.iotype == UPIO_DWAPB ||
up->port.iotype == UPIO_DWAPB32) &&
(iir & UART_IIR_BUSY) == UART_IIR_BUSY) { (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* The DesignWare APB UART has an Busy Detect (0x07) /* The DesignWare APB UART has an Busy Detect (0x07)
* interrupt meaning an LCR write attempt occured while the * interrupt meaning an LCR write attempt occured while the
...@@ -2492,6 +2517,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) ...@@ -2492,6 +2517,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_MEM32: case UPIO_MEM32:
case UPIO_MEM: case UPIO_MEM:
case UPIO_DWAPB: case UPIO_DWAPB:
case UPIO_DWAPB32:
if (!up->port.mapbase) if (!up->port.mapbase)
break; break;
...@@ -2529,6 +2555,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) ...@@ -2529,6 +2555,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_MEM32: case UPIO_MEM32:
case UPIO_MEM: case UPIO_MEM:
case UPIO_DWAPB: case UPIO_DWAPB:
case UPIO_DWAPB32:
if (!up->port.mapbase) if (!up->port.mapbase)
break; break;
......
...@@ -2135,6 +2135,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) ...@@ -2135,6 +2135,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
case UPIO_AU: case UPIO_AU:
case UPIO_TSI: case UPIO_TSI:
case UPIO_DWAPB: case UPIO_DWAPB:
case UPIO_DWAPB32:
snprintf(address, sizeof(address), snprintf(address, sizeof(address),
"MMIO 0x%llx", (unsigned long long)port->mapbase); "MMIO 0x%llx", (unsigned long long)port->mapbase);
break; break;
...@@ -2555,6 +2556,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) ...@@ -2555,6 +2556,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
case UPIO_AU: case UPIO_AU:
case UPIO_TSI: case UPIO_TSI:
case UPIO_DWAPB: case UPIO_DWAPB:
case UPIO_DWAPB32:
return (port1->mapbase == port2->mapbase); return (port1->mapbase == port2->mapbase);
} }
return 0; return 0;
......
...@@ -314,6 +314,7 @@ struct uart_port { ...@@ -314,6 +314,7 @@ struct uart_port {
#define UPIO_TSI (5) /* Tsi108/109 type IO */ #define UPIO_TSI (5) /* Tsi108/109 type IO */
#define UPIO_DWAPB (6) /* DesignWare APB UART */ #define UPIO_DWAPB (6) /* DesignWare APB UART */
#define UPIO_RM9000 (7) /* RM9000 type IO */ #define UPIO_RM9000 (7) /* RM9000 type IO */
#define UPIO_DWAPB32 (8) /* DesignWare APB UART (32 bit accesses) */
unsigned int read_status_mask; /* driver specific */ unsigned int read_status_mask; /* driver specific */
unsigned int ignore_status_mask; /* driver specific */ unsigned int ignore_status_mask; /* driver specific */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册