159 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 469daac0faff06209bc1d1390571b860d153a82b Mon Sep 17 00:00:00 2001
 | |
| From: Yangbo Lu <yangbo.lu@nxp.com>
 | |
| Date: Wed, 27 Sep 2017 10:33:47 +0800
 | |
| Subject: [PATCH] tty: serial: support layerscape
 | |
| 
 | |
| This is a integrated patch for layerscape uart support.
 | |
| 
 | |
| Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
 | |
| Signed-off-by: Yuan Yao <yao.yuan@nxp.com>
 | |
| Signed-off-by: Stefan Agner <stefan@agner.ch>
 | |
| Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
 | |
| ---
 | |
|  drivers/tty/serial/fsl_lpuart.c | 66 ++++++++++++++++++++++++++++-------------
 | |
|  1 file changed, 46 insertions(+), 20 deletions(-)
 | |
| 
 | |
| --- a/drivers/tty/serial/fsl_lpuart.c
 | |
| +++ b/drivers/tty/serial/fsl_lpuart.c
 | |
| @@ -231,6 +231,8 @@
 | |
|  #define DEV_NAME	"ttyLP"
 | |
|  #define UART_NR		6
 | |
|  
 | |
| +static DECLARE_BITMAP(linemap, UART_NR);
 | |
| +
 | |
|  struct lpuart_port {
 | |
|  	struct uart_port	port;
 | |
|  	struct clk		*clk;
 | |
| @@ -1348,6 +1350,18 @@ lpuart_set_termios(struct uart_port *por
 | |
|  	/* ask the core to calculate the divisor */
 | |
|  	baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16);
 | |
|  
 | |
| +	/*
 | |
| +	 * Need to update the Ring buffer length according to the selected
 | |
| +	 * baud rate and restart Rx DMA path.
 | |
| +	 *
 | |
| +	 * Since timer function acqures sport->port.lock, need to stop before
 | |
| +	 * acquring same lock because otherwise del_timer_sync() can deadlock.
 | |
| +	 */
 | |
| +	if (old && sport->lpuart_dma_rx_use) {
 | |
| +		del_timer_sync(&sport->lpuart_timer);
 | |
| +		lpuart_dma_rx_free(&sport->port);
 | |
| +	}
 | |
| +
 | |
|  	spin_lock_irqsave(&sport->port.lock, flags);
 | |
|  
 | |
|  	sport->port.read_status_mask = 0;
 | |
| @@ -1397,22 +1411,11 @@ lpuart_set_termios(struct uart_port *por
 | |
|  	/* restore control register */
 | |
|  	writeb(old_cr2, sport->port.membase + UARTCR2);
 | |
|  
 | |
| -	/*
 | |
| -	 * If new baud rate is set, we will also need to update the Ring buffer
 | |
| -	 * length according to the selected baud rate and restart Rx DMA path.
 | |
| -	 */
 | |
| -	if (old) {
 | |
| -		if (sport->lpuart_dma_rx_use) {
 | |
| -			del_timer_sync(&sport->lpuart_timer);
 | |
| -			lpuart_dma_rx_free(&sport->port);
 | |
| -		}
 | |
| -
 | |
| -		if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) {
 | |
| -			sport->lpuart_dma_rx_use = true;
 | |
| +	if (old && sport->lpuart_dma_rx_use) {
 | |
| +		if (!lpuart_start_rx_dma(sport))
 | |
|  			rx_dma_timer_init(sport);
 | |
| -		} else {
 | |
| +		else
 | |
|  			sport->lpuart_dma_rx_use = false;
 | |
| -		}
 | |
|  	}
 | |
|  
 | |
|  	spin_unlock_irqrestore(&sport->port.lock, flags);
 | |
| @@ -1640,6 +1643,13 @@ lpuart_console_write(struct console *co,
 | |
|  {
 | |
|  	struct lpuart_port *sport = lpuart_ports[co->index];
 | |
|  	unsigned char  old_cr2, cr2;
 | |
| +	unsigned long flags;
 | |
| +	int locked = 1;
 | |
| +
 | |
| +	if (sport->port.sysrq || oops_in_progress)
 | |
| +		locked = spin_trylock_irqsave(&sport->port.lock, flags);
 | |
| +	else
 | |
| +		spin_lock_irqsave(&sport->port.lock, flags);
 | |
|  
 | |
|  	/* first save CR2 and then disable interrupts */
 | |
|  	cr2 = old_cr2 = readb(sport->port.membase + UARTCR2);
 | |
| @@ -1654,6 +1664,9 @@ lpuart_console_write(struct console *co,
 | |
|  		barrier();
 | |
|  
 | |
|  	writeb(old_cr2, sport->port.membase + UARTCR2);
 | |
| +
 | |
| +	if (locked)
 | |
| +		spin_unlock_irqrestore(&sport->port.lock, flags);
 | |
|  }
 | |
|  
 | |
|  static void
 | |
| @@ -1661,6 +1674,13 @@ lpuart32_console_write(struct console *c
 | |
|  {
 | |
|  	struct lpuart_port *sport = lpuart_ports[co->index];
 | |
|  	unsigned long  old_cr, cr;
 | |
| +	unsigned long flags;
 | |
| +	int locked = 1;
 | |
| +
 | |
| +	if (sport->port.sysrq || oops_in_progress)
 | |
| +		locked = spin_trylock_irqsave(&sport->port.lock, flags);
 | |
| +	else
 | |
| +		spin_lock_irqsave(&sport->port.lock, flags);
 | |
|  
 | |
|  	/* first save CR2 and then disable interrupts */
 | |
|  	cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL);
 | |
| @@ -1675,6 +1695,9 @@ lpuart32_console_write(struct console *c
 | |
|  		barrier();
 | |
|  
 | |
|  	lpuart32_write(old_cr, sport->port.membase + UARTCTRL);
 | |
| +
 | |
| +	if (locked)
 | |
| +		spin_unlock_irqrestore(&sport->port.lock, flags);
 | |
|  }
 | |
|  
 | |
|  /*
 | |
| @@ -1899,9 +1922,13 @@ static int lpuart_probe(struct platform_
 | |
|  
 | |
|  	ret = of_alias_get_id(np, "serial");
 | |
|  	if (ret < 0) {
 | |
| -		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
 | |
| -		return ret;
 | |
| +		ret = find_first_zero_bit(linemap, UART_NR);
 | |
| +		if (ret >= UART_NR) {
 | |
| +			dev_err(&pdev->dev, "port line is full, add device failed\n");
 | |
| +			return ret;
 | |
| +		}
 | |
|  	}
 | |
| +	set_bit(ret, linemap);
 | |
|  	sport->port.line = ret;
 | |
|  	sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
 | |
|  
 | |
| @@ -1983,6 +2010,7 @@ static int lpuart_remove(struct platform
 | |
|  	struct lpuart_port *sport = platform_get_drvdata(pdev);
 | |
|  
 | |
|  	uart_remove_one_port(&lpuart_reg, &sport->port);
 | |
| +	clear_bit(sport->port.line, linemap);
 | |
|  
 | |
|  	clk_disable_unprepare(sport->clk);
 | |
|  
 | |
| @@ -2067,12 +2095,10 @@ static int lpuart_resume(struct device *
 | |
|  
 | |
|  	if (sport->lpuart_dma_rx_use) {
 | |
|  		if (sport->port.irq_wake) {
 | |
| -			if (!lpuart_start_rx_dma(sport)) {
 | |
| -				sport->lpuart_dma_rx_use = true;
 | |
| +			if (!lpuart_start_rx_dma(sport))
 | |
|  				rx_dma_timer_init(sport);
 | |
| -			} else {
 | |
| +			else
 | |
|  				sport->lpuart_dma_rx_use = false;
 | |
| -			}
 | |
|  		}
 | |
|  	}
 | |
|  
 | 
