diff options
Diffstat (limited to 'drivers/tty/serial/omap-serial.c')
| -rw-r--r-- | drivers/tty/serial/omap-serial.c | 222 | 
1 files changed, 110 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 |