diff options
author | Jamie Iles <jamie@jamieiles.com> | 2010-12-01 18:39:36 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-12-10 18:19:38 -0500 |
commit | a3ae0fc34f58e7163b7724feb3d77aa4603f0dc3 (patch) | |
tree | 05c435ba0ee0b071e3c45bcef33eac9f1fd37e80 /drivers/serial | |
parent | 49d5741be27aa90301b89bf254972b355ed9c8ee (diff) |
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: Jamie Iles <jamie@jamieiles.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/8250.c | 51 | ||||
-rw-r--r-- | drivers/serial/serial_core.c | 2 |
2 files changed, 41 insertions, 12 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 0b4ce47d9871..9839199c1d1d 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c | |||
@@ -454,22 +454,40 @@ static void tsi_serial_out(struct uart_port *p, int offset, int value) | |||
454 | writeb(value, p->membase + offset); | 454 | writeb(value, p->membase + offset); |
455 | } | 455 | } |
456 | 456 | ||
457 | /* Save the LCR value so it can be re-written when a Busy Detect IRQ occurs. */ | ||
458 | static inline void dwapb_save_out_value(struct uart_port *p, int offset, | ||
459 | int value) | ||
460 | { | ||
461 | struct uart_8250_port *up = | ||
462 | container_of(p, struct uart_8250_port, port); | ||
463 | |||
464 | if (offset == UART_LCR) | ||
465 | up->lcr = value; | ||
466 | } | ||
467 | |||
468 | /* Read the IER to ensure any interrupt is cleared before returning from ISR. */ | ||
469 | static inline void dwapb_check_clear_ier(struct uart_port *p, int offset) | ||
470 | { | ||
471 | if (offset == UART_TX || offset == UART_IER) | ||
472 | p->serial_in(p, UART_IER); | ||
473 | } | ||
474 | |||
457 | static void dwapb_serial_out(struct uart_port *p, int offset, int value) | 475 | static void dwapb_serial_out(struct uart_port *p, int offset, int value) |
458 | { | 476 | { |
459 | int save_offset = offset; | 477 | int save_offset = offset; |
460 | offset = map_8250_out_reg(p, offset) << p->regshift; | 478 | offset = map_8250_out_reg(p, offset) << p->regshift; |
461 | /* Save the LCR value so it can be re-written when a | 479 | dwapb_save_out_value(p, save_offset, value); |
462 | * Busy Detect interrupt occurs. */ | ||
463 | if (save_offset == UART_LCR) { | ||
464 | struct uart_8250_port *up = | ||
465 | container_of(p, struct uart_8250_port, port); | ||
466 | up->lcr = value; | ||
467 | } | ||
468 | writeb(value, p->membase + offset); | 480 | writeb(value, p->membase + offset); |
469 | /* Read the IER to ensure any interrupt is cleared before | 481 | dwapb_check_clear_ier(p, save_offset); |
470 | * returning from ISR. */ | 482 | } |
471 | if (save_offset == UART_TX || save_offset == UART_IER) | 483 | |
472 | value = p->serial_in(p, UART_IER); | 484 | static void dwapb32_serial_out(struct uart_port *p, int offset, int value) |
485 | { | ||
486 | int save_offset = offset; | ||
487 | offset = map_8250_out_reg(p, offset) << p->regshift; | ||
488 | dwapb_save_out_value(p, save_offset, value); | ||
489 | writel(value, p->membase + offset); | ||
490 | dwapb_check_clear_ier(p, save_offset); | ||
473 | } | 491 | } |
474 | 492 | ||
475 | static unsigned int io_serial_in(struct uart_port *p, int offset) | 493 | 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 | p->serial_out = dwapb_serial_out; | 538 | p->serial_out = dwapb_serial_out; |
521 | break; | 539 | break; |
522 | 540 | ||
541 | case UPIO_DWAPB32: | ||
542 | p->serial_in = mem32_serial_in; | ||
543 | p->serial_out = dwapb32_serial_out; | ||
544 | break; | ||
545 | |||
523 | default: | 546 | default: |
524 | p->serial_in = io_serial_in; | 547 | p->serial_in = io_serial_in; |
525 | p->serial_out = io_serial_out; | 548 | p->serial_out = io_serial_out; |
@@ -538,6 +561,7 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value) | |||
538 | case UPIO_MEM32: | 561 | case UPIO_MEM32: |
539 | case UPIO_AU: | 562 | case UPIO_AU: |
540 | case UPIO_DWAPB: | 563 | case UPIO_DWAPB: |
564 | case UPIO_DWAPB32: | ||
541 | p->serial_out(p, offset, value); | 565 | p->serial_out(p, offset, value); |
542 | p->serial_in(p, UART_LCR); /* safe, no side-effects */ | 566 | p->serial_in(p, UART_LCR); /* safe, no side-effects */ |
543 | break; | 567 | break; |
@@ -1587,7 +1611,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) | |||
1587 | handled = 1; | 1611 | handled = 1; |
1588 | 1612 | ||
1589 | end = NULL; | 1613 | end = NULL; |
1590 | } else if (up->port.iotype == UPIO_DWAPB && | 1614 | } else if ((up->port.iotype == UPIO_DWAPB || |
1615 | up->port.iotype == UPIO_DWAPB32) && | ||
1591 | (iir & UART_IIR_BUSY) == UART_IIR_BUSY) { | 1616 | (iir & UART_IIR_BUSY) == UART_IIR_BUSY) { |
1592 | /* The DesignWare APB UART has an Busy Detect (0x07) | 1617 | /* The DesignWare APB UART has an Busy Detect (0x07) |
1593 | * interrupt meaning an LCR write attempt occured while the | 1618 | * 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 | case UPIO_MEM32: | 2517 | case UPIO_MEM32: |
2493 | case UPIO_MEM: | 2518 | case UPIO_MEM: |
2494 | case UPIO_DWAPB: | 2519 | case UPIO_DWAPB: |
2520 | case UPIO_DWAPB32: | ||
2495 | if (!up->port.mapbase) | 2521 | if (!up->port.mapbase) |
2496 | break; | 2522 | break; |
2497 | 2523 | ||
@@ -2529,6 +2555,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up) | |||
2529 | case UPIO_MEM32: | 2555 | case UPIO_MEM32: |
2530 | case UPIO_MEM: | 2556 | case UPIO_MEM: |
2531 | case UPIO_DWAPB: | 2557 | case UPIO_DWAPB: |
2558 | case UPIO_DWAPB32: | ||
2532 | if (!up->port.mapbase) | 2559 | if (!up->port.mapbase) |
2533 | break; | 2560 | break; |
2534 | 2561 | ||
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index c4ea14670d44..2835e29298ed 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c | |||
@@ -2135,6 +2135,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) | |||
2135 | case UPIO_AU: | 2135 | case UPIO_AU: |
2136 | case UPIO_TSI: | 2136 | case UPIO_TSI: |
2137 | case UPIO_DWAPB: | 2137 | case UPIO_DWAPB: |
2138 | case UPIO_DWAPB32: | ||
2138 | snprintf(address, sizeof(address), | 2139 | snprintf(address, sizeof(address), |
2139 | "MMIO 0x%llx", (unsigned long long)port->mapbase); | 2140 | "MMIO 0x%llx", (unsigned long long)port->mapbase); |
2140 | break; | 2141 | break; |
@@ -2555,6 +2556,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2) | |||
2555 | case UPIO_AU: | 2556 | case UPIO_AU: |
2556 | case UPIO_TSI: | 2557 | case UPIO_TSI: |
2557 | case UPIO_DWAPB: | 2558 | case UPIO_DWAPB: |
2559 | case UPIO_DWAPB32: | ||
2558 | return (port1->mapbase == port2->mapbase); | 2560 | return (port1->mapbase == port2->mapbase); |
2559 | } | 2561 | } |
2560 | return 0; | 2562 | return 0; |