diff options
| -rw-r--r-- | drivers/tty/serial/omap-serial.c | 222 | ||||
| -rw-r--r-- | include/linux/platform_data/serial-omap.h | 1 |
2 files changed, 111 insertions, 112 deletions
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index aaad63b7fe8..780c5c28545 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -67,6 +67,10 @@ #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6) #define OMAP_UART_FCR_TX_FIFO_TRIG_MASK (0x3 << 4) +/* TLR register bitmasks */ +#define OMAP_UART_TLR_RX_FIFO_TRIG_MASK (0xf << 4) +#define OMAP_UART_TLR_TX_FIFO_TRIG_MASK (0xf) + /* MVR register bitmasks */ #define OMAP_UART_MVR_SCHEME_SHIFT 30 @@ -138,6 +142,9 @@ struct uart_omap_port { unsigned char dlh; unsigned char mdr1; unsigned char scr; + unsigned char tlr; + unsigned char xon1; + unsigned char xoff; int use_dma; /* @@ -165,6 +172,7 @@ struct uart_omap_port { bool in_transmit; int ext_rt_cnt; bool open_close_pm; + unsigned int rx_trig; int (*get_context_loss_count)(struct device *); }; @@ -371,6 +379,7 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) pm_runtime_get_sync(up->dev); } count = up->port.fifosize / 4; + do { serial_out(up, UART_TX, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -462,71 +471,60 @@ static unsigned int check_modem_status(struct uart_omap_port *up) return status; } - -static void serial_omap_rlsi(struct uart_omap_port *up, unsigned int lsr) +static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) { - unsigned int flag; unsigned char ch = 0; + unsigned int flag; + int max_count = 256; - if (likely(lsr & UART_LSR_DR)) - ch = serial_in(up, UART_RX); - - up->port.icount.rx++; - flag = TTY_NORMAL; - - if (lsr & UART_LSR_BI) { - flag = TTY_BREAK; - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - up->port.icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(&up->port)) - return; - - } - - if (lsr & UART_LSR_PE) { - flag = TTY_PARITY; - up->port.icount.parity++; - } + do { + if (likely(lsr & UART_LSR_DR)) + ch = serial_in(up, UART_RX); + flag = TTY_NORMAL; + up->port.icount.rx++; - if (lsr & UART_LSR_FE) { - flag = TTY_FRAME; - up->port.icount.frame++; - } + if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { + /* + * For statistics only + */ + if (lsr & UART_LSR_BI) { + lsr &= ~(UART_LSR_FE | UART_LSR_PE); + up->port.icount.brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ + if (uart_handle_break(&up->port)) + goto ignore_char; + } else if (lsr & UART_LSR_PE) { + flag = TTY_PARITY; + up->port.icount.parity++; + } else if (lsr & UART_LSR_FE) { + flag = TTY_FRAME; + up->port.icount.frame++; + } - if (lsr & UART_LSR_OE) - up->port.icount.overrun++; + if (lsr & UART_LSR_OE) + up->port.icount.overrun++; #ifdef CONFIG_SERIAL_OMAP_CONSOLE - if (up->port.line == up->port.cons->index) { - /* Recover the break flag from console xmit */ - lsr |= up->lsr_break_flag; - } + if (up->port.line == up->port.cons->index) { + /* Recover the break flag from console xmit */ + lsr |= up->lsr_break_flag; + } #endif - uart_insert_char(&up->port, lsr, UART_LSR_OE, 0, flag); -} - -static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr) -{ - unsigned char ch = 0; - unsigned int flag; - - if (!(lsr & UART_LSR_DR)) - return; - - ch = serial_in(up, UART_RX); - flag = TTY_NORMAL; - up->port.icount.rx++; - - if (uart_handle_sysrq_char(&up->port, ch)) - return; + uart_insert_char(&up->port, lsr, UART_LSR_OE, 0, flag); + goto ignore_char; + } - uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); + if (uart_handle_sysrq_char(&up->port, ch)) + goto ignore_char; + uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); +ignore_char: + lsr = serial_in(up, UART_LSR); + } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0)); } /** @@ -563,13 +561,10 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) case UART_IIR_THRI: transmit_chars(up, lsr); break; - case UART_IIR_RX_TIMEOUT: - /* FALLTHROUGH */ case UART_IIR_RDI: - serial_omap_rdi(up, lsr); - break; case UART_IIR_RLSI: - serial_omap_rlsi(up, lsr); + case UART_IIR_RX_TIMEOUT: + serial_omap_rdi(up, lsr); break; case UART_IIR_CTS_RTS_DSR: /* simply try again */ @@ -923,27 +918,24 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); /* FIFO ENABLE, DMA MODE */ - up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK; - - /* - * NOTE: Setting OMAP_UART_SCR_RX_TRIG_GRANU1_MASK - * sets Enables the granularity of 1 for TRIGGER RX - * level. Along with setting RX FIFO trigger level - * to 1 (as noted below, 16 characters) and TLR[3:0] - * to zero this will result RX FIFO threshold level - * to 1 character, instead of 16 as noted in comment - * below. - */ - - /* Set receive FIFO threshold to 16 characters and - * transmit FIFO threshold to 16 spaces - */ up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK; up->fcr &= ~OMAP_UART_FCR_TX_FIFO_TRIG_MASK; - up->fcr |= UART_FCR6_R_TRIGGER_16 | UART_FCR6_T_TRIGGER_24 | - UART_FCR_ENABLE_FIFO; + + up->fcr |= UART_FCR6_T_TRIGGER_24 | UART_FCR_ENABLE_FIFO; + + if ((up->rx_trig & 0x3) != 0) { + up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK; + up->fcr |= (up->rx_trig & 0x3) << + __ffs(OMAP_UART_FCR_RX_FIFO_TRIG_MASK); + up->tlr |= ((up->rx_trig & 0x3) >> 2) << + __ffs(OMAP_UART_TLR_RX_FIFO_TRIG_MASK); + } + up->tlr |= ((up->rx_trig & 0x3C) >> 2) << + __ffs(OMAP_UART_TLR_RX_FIFO_TRIG_MASK); serial_out(up, UART_FCR, up->fcr); + serial_out(up, UART_TI752_TLR, up->tlr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(up, UART_OMAP_SCR, up->scr); @@ -993,8 +985,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* XON1/XOFF1 accessible mode B, TCRTLR=0, ECB=0 */ - serial_out(up, UART_XON1, termios->c_cc[VSTART]); - serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]); + up->xon1 = termios->c_cc[VSTART]; + up->xoff = termios->c_cc[VSTOP]; + serial_out(up, UART_XON1, up->xon1); + serial_out(up, UART_XOFF1, up->xoff); /* Enable access to TCR/TLR */ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); @@ -1431,23 +1425,22 @@ static void omap_serial_fill_features_erratas(struct uart_omap_port *up) static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) { - struct omap_uart_port_info *omap_up_info; + struct omap_uart_port_info *oi; + struct device_node *np = dev->of_node; - omap_up_info = devm_kzalloc(dev, sizeof(*omap_up_info), GFP_KERNEL); - if (!omap_up_info) + oi = devm_kzalloc(dev, sizeof(*oi), GFP_KERNEL); + if (!oi) return NULL; /* out of memory */ - of_property_read_u32(dev->of_node, "clock-frequency", - &omap_up_info->uartclk); - of_property_read_u32(dev->of_node, "flags", - &omap_up_info->flags); - omap_up_info->wakeup_capable = of_property_read_bool(dev->of_node, - "wakeup-capable"); - of_property_read_u32(dev->of_node, "autosuspend-delay", - &omap_up_info->autosuspend_timeout); - omap_up_info->open_close_pm = of_property_read_bool(dev->of_node, - "open_close_pm"); - return omap_up_info; + of_property_read_u32(np, "clock-frequency", &oi->uartclk); + of_property_read_u32(np, "flags", &oi->flags); + oi->wakeup_capable = of_property_read_bool(np, "wakeup-capable"); + of_property_read_u32(np, "autosuspend-delay", &oi->autosuspend_timeout); + oi->open_close_pm = of_property_read_bool(np, "open_close_pm"); + if (of_property_read_u32(np, "rx_trig", &oi->rx_trig)) + oi->rx_trig = 1; + + return oi; } static int serial_omap_probe(struct platform_device *pdev) @@ -1540,6 +1533,7 @@ static int serial_omap_probe(struct platform_device *pdev) goto err_ioremap; } + up->rx_trig = omap_up_info->rx_trig; up->port.flags = omap_up_info->flags; up->port.uartclk = omap_up_info->uartclk; if (!up->port.uartclk) { @@ -1547,7 +1541,6 @@ static int serial_omap_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "No clock speed specified: using default:" "%d\n", DEFAULT_CLK_SPEED); } - up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; up->calc_latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; pm_qos_add_request(&up->pm_qos_request, @@ -1641,27 +1634,32 @@ static void serial_omap_mdr1_errataset(struct uart_omap_port *up, u8 mdr1) #ifdef CONFIG_PM_RUNTIME static void serial_omap_restore_context(struct uart_omap_port *up) { - if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) - serial_omap_mdr1_errataset(up, UART_OMAP_MDR1_DISABLE); - else - serial_out(up, UART_OMAP_MDR1, UART_OMAP_MDR1_DISABLE); - - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */ - serial_out(up, UART_EFR, UART_EFR_ECB); - serial_out(up, UART_LCR, 0x0); /* Operational mode */ - serial_out(up, UART_IER, 0x0); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */ - serial_out(up, UART_DLL, up->dll); - serial_out(up, UART_DLM, up->dlh); - serial_out(up, UART_LCR, 0x0); /* Operational mode */ - serial_out(up, UART_IER, up->ier); - serial_out(up, UART_FCR, up->fcr); + /* FCR can be changed only when the + * baud clock is not running + * DLL_REG and DLH_REG set to 0. + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_DLL, 0); + serial_out(up, UART_DLM, 0); + /* FCR can be written only if ECB is set */ + serial_out(up, UART_EFR, up->efr | UART_EFR_ECB); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_out(up, UART_MCR, up->mcr); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */ + serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR); + serial_out(up, UART_FCR, up->fcr); + serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG); + serial_out(up, UART_TI752_TLR, up->tlr); serial_out(up, UART_OMAP_SCR, up->scr); + /* Reset UART_MCR_TCRTLR: this must be done with the EFR_ECB bit set */ + serial_out(up, UART_MCR, up->mcr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(up, UART_EFR, up->efr); + serial_out(up, UART_DLL, up->dll); /* LS of divisor */ + serial_out(up, UART_DLM, up->dlh); /* MS of divisor */ + /* XON1/XOFF1 accessible mode B, TCRTLR=0, ECB=0 */ + serial_out(up, UART_XON1, up->xon1); + serial_out(up, UART_XOFF1, up->xoff); serial_out(up, UART_LCR, up->lcr); + serial_out(up, UART_IER, up->ier); if (up->errata & UART_ERRATA_i202_MDR1_ACCESS) serial_omap_mdr1_errataset(up, up->mdr1); else diff --git a/include/linux/platform_data/serial-omap.h b/include/linux/platform_data/serial-omap.h index b2239557aa2..838132af5d8 100644 --- a/include/linux/platform_data/serial-omap.h +++ b/include/linux/platform_data/serial-omap.h @@ -43,6 +43,7 @@ struct omap_uart_port_info { int DTR_present; bool wakeup_capable; bool open_close_pm; + unsigned int rx_trig; int (*get_context_loss_count)(struct device *); void (*enable_wakeup)(struct device *, bool); |