aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/serial/amba-pl011.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-05-22 19:12:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-05-22 19:12:24 -0400
commit94b5aff4c6f72fee6b0f49d49e4fa8b204e8ded9 (patch)
tree39197121b6ef8cddaa0f4057fe24b4ced58e8982 /drivers/tty/serial/amba-pl011.c
parent5d4e2d08e7fdf7339f84a1c670d296a77e02f881 (diff)
parent59bd234b72fc29887839d792b7d6c7e8d2a577a6 (diff)
Merge tag 'tty-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull TTY updates from Greg Kroah-Hartman: "Here's the big TTY/serial driver pull request for the 3.5-rc1 merge window. Nothing major in here, just lots of incremental changes from Alan and Jiri reworking some tty core things to behave better and to get a more solid grasp on some of the nasty tty locking issues. There are a few tty and serial driver updates in here as well. All of this has been in the linux-next releases for a while with no problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>" * tag 'tty-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (115 commits) serial: bfin_uart: Make MMR access compatible with 32 bits bf609 style controller. serial: bfin_uart: RTS and CTS MMRs can be either 16-bit width or 32-bit width. serial: bfin_uart: narrow the reboot condition in DMA tx interrupt serial: bfin_uart: Adapt bf5xx serial driver to bf60x serial4 controller. Revert "serial_core: Update buffer overrun statistics." tty: hvc_xen: NULL dereference on allocation failure tty: Fix LED error return tty: Allow uart_register/unregister/register tty: move global ldisc idle waitqueue to the individual ldisc serial8250-em: Add DT support serial8250-em: clk_get() IS_ERR() error handling fix serial_core: Update buffer overrun statistics. tty: drop the pty lock during hangup cris: fix missing tty arg in wait_event_interruptible_tty call tty/amiserial: Add missing argument for tty_unlock() tty_lock: Localise the lock pty: Lock the devpts bits privately tty_lock: undo the old tty_lock use on the ctty serial8250-em: Emma Mobile UART driver V2 Add missing call to uart_update_timeout() ...
Diffstat (limited to 'drivers/tty/serial/amba-pl011.c')
-rw-r--r--drivers/tty/serial/amba-pl011.c109
1 files changed, 18 insertions, 91 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 062ef8c2b3cb..4ad721fb8405 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -68,30 +68,6 @@
68#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) 68#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
69#define UART_DUMMY_DR_RX (1 << 16) 69#define UART_DUMMY_DR_RX (1 << 16)
70 70
71
72#define UART_WA_SAVE_NR 14
73
74static void pl011_lockup_wa(unsigned long data);
75static const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
76 ST_UART011_DMAWM,
77 ST_UART011_TIMEOUT,
78 ST_UART011_LCRH_RX,
79 UART011_IBRD,
80 UART011_FBRD,
81 ST_UART011_LCRH_TX,
82 UART011_IFLS,
83 ST_UART011_XFCR,
84 ST_UART011_XON1,
85 ST_UART011_XON2,
86 ST_UART011_XOFF1,
87 ST_UART011_XOFF2,
88 UART011_CR,
89 UART011_IMSC
90};
91
92static u32 uart_wa_regdata[UART_WA_SAVE_NR];
93static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
94
95/* There is by now at least one vendor with differing details, so handle it */ 71/* There is by now at least one vendor with differing details, so handle it */
96struct vendor_data { 72struct vendor_data {
97 unsigned int ifls; 73 unsigned int ifls;
@@ -101,6 +77,7 @@ struct vendor_data {
101 bool oversampling; 77 bool oversampling;
102 bool interrupt_may_hang; /* vendor-specific */ 78 bool interrupt_may_hang; /* vendor-specific */
103 bool dma_threshold; 79 bool dma_threshold;
80 bool cts_event_workaround;
104}; 81};
105 82
106static struct vendor_data vendor_arm = { 83static struct vendor_data vendor_arm = {
@@ -110,6 +87,7 @@ static struct vendor_data vendor_arm = {
110 .lcrh_rx = UART011_LCRH, 87 .lcrh_rx = UART011_LCRH,
111 .oversampling = false, 88 .oversampling = false,
112 .dma_threshold = false, 89 .dma_threshold = false,
90 .cts_event_workaround = false,
113}; 91};
114 92
115static struct vendor_data vendor_st = { 93static struct vendor_data vendor_st = {
@@ -120,6 +98,7 @@ static struct vendor_data vendor_st = {
120 .oversampling = true, 98 .oversampling = true,
121 .interrupt_may_hang = true, 99 .interrupt_may_hang = true,
122 .dma_threshold = true, 100 .dma_threshold = true,
101 .cts_event_workaround = true,
123}; 102};
124 103
125static struct uart_amba_port *amba_ports[UART_NR]; 104static struct uart_amba_port *amba_ports[UART_NR];
@@ -1055,69 +1034,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
1055#define pl011_dma_flush_buffer NULL 1034#define pl011_dma_flush_buffer NULL
1056#endif 1035#endif
1057 1036
1058
1059/*
1060 * pl011_lockup_wa
1061 * This workaround aims to break the deadlock situation
1062 * when after long transfer over uart in hardware flow
1063 * control, uart interrupt registers cannot be cleared.
1064 * Hence uart transfer gets blocked.
1065 *
1066 * It is seen that during such deadlock condition ICR
1067 * don't get cleared even on multiple write. This leads
1068 * pass_counter to decrease and finally reach zero. This
1069 * can be taken as trigger point to run this UART_BT_WA.
1070 *
1071 */
1072static void pl011_lockup_wa(unsigned long data)
1073{
1074 struct uart_amba_port *uap = amba_ports[0];
1075 void __iomem *base = uap->port.membase;
1076 struct circ_buf *xmit = &uap->port.state->xmit;
1077 struct tty_struct *tty = uap->port.state->port.tty;
1078 int buf_empty_retries = 200;
1079 int loop;
1080
1081 /* Stop HCI layer from submitting data for tx */
1082 tty->hw_stopped = 1;
1083 while (!uart_circ_empty(xmit)) {
1084 if (buf_empty_retries-- == 0)
1085 break;
1086 udelay(100);
1087 }
1088
1089 /* Backup registers */
1090 for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
1091 uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
1092
1093 /* Disable UART so that FIFO data is flushed out */
1094 writew(0x00, uap->port.membase + UART011_CR);
1095
1096 /* Soft reset UART module */
1097 if (uap->port.dev->platform_data) {
1098 struct amba_pl011_data *plat;
1099
1100 plat = uap->port.dev->platform_data;
1101 if (plat->reset)
1102 plat->reset();
1103 }
1104
1105 /* Restore registers */
1106 for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
1107 writew(uart_wa_regdata[loop] ,
1108 uap->port.membase + uart_wa_reg[loop]);
1109
1110 /* Initialise the old status of the modem signals */
1111 uap->old_status = readw(uap->port.membase + UART01x_FR) &
1112 UART01x_FR_MODEM_ANY;
1113
1114 if (readl(base + UART011_MIS) & 0x2)
1115 printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
1116
1117 /* Start Tx/Rx */
1118 tty->hw_stopped = 0;
1119}
1120
1121static void pl011_stop_tx(struct uart_port *port) 1037static void pl011_stop_tx(struct uart_port *port)
1122{ 1038{
1123 struct uart_amba_port *uap = (struct uart_amba_port *)port; 1039 struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1246,12 +1162,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
1246 unsigned long flags; 1162 unsigned long flags;
1247 unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; 1163 unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
1248 int handled = 0; 1164 int handled = 0;
1165 unsigned int dummy_read;
1249 1166
1250 spin_lock_irqsave(&uap->port.lock, flags); 1167 spin_lock_irqsave(&uap->port.lock, flags);
1251 1168
1252 status = readw(uap->port.membase + UART011_MIS); 1169 status = readw(uap->port.membase + UART011_MIS);
1253 if (status) { 1170 if (status) {
1254 do { 1171 do {
1172 if (uap->vendor->cts_event_workaround) {
1173 /* workaround to make sure that all bits are unlocked.. */
1174 writew(0x00, uap->port.membase + UART011_ICR);
1175
1176 /*
1177 * WA: introduce 26ns(1 uart clk) delay before W1C;
1178 * single apb access will incur 2 pclk(133.12Mhz) delay,
1179 * so add 2 dummy reads
1180 */
1181 dummy_read = readw(uap->port.membase + UART011_ICR);
1182 dummy_read = readw(uap->port.membase + UART011_ICR);
1183 }
1184
1255 writew(status & ~(UART011_TXIS|UART011_RTIS| 1185 writew(status & ~(UART011_TXIS|UART011_RTIS|
1256 UART011_RXIS), 1186 UART011_RXIS),
1257 uap->port.membase + UART011_ICR); 1187 uap->port.membase + UART011_ICR);
@@ -1268,11 +1198,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
1268 if (status & UART011_TXIS) 1198 if (status & UART011_TXIS)
1269 pl011_tx_chars(uap); 1199 pl011_tx_chars(uap);
1270 1200
1271 if (pass_counter-- == 0) { 1201 if (pass_counter-- == 0)
1272 if (uap->interrupt_may_hang)
1273 tasklet_schedule(&pl011_lockup_tlet);
1274 break; 1202 break;
1275 }
1276 1203
1277 status = readw(uap->port.membase + UART011_MIS); 1204 status = readw(uap->port.membase + UART011_MIS);
1278 } while (status != 0); 1205 } while (status != 0);