diff options
-rw-r--r-- | arch/arm/mach-exynos4/init.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-mop500-pins.c | 16 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-mop500.c | 54 | ||||
-rw-r--r-- | arch/arm/plat-samsung/include/plat/regs-serial.h | 2 | ||||
-rw-r--r-- | drivers/tty/n_gsm.c | 26 | ||||
-rw-r--r-- | drivers/tty/n_tty.c | 1 | ||||
-rw-r--r-- | drivers/tty/serial/8250.c | 1 | ||||
-rw-r--r-- | drivers/tty/serial/8250_pci.c | 59 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 123 | ||||
-rw-r--r-- | drivers/tty/serial/bcm63xx_uart.c | 18 | ||||
-rw-r--r-- | drivers/tty/serial/jsm/jsm_driver.c | 2 | ||||
-rw-r--r-- | drivers/tty/serial/s5pv210.c | 4 | ||||
-rw-r--r-- | drivers/tty/tty_ldisc.c | 4 | ||||
-rw-r--r-- | include/linux/amba/serial.h | 3 |
14 files changed, 295 insertions, 19 deletions
diff --git a/arch/arm/mach-exynos4/init.c b/arch/arm/mach-exynos4/init.c index cf91f50e43ab..a8a83e3881a4 100644 --- a/arch/arm/mach-exynos4/init.c +++ b/arch/arm/mach-exynos4/init.c | |||
@@ -35,6 +35,7 @@ void __init exynos4_common_init_uarts(struct s3c2410_uartcfg *cfg, int no) | |||
35 | tcfg->clocks = exynos4_serial_clocks; | 35 | tcfg->clocks = exynos4_serial_clocks; |
36 | tcfg->clocks_size = ARRAY_SIZE(exynos4_serial_clocks); | 36 | tcfg->clocks_size = ARRAY_SIZE(exynos4_serial_clocks); |
37 | } | 37 | } |
38 | tcfg->flags |= NO_NEED_CHECK_CLKSRC; | ||
38 | } | 39 | } |
39 | 40 | ||
40 | s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no); | 41 | s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no); |
diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index fd4cf1ca5efd..70cdbd60596a 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c | |||
@@ -110,10 +110,18 @@ static pin_cfg_t mop500_pins_common[] = { | |||
110 | GPIO168_KP_O0, | 110 | GPIO168_KP_O0, |
111 | 111 | ||
112 | /* UART */ | 112 | /* UART */ |
113 | GPIO0_U0_CTSn | PIN_INPUT_PULLUP, | 113 | /* uart-0 pins gpio configuration should be |
114 | GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, | 114 | * kept intact to prevent glitch in tx line |
115 | GPIO2_U0_RXD | PIN_INPUT_PULLUP, | 115 | * when tty dev is opened. Later these pins |
116 | GPIO3_U0_TXD | PIN_OUTPUT_HIGH, | 116 | * are configured to uart mop500_pins_uart0 |
117 | * | ||
118 | * It will be replaced with uart configuration | ||
119 | * once the issue is solved. | ||
120 | */ | ||
121 | GPIO0_GPIO | PIN_INPUT_PULLUP, | ||
122 | GPIO1_GPIO | PIN_OUTPUT_HIGH, | ||
123 | GPIO2_GPIO | PIN_INPUT_PULLUP, | ||
124 | GPIO3_GPIO | PIN_OUTPUT_HIGH, | ||
117 | 125 | ||
118 | GPIO29_U2_RXD | PIN_INPUT_PULLUP, | 126 | GPIO29_U2_RXD | PIN_INPUT_PULLUP, |
119 | GPIO30_U2_TXD | PIN_OUTPUT_HIGH, | 127 | GPIO30_U2_TXD | PIN_OUTPUT_HIGH, |
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index bb26f40493e6..2a08c07dec6d 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c | |||
@@ -27,18 +27,21 @@ | |||
27 | #include <linux/leds-lp5521.h> | 27 | #include <linux/leds-lp5521.h> |
28 | #include <linux/input.h> | 28 | #include <linux/input.h> |
29 | #include <linux/gpio_keys.h> | 29 | #include <linux/gpio_keys.h> |
30 | #include <linux/delay.h> | ||
30 | 31 | ||
31 | #include <asm/mach-types.h> | 32 | #include <asm/mach-types.h> |
32 | #include <asm/mach/arch.h> | 33 | #include <asm/mach/arch.h> |
33 | 34 | ||
34 | #include <plat/i2c.h> | 35 | #include <plat/i2c.h> |
35 | #include <plat/ste_dma40.h> | 36 | #include <plat/ste_dma40.h> |
37 | #include <plat/pincfg.h> | ||
36 | 38 | ||
37 | #include <mach/hardware.h> | 39 | #include <mach/hardware.h> |
38 | #include <mach/setup.h> | 40 | #include <mach/setup.h> |
39 | #include <mach/devices.h> | 41 | #include <mach/devices.h> |
40 | #include <mach/irqs.h> | 42 | #include <mach/irqs.h> |
41 | 43 | ||
44 | #include "pins-db8500.h" | ||
42 | #include "ste-dma40-db8500.h" | 45 | #include "ste-dma40-db8500.h" |
43 | #include "devices-db8500.h" | 46 | #include "devices-db8500.h" |
44 | #include "board-mop500.h" | 47 | #include "board-mop500.h" |
@@ -393,12 +396,63 @@ static struct stedma40_chan_cfg uart2_dma_cfg_tx = { | |||
393 | }; | 396 | }; |
394 | #endif | 397 | #endif |
395 | 398 | ||
399 | |||
400 | static pin_cfg_t mop500_pins_uart0[] = { | ||
401 | GPIO0_U0_CTSn | PIN_INPUT_PULLUP, | ||
402 | GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, | ||
403 | GPIO2_U0_RXD | PIN_INPUT_PULLUP, | ||
404 | GPIO3_U0_TXD | PIN_OUTPUT_HIGH, | ||
405 | }; | ||
406 | |||
407 | #define PRCC_K_SOFTRST_SET 0x18 | ||
408 | #define PRCC_K_SOFTRST_CLEAR 0x1C | ||
409 | static void ux500_uart0_reset(void) | ||
410 | { | ||
411 | void __iomem *prcc_rst_set, *prcc_rst_clr; | ||
412 | |||
413 | prcc_rst_set = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE + | ||
414 | PRCC_K_SOFTRST_SET); | ||
415 | prcc_rst_clr = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE + | ||
416 | PRCC_K_SOFTRST_CLEAR); | ||
417 | |||
418 | /* Activate soft reset PRCC_K_SOFTRST_CLEAR */ | ||
419 | writel((readl(prcc_rst_clr) | 0x1), prcc_rst_clr); | ||
420 | udelay(1); | ||
421 | |||
422 | /* Release soft reset PRCC_K_SOFTRST_SET */ | ||
423 | writel((readl(prcc_rst_set) | 0x1), prcc_rst_set); | ||
424 | udelay(1); | ||
425 | } | ||
426 | |||
427 | static void ux500_uart0_init(void) | ||
428 | { | ||
429 | int ret; | ||
430 | |||
431 | ret = nmk_config_pins(mop500_pins_uart0, | ||
432 | ARRAY_SIZE(mop500_pins_uart0)); | ||
433 | if (ret < 0) | ||
434 | pr_err("pl011: uart pins_enable failed\n"); | ||
435 | } | ||
436 | |||
437 | static void ux500_uart0_exit(void) | ||
438 | { | ||
439 | int ret; | ||
440 | |||
441 | ret = nmk_config_pins_sleep(mop500_pins_uart0, | ||
442 | ARRAY_SIZE(mop500_pins_uart0)); | ||
443 | if (ret < 0) | ||
444 | pr_err("pl011: uart pins_disable failed\n"); | ||
445 | } | ||
446 | |||
396 | static struct amba_pl011_data uart0_plat = { | 447 | static struct amba_pl011_data uart0_plat = { |
397 | #ifdef CONFIG_STE_DMA40 | 448 | #ifdef CONFIG_STE_DMA40 |
398 | .dma_filter = stedma40_filter, | 449 | .dma_filter = stedma40_filter, |
399 | .dma_rx_param = &uart0_dma_cfg_rx, | 450 | .dma_rx_param = &uart0_dma_cfg_rx, |
400 | .dma_tx_param = &uart0_dma_cfg_tx, | 451 | .dma_tx_param = &uart0_dma_cfg_tx, |
401 | #endif | 452 | #endif |
453 | .init = ux500_uart0_init, | ||
454 | .exit = ux500_uart0_exit, | ||
455 | .reset = ux500_uart0_reset, | ||
402 | }; | 456 | }; |
403 | 457 | ||
404 | static struct amba_pl011_data uart1_plat = { | 458 | static struct amba_pl011_data uart1_plat = { |
diff --git a/arch/arm/plat-samsung/include/plat/regs-serial.h b/arch/arm/plat-samsung/include/plat/regs-serial.h index c151c5f94a87..116edfe120b9 100644 --- a/arch/arm/plat-samsung/include/plat/regs-serial.h +++ b/arch/arm/plat-samsung/include/plat/regs-serial.h | |||
@@ -224,6 +224,8 @@ | |||
224 | #define S5PV210_UFSTAT_RXMASK (255<<0) | 224 | #define S5PV210_UFSTAT_RXMASK (255<<0) |
225 | #define S5PV210_UFSTAT_RXSHIFT (0) | 225 | #define S5PV210_UFSTAT_RXSHIFT (0) |
226 | 226 | ||
227 | #define NO_NEED_CHECK_CLKSRC 1 | ||
228 | |||
227 | #ifndef __ASSEMBLY__ | 229 | #ifndef __ASSEMBLY__ |
228 | 230 | ||
229 | /* struct s3c24xx_uart_clksrc | 231 | /* struct s3c24xx_uart_clksrc |
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 09e8c7d53af3..19b4ae052af8 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c | |||
@@ -875,7 +875,8 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, | |||
875 | *dp++ = last << 7 | first << 6 | 1; /* EA */ | 875 | *dp++ = last << 7 | first << 6 | 1; /* EA */ |
876 | len--; | 876 | len--; |
877 | } | 877 | } |
878 | memcpy(dp, skb_pull(dlci->skb, len), len); | 878 | memcpy(dp, dlci->skb->data, len); |
879 | skb_pull(dlci->skb, len); | ||
879 | __gsm_data_queue(dlci, msg); | 880 | __gsm_data_queue(dlci, msg); |
880 | if (last) | 881 | if (last) |
881 | dlci->skb = NULL; | 882 | dlci->skb = NULL; |
@@ -984,10 +985,22 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data, | |||
984 | */ | 985 | */ |
985 | 986 | ||
986 | static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, | 987 | static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci, |
987 | u32 modem) | 988 | u32 modem, int clen) |
988 | { | 989 | { |
989 | int mlines = 0; | 990 | int mlines = 0; |
990 | u8 brk = modem >> 6; | 991 | u8 brk = 0; |
992 | |||
993 | /* The modem status command can either contain one octet (v.24 signals) | ||
994 | or two octets (v.24 signals + break signals). The length field will | ||
995 | either be 2 or 3 respectively. This is specified in section | ||
996 | 5.4.6.3.7 of the 27.010 mux spec. */ | ||
997 | |||
998 | if (clen == 2) | ||
999 | modem = modem & 0x7f; | ||
1000 | else { | ||
1001 | brk = modem & 0x7f; | ||
1002 | modem = (modem >> 7) & 0x7f; | ||
1003 | }; | ||
991 | 1004 | ||
992 | /* Flow control/ready to communicate */ | 1005 | /* Flow control/ready to communicate */ |
993 | if (modem & MDM_FC) { | 1006 | if (modem & MDM_FC) { |
@@ -1061,7 +1074,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen) | |||
1061 | return; | 1074 | return; |
1062 | } | 1075 | } |
1063 | tty = tty_port_tty_get(&dlci->port); | 1076 | tty = tty_port_tty_get(&dlci->port); |
1064 | gsm_process_modem(tty, dlci, modem); | 1077 | gsm_process_modem(tty, dlci, modem, clen); |
1065 | if (tty) { | 1078 | if (tty) { |
1066 | tty_wakeup(tty); | 1079 | tty_wakeup(tty); |
1067 | tty_kref_put(tty); | 1080 | tty_kref_put(tty); |
@@ -1482,12 +1495,13 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci) | |||
1482 | * open we shovel the bits down it, if not we drop them. | 1495 | * open we shovel the bits down it, if not we drop them. |
1483 | */ | 1496 | */ |
1484 | 1497 | ||
1485 | static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len) | 1498 | static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen) |
1486 | { | 1499 | { |
1487 | /* krefs .. */ | 1500 | /* krefs .. */ |
1488 | struct tty_port *port = &dlci->port; | 1501 | struct tty_port *port = &dlci->port; |
1489 | struct tty_struct *tty = tty_port_tty_get(port); | 1502 | struct tty_struct *tty = tty_port_tty_get(port); |
1490 | unsigned int modem = 0; | 1503 | unsigned int modem = 0; |
1504 | int len = clen; | ||
1491 | 1505 | ||
1492 | if (debug & 16) | 1506 | if (debug & 16) |
1493 | pr_debug("%d bytes for tty %p\n", len, tty); | 1507 | pr_debug("%d bytes for tty %p\n", len, tty); |
@@ -1507,7 +1521,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len) | |||
1507 | if (len == 0) | 1521 | if (len == 0) |
1508 | return; | 1522 | return; |
1509 | } | 1523 | } |
1510 | gsm_process_modem(tty, dlci, modem); | 1524 | gsm_process_modem(tty, dlci, modem, clen); |
1511 | /* Line state will go via DLCI 0 controls only */ | 1525 | /* Line state will go via DLCI 0 controls only */ |
1512 | case 1: | 1526 | case 1: |
1513 | default: | 1527 | default: |
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 0ad32888091c..c3954fbf6ac4 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c | |||
@@ -1815,6 +1815,7 @@ do_it_again: | |||
1815 | /* FIXME: does n_tty_set_room need locking ? */ | 1815 | /* FIXME: does n_tty_set_room need locking ? */ |
1816 | n_tty_set_room(tty); | 1816 | n_tty_set_room(tty); |
1817 | timeout = schedule_timeout(timeout); | 1817 | timeout = schedule_timeout(timeout); |
1818 | BUG_ON(!tty->read_buf); | ||
1818 | continue; | 1819 | continue; |
1819 | } | 1820 | } |
1820 | __set_current_state(TASK_RUNNING); | 1821 | __set_current_state(TASK_RUNNING); |
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c index b40f7b90c81d..b4129f53fb1b 100644 --- a/drivers/tty/serial/8250.c +++ b/drivers/tty/serial/8250.c | |||
@@ -3318,6 +3318,7 @@ void serial8250_unregister_port(int line) | |||
3318 | uart->port.flags &= ~UPF_BOOT_AUTOCONF; | 3318 | uart->port.flags &= ~UPF_BOOT_AUTOCONF; |
3319 | uart->port.type = PORT_UNKNOWN; | 3319 | uart->port.type = PORT_UNKNOWN; |
3320 | uart->port.dev = &serial8250_isa_devs->dev; | 3320 | uart->port.dev = &serial8250_isa_devs->dev; |
3321 | uart->capabilities = uart_config[uart->port.type].flags; | ||
3321 | uart_add_one_port(&serial8250_reg, &uart->port); | 3322 | uart_add_one_port(&serial8250_reg, &uart->port); |
3322 | } else { | 3323 | } else { |
3323 | uart->port.dev = NULL; | 3324 | uart->port.dev = NULL; |
diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c index 78e98a5cef96..f41b4259ecdd 100644 --- a/drivers/tty/serial/8250_pci.c +++ b/drivers/tty/serial/8250_pci.c | |||
@@ -994,6 +994,15 @@ static int skip_tx_en_setup(struct serial_private *priv, | |||
994 | return pci_default_setup(priv, board, port, idx); | 994 | return pci_default_setup(priv, board, port, idx); |
995 | } | 995 | } |
996 | 996 | ||
997 | static int pci_eg20t_init(struct pci_dev *dev) | ||
998 | { | ||
999 | #if defined(CONFIG_SERIAL_PCH_UART) || defined(CONFIG_SERIAL_PCH_UART_MODULE) | ||
1000 | return -ENODEV; | ||
1001 | #else | ||
1002 | return 0; | ||
1003 | #endif | ||
1004 | } | ||
1005 | |||
997 | /* This should be in linux/pci_ids.h */ | 1006 | /* This should be in linux/pci_ids.h */ |
998 | #define PCI_VENDOR_ID_SBSMODULARIO 0x124B | 1007 | #define PCI_VENDOR_ID_SBSMODULARIO 0x124B |
999 | #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B | 1008 | #define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B |
@@ -1446,6 +1455,56 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { | |||
1446 | .init = pci_oxsemi_tornado_init, | 1455 | .init = pci_oxsemi_tornado_init, |
1447 | .setup = pci_default_setup, | 1456 | .setup = pci_default_setup, |
1448 | }, | 1457 | }, |
1458 | { | ||
1459 | .vendor = PCI_VENDOR_ID_INTEL, | ||
1460 | .device = 0x8811, | ||
1461 | .init = pci_eg20t_init, | ||
1462 | }, | ||
1463 | { | ||
1464 | .vendor = PCI_VENDOR_ID_INTEL, | ||
1465 | .device = 0x8812, | ||
1466 | .init = pci_eg20t_init, | ||
1467 | }, | ||
1468 | { | ||
1469 | .vendor = PCI_VENDOR_ID_INTEL, | ||
1470 | .device = 0x8813, | ||
1471 | .init = pci_eg20t_init, | ||
1472 | }, | ||
1473 | { | ||
1474 | .vendor = PCI_VENDOR_ID_INTEL, | ||
1475 | .device = 0x8814, | ||
1476 | .init = pci_eg20t_init, | ||
1477 | }, | ||
1478 | { | ||
1479 | .vendor = 0x10DB, | ||
1480 | .device = 0x8027, | ||
1481 | .init = pci_eg20t_init, | ||
1482 | }, | ||
1483 | { | ||
1484 | .vendor = 0x10DB, | ||
1485 | .device = 0x8028, | ||
1486 | .init = pci_eg20t_init, | ||
1487 | }, | ||
1488 | { | ||
1489 | .vendor = 0x10DB, | ||
1490 | .device = 0x8029, | ||
1491 | .init = pci_eg20t_init, | ||
1492 | }, | ||
1493 | { | ||
1494 | .vendor = 0x10DB, | ||
1495 | .device = 0x800C, | ||
1496 | .init = pci_eg20t_init, | ||
1497 | }, | ||
1498 | { | ||
1499 | .vendor = 0x10DB, | ||
1500 | .device = 0x800D, | ||
1501 | .init = pci_eg20t_init, | ||
1502 | }, | ||
1503 | { | ||
1504 | .vendor = 0x10DB, | ||
1505 | .device = 0x800D, | ||
1506 | .init = pci_eg20t_init, | ||
1507 | }, | ||
1449 | /* | 1508 | /* |
1450 | * Cronyx Omega PCI (PLX-chip based) | 1509 | * Cronyx Omega PCI (PLX-chip based) |
1451 | */ | 1510 | */ |
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 8dc0541feecc..f5f6831b0a64 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <linux/dmaengine.h> | 50 | #include <linux/dmaengine.h> |
51 | #include <linux/dma-mapping.h> | 51 | #include <linux/dma-mapping.h> |
52 | #include <linux/scatterlist.h> | 52 | #include <linux/scatterlist.h> |
53 | #include <linux/delay.h> | ||
53 | 54 | ||
54 | #include <asm/io.h> | 55 | #include <asm/io.h> |
55 | #include <asm/sizes.h> | 56 | #include <asm/sizes.h> |
@@ -65,6 +66,30 @@ | |||
65 | #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) | 66 | #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) |
66 | #define UART_DUMMY_DR_RX (1 << 16) | 67 | #define UART_DUMMY_DR_RX (1 << 16) |
67 | 68 | ||
69 | |||
70 | #define UART_WA_SAVE_NR 14 | ||
71 | |||
72 | static void pl011_lockup_wa(unsigned long data); | ||
73 | static const u32 uart_wa_reg[UART_WA_SAVE_NR] = { | ||
74 | ST_UART011_DMAWM, | ||
75 | ST_UART011_TIMEOUT, | ||
76 | ST_UART011_LCRH_RX, | ||
77 | UART011_IBRD, | ||
78 | UART011_FBRD, | ||
79 | ST_UART011_LCRH_TX, | ||
80 | UART011_IFLS, | ||
81 | ST_UART011_XFCR, | ||
82 | ST_UART011_XON1, | ||
83 | ST_UART011_XON2, | ||
84 | ST_UART011_XOFF1, | ||
85 | ST_UART011_XOFF2, | ||
86 | UART011_CR, | ||
87 | UART011_IMSC | ||
88 | }; | ||
89 | |||
90 | static u32 uart_wa_regdata[UART_WA_SAVE_NR]; | ||
91 | static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0); | ||
92 | |||
68 | /* There is by now at least one vendor with differing details, so handle it */ | 93 | /* There is by now at least one vendor with differing details, so handle it */ |
69 | struct vendor_data { | 94 | struct vendor_data { |
70 | unsigned int ifls; | 95 | unsigned int ifls; |
@@ -72,6 +97,7 @@ struct vendor_data { | |||
72 | unsigned int lcrh_tx; | 97 | unsigned int lcrh_tx; |
73 | unsigned int lcrh_rx; | 98 | unsigned int lcrh_rx; |
74 | bool oversampling; | 99 | bool oversampling; |
100 | bool interrupt_may_hang; /* vendor-specific */ | ||
75 | bool dma_threshold; | 101 | bool dma_threshold; |
76 | }; | 102 | }; |
77 | 103 | ||
@@ -90,9 +116,12 @@ static struct vendor_data vendor_st = { | |||
90 | .lcrh_tx = ST_UART011_LCRH_TX, | 116 | .lcrh_tx = ST_UART011_LCRH_TX, |
91 | .lcrh_rx = ST_UART011_LCRH_RX, | 117 | .lcrh_rx = ST_UART011_LCRH_RX, |
92 | .oversampling = true, | 118 | .oversampling = true, |
119 | .interrupt_may_hang = true, | ||
93 | .dma_threshold = true, | 120 | .dma_threshold = true, |
94 | }; | 121 | }; |
95 | 122 | ||
123 | static struct uart_amba_port *amba_ports[UART_NR]; | ||
124 | |||
96 | /* Deals with DMA transactions */ | 125 | /* Deals with DMA transactions */ |
97 | 126 | ||
98 | struct pl011_sgbuf { | 127 | struct pl011_sgbuf { |
@@ -132,6 +161,7 @@ struct uart_amba_port { | |||
132 | unsigned int lcrh_rx; /* vendor-specific */ | 161 | unsigned int lcrh_rx; /* vendor-specific */ |
133 | bool autorts; | 162 | bool autorts; |
134 | char type[12]; | 163 | char type[12]; |
164 | bool interrupt_may_hang; /* vendor-specific */ | ||
135 | #ifdef CONFIG_DMA_ENGINE | 165 | #ifdef CONFIG_DMA_ENGINE |
136 | /* DMA stuff */ | 166 | /* DMA stuff */ |
137 | bool using_tx_dma; | 167 | bool using_tx_dma; |
@@ -1008,6 +1038,68 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) | |||
1008 | #endif | 1038 | #endif |
1009 | 1039 | ||
1010 | 1040 | ||
1041 | /* | ||
1042 | * pl011_lockup_wa | ||
1043 | * This workaround aims to break the deadlock situation | ||
1044 | * when after long transfer over uart in hardware flow | ||
1045 | * control, uart interrupt registers cannot be cleared. | ||
1046 | * Hence uart transfer gets blocked. | ||
1047 | * | ||
1048 | * It is seen that during such deadlock condition ICR | ||
1049 | * don't get cleared even on multiple write. This leads | ||
1050 | * pass_counter to decrease and finally reach zero. This | ||
1051 | * can be taken as trigger point to run this UART_BT_WA. | ||
1052 | * | ||
1053 | */ | ||
1054 | static void pl011_lockup_wa(unsigned long data) | ||
1055 | { | ||
1056 | struct uart_amba_port *uap = amba_ports[0]; | ||
1057 | void __iomem *base = uap->port.membase; | ||
1058 | struct circ_buf *xmit = &uap->port.state->xmit; | ||
1059 | struct tty_struct *tty = uap->port.state->port.tty; | ||
1060 | int buf_empty_retries = 200; | ||
1061 | int loop; | ||
1062 | |||
1063 | /* Stop HCI layer from submitting data for tx */ | ||
1064 | tty->hw_stopped = 1; | ||
1065 | while (!uart_circ_empty(xmit)) { | ||
1066 | if (buf_empty_retries-- == 0) | ||
1067 | break; | ||
1068 | udelay(100); | ||
1069 | } | ||
1070 | |||
1071 | /* Backup registers */ | ||
1072 | for (loop = 0; loop < UART_WA_SAVE_NR; loop++) | ||
1073 | uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]); | ||
1074 | |||
1075 | /* Disable UART so that FIFO data is flushed out */ | ||
1076 | writew(0x00, uap->port.membase + UART011_CR); | ||
1077 | |||
1078 | /* Soft reset UART module */ | ||
1079 | if (uap->port.dev->platform_data) { | ||
1080 | struct amba_pl011_data *plat; | ||
1081 | |||
1082 | plat = uap->port.dev->platform_data; | ||
1083 | if (plat->reset) | ||
1084 | plat->reset(); | ||
1085 | } | ||
1086 | |||
1087 | /* Restore registers */ | ||
1088 | for (loop = 0; loop < UART_WA_SAVE_NR; loop++) | ||
1089 | writew(uart_wa_regdata[loop] , | ||
1090 | uap->port.membase + uart_wa_reg[loop]); | ||
1091 | |||
1092 | /* Initialise the old status of the modem signals */ | ||
1093 | uap->old_status = readw(uap->port.membase + UART01x_FR) & | ||
1094 | UART01x_FR_MODEM_ANY; | ||
1095 | |||
1096 | if (readl(base + UART011_MIS) & 0x2) | ||
1097 | printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n"); | ||
1098 | |||
1099 | /* Start Tx/Rx */ | ||
1100 | tty->hw_stopped = 0; | ||
1101 | } | ||
1102 | |||
1011 | static void pl011_stop_tx(struct uart_port *port) | 1103 | static void pl011_stop_tx(struct uart_port *port) |
1012 | { | 1104 | { |
1013 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | 1105 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
@@ -1158,8 +1250,11 @@ static irqreturn_t pl011_int(int irq, void *dev_id) | |||
1158 | if (status & UART011_TXIS) | 1250 | if (status & UART011_TXIS) |
1159 | pl011_tx_chars(uap); | 1251 | pl011_tx_chars(uap); |
1160 | 1252 | ||
1161 | if (pass_counter-- == 0) | 1253 | if (pass_counter-- == 0) { |
1254 | if (uap->interrupt_may_hang) | ||
1255 | tasklet_schedule(&pl011_lockup_tlet); | ||
1162 | break; | 1256 | break; |
1257 | } | ||
1163 | 1258 | ||
1164 | status = readw(uap->port.membase + UART011_MIS); | 1259 | status = readw(uap->port.membase + UART011_MIS); |
1165 | } while (status != 0); | 1260 | } while (status != 0); |
@@ -1339,6 +1434,14 @@ static int pl011_startup(struct uart_port *port) | |||
1339 | writew(uap->im, uap->port.membase + UART011_IMSC); | 1434 | writew(uap->im, uap->port.membase + UART011_IMSC); |
1340 | spin_unlock_irq(&uap->port.lock); | 1435 | spin_unlock_irq(&uap->port.lock); |
1341 | 1436 | ||
1437 | if (uap->port.dev->platform_data) { | ||
1438 | struct amba_pl011_data *plat; | ||
1439 | |||
1440 | plat = uap->port.dev->platform_data; | ||
1441 | if (plat->init) | ||
1442 | plat->init(); | ||
1443 | } | ||
1444 | |||
1342 | return 0; | 1445 | return 0; |
1343 | 1446 | ||
1344 | clk_dis: | 1447 | clk_dis: |
@@ -1394,6 +1497,15 @@ static void pl011_shutdown(struct uart_port *port) | |||
1394 | * Shut down the clock producer | 1497 | * Shut down the clock producer |
1395 | */ | 1498 | */ |
1396 | clk_disable(uap->clk); | 1499 | clk_disable(uap->clk); |
1500 | |||
1501 | if (uap->port.dev->platform_data) { | ||
1502 | struct amba_pl011_data *plat; | ||
1503 | |||
1504 | plat = uap->port.dev->platform_data; | ||
1505 | if (plat->exit) | ||
1506 | plat->exit(); | ||
1507 | } | ||
1508 | |||
1397 | } | 1509 | } |
1398 | 1510 | ||
1399 | static void | 1511 | static void |
@@ -1700,6 +1812,14 @@ static int __init pl011_console_setup(struct console *co, char *options) | |||
1700 | if (!uap) | 1812 | if (!uap) |
1701 | return -ENODEV; | 1813 | return -ENODEV; |
1702 | 1814 | ||
1815 | if (uap->port.dev->platform_data) { | ||
1816 | struct amba_pl011_data *plat; | ||
1817 | |||
1818 | plat = uap->port.dev->platform_data; | ||
1819 | if (plat->init) | ||
1820 | plat->init(); | ||
1821 | } | ||
1822 | |||
1703 | uap->port.uartclk = clk_get_rate(uap->clk); | 1823 | uap->port.uartclk = clk_get_rate(uap->clk); |
1704 | 1824 | ||
1705 | if (options) | 1825 | if (options) |
@@ -1774,6 +1894,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) | |||
1774 | uap->lcrh_rx = vendor->lcrh_rx; | 1894 | uap->lcrh_rx = vendor->lcrh_rx; |
1775 | uap->lcrh_tx = vendor->lcrh_tx; | 1895 | uap->lcrh_tx = vendor->lcrh_tx; |
1776 | uap->fifosize = vendor->fifosize; | 1896 | uap->fifosize = vendor->fifosize; |
1897 | uap->interrupt_may_hang = vendor->interrupt_may_hang; | ||
1777 | uap->port.dev = &dev->dev; | 1898 | uap->port.dev = &dev->dev; |
1778 | uap->port.mapbase = dev->res.start; | 1899 | uap->port.mapbase = dev->res.start; |
1779 | uap->port.membase = base; | 1900 | uap->port.membase = base; |
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index a1a0e55d0807..c0b68b9cad91 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c | |||
@@ -250,6 +250,20 @@ static void bcm_uart_do_rx(struct uart_port *port) | |||
250 | /* get overrun/fifo empty information from ier | 250 | /* get overrun/fifo empty information from ier |
251 | * register */ | 251 | * register */ |
252 | iestat = bcm_uart_readl(port, UART_IR_REG); | 252 | iestat = bcm_uart_readl(port, UART_IR_REG); |
253 | |||
254 | if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) { | ||
255 | unsigned int val; | ||
256 | |||
257 | /* fifo reset is required to clear | ||
258 | * interrupt */ | ||
259 | val = bcm_uart_readl(port, UART_CTL_REG); | ||
260 | val |= UART_CTL_RSTRXFIFO_MASK; | ||
261 | bcm_uart_writel(port, val, UART_CTL_REG); | ||
262 | |||
263 | port->icount.overrun++; | ||
264 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
265 | } | ||
266 | |||
253 | if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) | 267 | if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY))) |
254 | break; | 268 | break; |
255 | 269 | ||
@@ -284,10 +298,6 @@ static void bcm_uart_do_rx(struct uart_port *port) | |||
284 | if (uart_handle_sysrq_char(port, c)) | 298 | if (uart_handle_sysrq_char(port, c)) |
285 | continue; | 299 | continue; |
286 | 300 | ||
287 | if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) { | ||
288 | port->icount.overrun++; | ||
289 | tty_insert_flip_char(tty, 0, TTY_OVERRUN); | ||
290 | } | ||
291 | 301 | ||
292 | if ((cstat & port->ignore_status_mask) == 0) | 302 | if ((cstat & port->ignore_status_mask) == 0) |
293 | tty_insert_flip_char(tty, c, flag); | 303 | tty_insert_flip_char(tty, c, flag); |
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 18f548449c63..96da17868cf3 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c | |||
@@ -125,7 +125,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device | |||
125 | brd->bd_uart_offset = 0x200; | 125 | brd->bd_uart_offset = 0x200; |
126 | brd->bd_dividend = 921600; | 126 | brd->bd_dividend = 921600; |
127 | 127 | ||
128 | brd->re_map_membase = ioremap(brd->membase, 0x1000); | 128 | brd->re_map_membase = ioremap(brd->membase, pci_resource_len(pdev, 0)); |
129 | if (!brd->re_map_membase) { | 129 | if (!brd->re_map_membase) { |
130 | dev_err(&pdev->dev, | 130 | dev_err(&pdev->dev, |
131 | "card has no PCI Memory resources, " | 131 | "card has no PCI Memory resources, " |
diff --git a/drivers/tty/serial/s5pv210.c b/drivers/tty/serial/s5pv210.c index fb2619f93d84..dd194dc80ee9 100644 --- a/drivers/tty/serial/s5pv210.c +++ b/drivers/tty/serial/s5pv210.c | |||
@@ -30,7 +30,7 @@ static int s5pv210_serial_setsource(struct uart_port *port, | |||
30 | struct s3c2410_uartcfg *cfg = port->dev->platform_data; | 30 | struct s3c2410_uartcfg *cfg = port->dev->platform_data; |
31 | unsigned long ucon = rd_regl(port, S3C2410_UCON); | 31 | unsigned long ucon = rd_regl(port, S3C2410_UCON); |
32 | 32 | ||
33 | if ((cfg->clocks_size) == 1) | 33 | if (cfg->flags & NO_NEED_CHECK_CLKSRC) |
34 | return 0; | 34 | return 0; |
35 | 35 | ||
36 | if (strcmp(clk->name, "pclk") == 0) | 36 | if (strcmp(clk->name, "pclk") == 0) |
@@ -55,7 +55,7 @@ static int s5pv210_serial_getsource(struct uart_port *port, | |||
55 | 55 | ||
56 | clk->divisor = 1; | 56 | clk->divisor = 1; |
57 | 57 | ||
58 | if ((cfg->clocks_size) == 1) | 58 | if (cfg->flags & NO_NEED_CHECK_CLKSRC) |
59 | return 0; | 59 | return 0; |
60 | 60 | ||
61 | switch (ucon & S5PV210_UCON_CLKMASK) { | 61 | switch (ucon & S5PV210_UCON_CLKMASK) { |
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 5d01d32e2cf0..ef925d581713 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c | |||
@@ -555,7 +555,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) | |||
555 | static int tty_ldisc_wait_idle(struct tty_struct *tty) | 555 | static int tty_ldisc_wait_idle(struct tty_struct *tty) |
556 | { | 556 | { |
557 | int ret; | 557 | int ret; |
558 | ret = wait_event_interruptible_timeout(tty_ldisc_idle, | 558 | ret = wait_event_timeout(tty_ldisc_idle, |
559 | atomic_read(&tty->ldisc->users) == 1, 5 * HZ); | 559 | atomic_read(&tty->ldisc->users) == 1, 5 * HZ); |
560 | if (ret < 0) | 560 | if (ret < 0) |
561 | return ret; | 561 | return ret; |
@@ -763,6 +763,8 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) | |||
763 | if (IS_ERR(ld)) | 763 | if (IS_ERR(ld)) |
764 | return -1; | 764 | return -1; |
765 | 765 | ||
766 | WARN_ON_ONCE(tty_ldisc_wait_idle(tty)); | ||
767 | |||
766 | tty_ldisc_close(tty, tty->ldisc); | 768 | tty_ldisc_close(tty, tty->ldisc); |
767 | tty_ldisc_put(tty->ldisc); | 769 | tty_ldisc_put(tty->ldisc); |
768 | tty->ldisc = NULL; | 770 | tty->ldisc = NULL; |
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index 5479fdc849e9..514ed45c462e 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h | |||
@@ -201,6 +201,9 @@ struct amba_pl011_data { | |||
201 | bool (*dma_filter)(struct dma_chan *chan, void *filter_param); | 201 | bool (*dma_filter)(struct dma_chan *chan, void *filter_param); |
202 | void *dma_rx_param; | 202 | void *dma_rx_param; |
203 | void *dma_tx_param; | 203 | void *dma_tx_param; |
204 | void (*init) (void); | ||
205 | void (*exit) (void); | ||
206 | void (*reset) (void); | ||
204 | }; | 207 | }; |
205 | #endif | 208 | #endif |
206 | 209 | ||