diff options
Diffstat (limited to 'drivers/tty/serial/arc_uart.c')
| -rw-r--r-- | drivers/tty/serial/arc_uart.c | 337 | 
1 files changed, 121 insertions, 216 deletions
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 008c223eaf26..a59d1d77e750 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -37,8 +37,8 @@  #include <linux/tty_flip.h>  #include <linux/serial_core.h>  #include <linux/io.h> -#include <linux/of.h> -#include <linux/of_platform.h> +#include <linux/of_irq.h> +#include <linux/of_address.h>  /*************************************   * ARC UART Hardware Specs @@ -72,7 +72,7 @@  #define RXOERR  0x02	/* OverFlow Err: Char recv but RXFULL still set */  /* Uart bit fiddling helpers: lowest level */ -#define RBASE(uart, reg)      (uart->port.membase + reg) +#define RBASE(port, reg)      (port->membase + reg)  #define UART_REG_SET(u, r, v) writeb((v), RBASE(u, r))  #define UART_REG_GET(u, r)    readb(RBASE(u, r)) @@ -102,7 +102,6 @@  struct arc_uart_port {  	struct uart_port port;  	unsigned long baud; -	int is_emulated;	/* H/w vs. Instruction Set Simulator */  };  #define to_arc_port(uport)  container_of(uport, struct arc_uart_port, port) @@ -129,19 +128,15 @@ static struct uart_driver arc_uart_driver = {  static void arc_serial_stop_rx(struct uart_port *port)  { -	struct arc_uart_port *uart = to_arc_port(port); - -	UART_RX_IRQ_DISABLE(uart); +	UART_RX_IRQ_DISABLE(port);  }  static void arc_serial_stop_tx(struct uart_port *port)  { -	struct arc_uart_port *uart = to_arc_port(port); - -	while (!(UART_GET_STATUS(uart) & TXEMPTY)) +	while (!(UART_GET_STATUS(port) & TXEMPTY))  		cpu_relax(); -	UART_TX_IRQ_DISABLE(uart); +	UART_TX_IRQ_DISABLE(port);  }  /* @@ -149,10 +144,9 @@ static void arc_serial_stop_tx(struct uart_port *port)   */  static unsigned int arc_serial_tx_empty(struct uart_port *port)  { -	struct arc_uart_port *uart = to_arc_port(port);  	unsigned int stat; -	stat = UART_GET_STATUS(uart); +	stat = UART_GET_STATUS(port);  	if (stat & TXEMPTY)  		return TIOCSER_TEMT; @@ -166,24 +160,24 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port)   *     = by uart_start( ) before calling us   *     = tx_ist checks that too before calling   */ -static void arc_serial_tx_chars(struct arc_uart_port *uart) +static void arc_serial_tx_chars(struct uart_port *port)  { -	struct circ_buf *xmit = &uart->port.state->xmit; +	struct circ_buf *xmit = &port->state->xmit;  	int sent = 0;  	unsigned char ch; -	if (unlikely(uart->port.x_char)) { -		UART_SET_DATA(uart, uart->port.x_char); -		uart->port.icount.tx++; -		uart->port.x_char = 0; +	if (unlikely(port->x_char)) { +		UART_SET_DATA(port, port->x_char); +		port->icount.tx++; +		port->x_char = 0;  		sent = 1;  	} else if (!uart_circ_empty(xmit)) {  		ch = xmit->buf[xmit->tail];  		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -		uart->port.icount.tx++; -		while (!(UART_GET_STATUS(uart) & TXEMPTY)) +		port->icount.tx++; +		while (!(UART_GET_STATUS(port) & TXEMPTY))  			cpu_relax(); -		UART_SET_DATA(uart, ch); +		UART_SET_DATA(port, ch);  		sent = 1;  	} @@ -192,10 +186,10 @@ static void arc_serial_tx_chars(struct arc_uart_port *uart)  	 * By Hard ISR to schedule processing in software interrupt part  	 */  	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) -		uart_write_wakeup(&uart->port); +		uart_write_wakeup(port);  	if (sent) -		UART_TX_IRQ_ENABLE(uart); +		UART_TX_IRQ_ENABLE(port);  }  /* @@ -204,12 +198,10 @@ static void arc_serial_tx_chars(struct arc_uart_port *uart)   */  static void arc_serial_start_tx(struct uart_port *port)  { -	struct arc_uart_port *uart = to_arc_port(port); - -	arc_serial_tx_chars(uart); +	arc_serial_tx_chars(port);  } -static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status) +static void arc_serial_rx_chars(struct uart_port *port, unsigned int status)  {  	unsigned int ch, flg = 0; @@ -229,15 +221,15 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status)  		 */  		if (unlikely(status & (RXOERR | RXFERR))) {  			if (status & RXOERR) { -				uart->port.icount.overrun++; +				port->icount.overrun++;  				flg = TTY_OVERRUN; -				UART_CLR_STATUS(uart, RXOERR); +				UART_CLR_STATUS(port, RXOERR);  			}  			if (status & RXFERR) { -				uart->port.icount.frame++; +				port->icount.frame++;  				flg = TTY_FRAME; -				UART_CLR_STATUS(uart, RXFERR); +				UART_CLR_STATUS(port, RXFERR);  			}  		} else  			flg = TTY_NORMAL; @@ -245,16 +237,16 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status)  		if (status & RXEMPTY)  			continue; -		ch = UART_GET_DATA(uart); -		uart->port.icount.rx++; +		ch = UART_GET_DATA(port); +		port->icount.rx++; -		if (!(uart_handle_sysrq_char(&uart->port, ch))) -			uart_insert_char(&uart->port, status, RXOERR, ch, flg); +		if (!(uart_handle_sysrq_char(port, ch))) +			uart_insert_char(port, status, RXOERR, ch, flg); -		spin_unlock(&uart->port.lock); -		tty_flip_buffer_push(&uart->port.state->port); -		spin_lock(&uart->port.lock); -	} while (!((status = UART_GET_STATUS(uart)) & RXEMPTY)); +		spin_unlock(&port->lock); +		tty_flip_buffer_push(&port->state->port); +		spin_lock(&port->lock); +	} while (!((status = UART_GET_STATUS(port)) & RXEMPTY));  }  /* @@ -287,10 +279,10 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart, unsigned int status)  static irqreturn_t arc_serial_isr(int irq, void *dev_id)  { -	struct arc_uart_port *uart = dev_id; +	struct uart_port *port = dev_id;  	unsigned int status; -	status = UART_GET_STATUS(uart); +	status = UART_GET_STATUS(port);  	/*  	 * Single IRQ for both Rx (data available) Tx (room available) Interrupt @@ -300,9 +292,9 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id)  	if (status & RXIENB) {  		/* already in ISR, no need of xx_irqsave */ -		spin_lock(&uart->port.lock); -		arc_serial_rx_chars(uart, status); -		spin_unlock(&uart->port.lock); +		spin_lock(&port->lock); +		arc_serial_rx_chars(port, status); +		spin_unlock(&port->lock);  	}  	if ((status & TXIENB) && (status & TXEMPTY)) { @@ -310,14 +302,14 @@ static irqreturn_t arc_serial_isr(int irq, void *dev_id)  		/* Unconditionally disable further Tx-Interrupts.  		 * will be enabled by tx_chars() if needed.  		 */ -		UART_TX_IRQ_DISABLE(uart); +		UART_TX_IRQ_DISABLE(port); -		spin_lock(&uart->port.lock); +		spin_lock(&port->lock); -		if (!uart_tx_stopped(&uart->port)) -			arc_serial_tx_chars(uart); +		if (!uart_tx_stopped(port)) +			arc_serial_tx_chars(port); -		spin_unlock(&uart->port.lock); +		spin_unlock(&port->lock);  	}  	return IRQ_HANDLED; @@ -340,13 +332,6 @@ static void arc_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)  	/* MCR not present */  } -/* Enable Modem Status Interrupts */ - -static void arc_serial_enable_ms(struct uart_port *port) -{ -	/* MSR not present */ -} -  static void arc_serial_break_ctl(struct uart_port *port, int break_state)  {  	/* ARC UART doesn't support sending Break signal */ @@ -354,18 +339,15 @@ static void arc_serial_break_ctl(struct uart_port *port, int break_state)  static int arc_serial_startup(struct uart_port *port)  { -	struct arc_uart_port *uart = to_arc_port(port); -  	/* Before we hook up the ISR, Disable all UART Interrupts */ -	UART_ALL_IRQ_DISABLE(uart); +	UART_ALL_IRQ_DISABLE(port); -	if (request_irq(uart->port.irq, arc_serial_isr, 0, "arc uart rx-tx", -			uart)) { -		dev_warn(uart->port.dev, "Unable to attach ARC UART intr\n"); +	if (request_irq(port->irq, arc_serial_isr, 0, "arc uart rx-tx", port)) { +		dev_warn(port->dev, "Unable to attach ARC UART intr\n");  		return -EBUSY;  	} -	UART_RX_IRQ_ENABLE(uart); /* Only Rx IRQ enabled to begin with */ +	UART_RX_IRQ_ENABLE(port); /* Only Rx IRQ enabled to begin with */  	return 0;  } @@ -373,8 +355,7 @@ static int arc_serial_startup(struct uart_port *port)  /* This is not really needed */  static void arc_serial_shutdown(struct uart_port *port)  { -	struct arc_uart_port *uart = to_arc_port(port); -	free_irq(uart->port.irq, uart); +	free_irq(port->irq, port);  }  static void @@ -398,25 +379,14 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new,  	uartl = hw_val & 0xFF;  	uarth = (hw_val >> 8) & 0xFF; -	/* -	 * UART ISS(Instruction Set simulator) emulation has a subtle bug: -	 * A existing value of Baudh = 0 is used as a indication to startup -	 * it's internal state machine. -	 * Thus if baudh is set to 0, 2 times, it chokes. -	 * This happens with BAUD=115200 and the formaula above -	 * Until that is fixed, when running on ISS, we will set baudh to !0 -	 */ -	if (uart->is_emulated) -		uarth = 1; -  	spin_lock_irqsave(&port->lock, flags); -	UART_ALL_IRQ_DISABLE(uart); +	UART_ALL_IRQ_DISABLE(port); -	UART_SET_BAUDL(uart, uartl); -	UART_SET_BAUDH(uart, uarth); +	UART_SET_BAUDL(port, uartl); +	UART_SET_BAUDH(port, uarth); -	UART_RX_IRQ_ENABLE(uart); +	UART_RX_IRQ_ENABLE(port);  	/*  	 * UART doesn't support Parity/Hardware Flow Control; @@ -439,9 +409,7 @@ arc_serial_set_termios(struct uart_port *port, struct ktermios *new,  static const char *arc_serial_type(struct uart_port *port)  { -	struct arc_uart_port *uart = to_arc_port(port); - -	return uart->port.type == PORT_ARC ? DRIVER_NAME : NULL; +	return port->type == PORT_ARC ? DRIVER_NAME : NULL;  }  static void arc_serial_release_port(struct uart_port *port) @@ -470,35 +438,28 @@ arc_serial_verify_port(struct uart_port *port, struct serial_struct *ser)   */  static void arc_serial_config_port(struct uart_port *port, int flags)  { -	struct arc_uart_port *uart = to_arc_port(port); -  	if (flags & UART_CONFIG_TYPE) -		uart->port.type = PORT_ARC; +		port->type = PORT_ARC;  } -#if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_ARC_CONSOLE) +#ifdef CONFIG_CONSOLE_POLL  static void arc_serial_poll_putchar(struct uart_port *port, unsigned char chr)  { -	struct arc_uart_port *uart = to_arc_port(port); - -	while (!(UART_GET_STATUS(uart) & TXEMPTY)) +	while (!(UART_GET_STATUS(port) & TXEMPTY))  		cpu_relax(); -	UART_SET_DATA(uart, chr); +	UART_SET_DATA(port, chr);  } -#endif -#ifdef CONFIG_CONSOLE_POLL  static int arc_serial_poll_getchar(struct uart_port *port)  { -	struct arc_uart_port *uart = to_arc_port(port);  	unsigned char chr; -	while (!(UART_GET_STATUS(uart) & RXEMPTY)) +	while (!(UART_GET_STATUS(port) & RXEMPTY))  		cpu_relax(); -	chr = UART_GET_DATA(uart); +	chr = UART_GET_DATA(port);  	return chr;  }  #endif @@ -510,7 +471,6 @@ static struct uart_ops arc_serial_pops = {  	.stop_tx	= arc_serial_stop_tx,  	.start_tx	= arc_serial_start_tx,  	.stop_rx	= arc_serial_stop_rx, -	.enable_ms	= arc_serial_enable_ms,  	.break_ctl	= arc_serial_break_ctl,  	.startup	= arc_serial_startup,  	.shutdown	= arc_serial_shutdown, @@ -526,71 +486,6 @@ static struct uart_ops arc_serial_pops = {  #endif  }; -static int -arc_uart_init_one(struct platform_device *pdev, int dev_id) -{ -	struct resource *res, *res2; -	unsigned long *plat_data; -	struct arc_uart_port *uart = &arc_uart_ports[dev_id]; - -	plat_data = dev_get_platdata(&pdev->dev); -	if (!plat_data) -		return -ENODEV; - -	uart->is_emulated = !!plat_data[0];	/* workaround ISS bug */ - -	if (is_early_platform_device(pdev)) { -		uart->port.uartclk = plat_data[1]; -		uart->baud = plat_data[2]; -	} else { -		struct device_node *np = pdev->dev.of_node; -		u32 val; - -		if (of_property_read_u32(np, "clock-frequency", &val)) { -			dev_err(&pdev->dev, "clock-frequency property NOTset\n"); -			return -EINVAL; -		} -		uart->port.uartclk = val; - -		if (of_property_read_u32(np, "current-speed", &val)) { -			dev_err(&pdev->dev, "current-speed property NOT set\n"); -			return -EINVAL; -		} -		uart->baud = val; -	} - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) -		return -ENODEV; - -	res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -	if (!res2) -		return -ENODEV; - -	uart->port.mapbase = res->start; -	uart->port.membase = ioremap_nocache(res->start, resource_size(res)); -	if (!uart->port.membase) -		/* No point of dev_err since UART itself is hosed here */ -		return -ENXIO; - -	uart->port.irq = res2->start; -	uart->port.dev = &pdev->dev; -	uart->port.iotype = UPIO_MEM; -	uart->port.flags = UPF_BOOT_AUTOCONF; -	uart->port.line = dev_id; -	uart->port.ops = &arc_serial_pops; - -	uart->port.fifosize = ARC_UART_TX_FIFO_SIZE; - -	/* -	 * uart_insert_char( ) uses it in decideding whether to ignore a -	 * char or not. Explicitly setting it here, removes the subtelty -	 */ -	uart->port.ignore_status_mask = 0; - -	return 0; -} -  #ifdef CONFIG_SERIAL_ARC_CONSOLE  static int arc_serial_console_setup(struct console *co, char *options) @@ -624,7 +519,10 @@ static int arc_serial_console_setup(struct console *co, char *options)  static void arc_serial_console_putchar(struct uart_port *port, int ch)  { -	arc_serial_poll_putchar(port, (unsigned char)ch); +	while (!(UART_GET_STATUS(port) & TXEMPTY)) +		cpu_relax(); + +	UART_SET_DATA(port, (unsigned char)ch);  }  /* @@ -651,48 +549,45 @@ static struct console arc_console = {  	.data	= &arc_uart_driver  }; -static __init void early_serial_write(struct console *con, const char *s, -					unsigned int n) +static __init void arc_early_serial_write(struct console *con, const char *s, +					  unsigned int n)  { -	struct uart_port *port = &arc_uart_ports[con->index].port; -	unsigned int i; +	struct earlycon_device *dev = con->data; -	for (i = 0; i < n; i++, s++) { -		if (*s == '\n') -			arc_serial_poll_putchar(port, '\r'); -		arc_serial_poll_putchar(port, *s); -	} +	uart_console_write(&dev->port, s, n, arc_serial_console_putchar);  } -static struct console arc_early_serial_console __initdata = { -	.name = "early_ARCuart", -	.write = early_serial_write, -	.flags = CON_PRINTBUFFER | CON_BOOT, -	.index = -1 -}; - -static int __init arc_serial_probe_earlyprintk(struct platform_device *pdev) +static int __init arc_early_console_setup(struct earlycon_device *dev, +					  const char *opt)  { -	int dev_id = pdev->id < 0 ? 0 : pdev->id; -	int rc; +	struct uart_port *port = &dev->port; +	unsigned int l, h, hw_val; -	arc_early_serial_console.index = dev_id; +	if (!dev->port.membase) +		return -ENODEV; -	rc = arc_uart_init_one(pdev, dev_id); -	if (rc) -		panic("early console init failed\n"); +	hw_val = port->uartclk / (dev->baud * 4) - 1; +	l = hw_val & 0xFF; +	h = (hw_val >> 8) & 0xFF; -	arc_serial_console_setup(&arc_early_serial_console, NULL); +	UART_SET_BAUDL(port, l); +	UART_SET_BAUDH(port, h); -	register_console(&arc_early_serial_console); +	dev->con->write = arc_early_serial_write;  	return 0;  } +EARLYCON_DECLARE(arc_uart, arc_early_console_setup); +OF_EARLYCON_DECLARE(arc_uart, "snps,arc-uart", arc_early_console_setup); +  #endif	/* CONFIG_SERIAL_ARC_CONSOLE */  static int arc_serial_probe(struct platform_device *pdev)  { -	int rc, dev_id;  	struct device_node *np = pdev->dev.of_node; +	struct arc_uart_port *uart; +	struct uart_port *port; +	int dev_id; +	u32 val;  	/* no device tree device */  	if (!np) @@ -702,12 +597,43 @@ static int arc_serial_probe(struct platform_device *pdev)  	if (dev_id < 0)  		dev_id = 0; -	rc = arc_uart_init_one(pdev, dev_id); -	if (rc) -		return rc; +	uart = &arc_uart_ports[dev_id]; +	port = &uart->port; + +	if (of_property_read_u32(np, "clock-frequency", &val)) { +		dev_err(&pdev->dev, "clock-frequency property NOTset\n"); +		return -EINVAL; +	} +	port->uartclk = val; + +	if (of_property_read_u32(np, "current-speed", &val)) { +		dev_err(&pdev->dev, "current-speed property NOT set\n"); +		return -EINVAL; +	} +	uart->baud = val; + +	port->membase = of_iomap(np, 0); +	if (!port->membase) +		/* No point of dev_err since UART itself is hosed here */ +		return -ENXIO; + +	port->irq = irq_of_parse_and_map(np, 0); -	rc = uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port); -	return rc; +	port->dev = &pdev->dev; +	port->iotype = UPIO_MEM; +	port->flags = UPF_BOOT_AUTOCONF; +	port->line = dev_id; +	port->ops = &arc_serial_pops; + +	port->fifosize = ARC_UART_TX_FIFO_SIZE; + +	/* +	 * uart_insert_char( ) uses it in decideding whether to ignore a +	 * char or not. Explicitly setting it here, removes the subtelty +	 */ +	port->ignore_status_mask = 0; + +	return uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port);  }  static int arc_serial_remove(struct platform_device *pdev) @@ -732,27 +658,6 @@ static struct platform_driver arc_platform_driver = {  	 },  }; -#ifdef CONFIG_SERIAL_ARC_CONSOLE - -static struct platform_driver early_arc_platform_driver __initdata = { -	.probe = arc_serial_probe_earlyprintk, -	.remove = arc_serial_remove, -	.driver = { -		.name = DRIVER_NAME, -		.owner = THIS_MODULE, -	 }, -}; -/* - * Register an early platform driver of "earlyprintk" class. - * ARCH platform code installs the driver and probes the early devices - * The installation could rely on user specifying earlyprintk=xyx in cmd line - * or it could be done independently, for all "earlyprintk" class drivers. - * [see arch/arc/plat-arcfpga/platform.c] - */ -early_platform_init("earlyprintk", &early_arc_platform_driver); - -#endif  /* CONFIG_SERIAL_ARC_CONSOLE */ -  static int __init arc_serial_init(void)  {  	int ret;  |