diff options
Diffstat (limited to 'drivers/tty/serial/tilegx.c')
-rw-r--r-- | drivers/tty/serial/tilegx.c | 689 |
1 files changed, 0 insertions, 689 deletions
diff --git a/drivers/tty/serial/tilegx.c b/drivers/tty/serial/tilegx.c deleted file mode 100644 index f0a3ae57f881..000000000000 --- a/drivers/tty/serial/tilegx.c +++ /dev/null @@ -1,689 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * TILEGx UART driver. - */ - -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/module.h> -#include <linux/serial_core.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> - -#include <gxio/common.h> -#include <gxio/iorpc_globals.h> -#include <gxio/iorpc_uart.h> -#include <gxio/kiorpc.h> - -#include <hv/drv_uart_intf.h> - -/* - * Use device name ttyS, major 4, minor 64-65. - * This is the usual serial port name, 8250 conventional range. - */ -#define TILEGX_UART_MAJOR TTY_MAJOR -#define TILEGX_UART_MINOR 64 -#define TILEGX_UART_NAME "ttyS" -#define DRIVER_NAME_STRING "TILEGx_Serial" -#define TILEGX_UART_REF_CLK 125000000; /* REF_CLK is always 125 MHz. */ - -struct tile_uart_port { - /* UART port. */ - struct uart_port uart; - - /* GXIO device context. */ - gxio_uart_context_t context; - - /* UART access mutex. */ - struct mutex mutex; - - /* CPU receiving interrupts. */ - int irq_cpu; -}; - -static struct tile_uart_port tile_uart_ports[TILEGX_UART_NR]; -static struct uart_driver tilegx_uart_driver; - - -/* - * Read UART rx fifo, and insert the chars into tty buffer. - */ -static void receive_chars(struct tile_uart_port *tile_uart, - struct tty_struct *tty) -{ - int i; - char c; - UART_FIFO_COUNT_t count; - gxio_uart_context_t *context = &tile_uart->context; - struct tty_port *port = tty->port; - - count.word = gxio_uart_read(context, UART_FIFO_COUNT); - for (i = 0; i < count.rfifo_count; i++) { - c = (char)gxio_uart_read(context, UART_RECEIVE_DATA); - tty_insert_flip_char(port, c, TTY_NORMAL); - } -} - - -/* - * Drain the Rx FIFO, called by interrupt handler. - */ -static void handle_receive(struct tile_uart_port *tile_uart) -{ - struct tty_port *port = &tile_uart->uart.state->port; - struct tty_struct *tty = tty_port_tty_get(port); - gxio_uart_context_t *context = &tile_uart->context; - - if (!tty) - return; - - /* First read UART rx fifo. */ - receive_chars(tile_uart, tty); - - /* Reset RFIFO_WE interrupt. */ - gxio_uart_write(context, UART_INTERRUPT_STATUS, - UART_INTERRUPT_MASK__RFIFO_WE_MASK); - - /* Final read, if any chars comes between the first read and - * the interrupt reset. - */ - receive_chars(tile_uart, tty); - - spin_unlock(&tile_uart->uart.lock); - tty_flip_buffer_push(port); - spin_lock(&tile_uart->uart.lock); - tty_kref_put(tty); -} - - -/* - * Push one char to UART Write FIFO. - * Return 0 on success, -1 if write filo is full. - */ -static int tilegx_putchar(gxio_uart_context_t *context, char c) -{ - UART_FLAG_t flag; - flag.word = gxio_uart_read(context, UART_FLAG); - if (flag.wfifo_full) - return -1; - - gxio_uart_write(context, UART_TRANSMIT_DATA, (unsigned long)c); - return 0; -} - - -/* - * Send chars to UART Write FIFO; called by interrupt handler. - */ -static void handle_transmit(struct tile_uart_port *tile_uart) -{ - unsigned char ch; - struct uart_port *port; - struct circ_buf *xmit; - gxio_uart_context_t *context = &tile_uart->context; - - /* First reset WFIFO_RE interrupt. */ - gxio_uart_write(context, UART_INTERRUPT_STATUS, - UART_INTERRUPT_MASK__WFIFO_RE_MASK); - - port = &tile_uart->uart; - xmit = &port->state->xmit; - if (port->x_char) { - if (tilegx_putchar(context, port->x_char)) - return; - port->x_char = 0; - port->icount.tx++; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) - return; - - while (!uart_circ_empty(xmit)) { - ch = xmit->buf[xmit->tail]; - if (tilegx_putchar(context, ch)) - break; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - - /* Reset WFIFO_RE interrupt. */ - gxio_uart_write(context, UART_INTERRUPT_STATUS, - UART_INTERRUPT_MASK__WFIFO_RE_MASK); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); -} - - -/* - * UART Interrupt handler. - */ -static irqreturn_t tilegx_interrupt(int irq, void *dev_id) -{ - unsigned long flags; - UART_INTERRUPT_STATUS_t intr_stat; - struct tile_uart_port *tile_uart; - gxio_uart_context_t *context; - struct uart_port *port = dev_id; - irqreturn_t ret = IRQ_NONE; - - spin_lock_irqsave(&port->lock, flags); - - tile_uart = container_of(port, struct tile_uart_port, uart); - context = &tile_uart->context; - intr_stat.word = gxio_uart_read(context, UART_INTERRUPT_STATUS); - - if (intr_stat.rfifo_we) { - handle_receive(tile_uart); - ret = IRQ_HANDLED; - } - if (intr_stat.wfifo_re) { - handle_transmit(tile_uart); - ret = IRQ_HANDLED; - } - - spin_unlock_irqrestore(&port->lock, flags); - return ret; -} - - -/* - * Return TIOCSER_TEMT when transmitter FIFO is empty. - */ -static u_int tilegx_tx_empty(struct uart_port *port) -{ - int ret; - UART_FLAG_t flag; - struct tile_uart_port *tile_uart; - gxio_uart_context_t *context; - - tile_uart = container_of(port, struct tile_uart_port, uart); - if (!mutex_trylock(&tile_uart->mutex)) - return 0; - context = &tile_uart->context; - - flag.word = gxio_uart_read(context, UART_FLAG); - ret = (flag.wfifo_empty) ? TIOCSER_TEMT : 0; - mutex_unlock(&tile_uart->mutex); - - return ret; -} - - -/* - * Set state of the modem control output lines. - */ -static void tilegx_set_mctrl(struct uart_port *port, u_int mctrl) -{ - /* N/A */ -} - - -/* - * Get state of the modem control input lines. - */ -static u_int tilegx_get_mctrl(struct uart_port *port) -{ - return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; -} - - -/* - * Stop transmitting. - */ -static void tilegx_stop_tx(struct uart_port *port) -{ - /* N/A */ -} - - -/* - * Start transmitting. - */ -static void tilegx_start_tx(struct uart_port *port) -{ - unsigned char ch; - struct circ_buf *xmit; - struct tile_uart_port *tile_uart; - gxio_uart_context_t *context; - - tile_uart = container_of(port, struct tile_uart_port, uart); - if (!mutex_trylock(&tile_uart->mutex)) - return; - context = &tile_uart->context; - xmit = &port->state->xmit; - if (port->x_char) { - if (tilegx_putchar(context, port->x_char)) - return; - port->x_char = 0; - port->icount.tx++; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - mutex_unlock(&tile_uart->mutex); - return; - } - - while (!uart_circ_empty(xmit)) { - ch = xmit->buf[xmit->tail]; - if (tilegx_putchar(context, ch)) - break; - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - mutex_unlock(&tile_uart->mutex); -} - - -/* - * Stop receiving - port is in process of being closed. - */ -static void tilegx_stop_rx(struct uart_port *port) -{ - int err; - struct tile_uart_port *tile_uart; - gxio_uart_context_t *context; - int cpu; - - tile_uart = container_of(port, struct tile_uart_port, uart); - if (!mutex_trylock(&tile_uart->mutex)) - return; - - context = &tile_uart->context; - cpu = tile_uart->irq_cpu; - err = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), - KERNEL_PL, -1); - mutex_unlock(&tile_uart->mutex); -} - -/* - * Control the transmission of a break signal. - */ -static void tilegx_break_ctl(struct uart_port *port, int break_state) -{ - /* N/A */ -} - - -/* - * Perform initialization and enable port for reception. - */ -static int tilegx_startup(struct uart_port *port) -{ - struct tile_uart_port *tile_uart; - gxio_uart_context_t *context; - int ret = 0; - int cpu = raw_smp_processor_id(); /* pick an arbitrary cpu */ - - tile_uart = container_of(port, struct tile_uart_port, uart); - if (mutex_lock_interruptible(&tile_uart->mutex)) - return -EBUSY; - context = &tile_uart->context; - - /* Now open the hypervisor device if we haven't already. */ - if (context->fd < 0) { - UART_INTERRUPT_MASK_t intr_mask; - - /* Initialize UART device. */ - ret = gxio_uart_init(context, port->line); - if (ret) { - ret = -ENXIO; - goto err; - } - - /* Create our IRQs. */ - port->irq = irq_alloc_hwirq(-1); - if (!port->irq) - goto err_uart_dest; - tile_irq_activate(port->irq, TILE_IRQ_PERCPU); - - /* Register our IRQs. */ - ret = request_irq(port->irq, tilegx_interrupt, 0, - tilegx_uart_driver.driver_name, port); - if (ret) - goto err_dest_irq; - - /* Request that the hardware start sending us interrupts. */ - tile_uart->irq_cpu = cpu; - ret = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), - KERNEL_PL, port->irq); - if (ret) - goto err_free_irq; - - /* Enable UART Tx/Rx Interrupt. */ - intr_mask.word = gxio_uart_read(context, UART_INTERRUPT_MASK); - intr_mask.wfifo_re = 0; - intr_mask.rfifo_we = 0; - gxio_uart_write(context, UART_INTERRUPT_MASK, intr_mask.word); - - /* Reset the Tx/Rx interrupt in case it's set. */ - gxio_uart_write(context, UART_INTERRUPT_STATUS, - UART_INTERRUPT_MASK__WFIFO_RE_MASK | - UART_INTERRUPT_MASK__RFIFO_WE_MASK); - } - - mutex_unlock(&tile_uart->mutex); - return ret; - -err_free_irq: - free_irq(port->irq, port); -err_dest_irq: - irq_free_hwirq(port->irq); -err_uart_dest: - gxio_uart_destroy(context); - ret = -ENXIO; -err: - mutex_unlock(&tile_uart->mutex); - return ret; -} - - -/* - * Release kernel resources if it is the last close, disable the port, - * free IRQ and close the port. - */ -static void tilegx_shutdown(struct uart_port *port) -{ - int err; - UART_INTERRUPT_MASK_t intr_mask; - struct tile_uart_port *tile_uart; - gxio_uart_context_t *context; - int cpu; - - tile_uart = container_of(port, struct tile_uart_port, uart); - if (mutex_lock_interruptible(&tile_uart->mutex)) - return; - context = &tile_uart->context; - - /* Disable UART Tx/Rx Interrupt. */ - intr_mask.word = gxio_uart_read(context, UART_INTERRUPT_MASK); - intr_mask.wfifo_re = 1; - intr_mask.rfifo_we = 1; - gxio_uart_write(context, UART_INTERRUPT_MASK, intr_mask.word); - - /* Request that the hardware stop sending us interrupts. */ - cpu = tile_uart->irq_cpu; - err = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), - KERNEL_PL, -1); - - if (port->irq > 0) { - free_irq(port->irq, port); - irq_free_hwirq(port->irq); - port->irq = 0; - } - - gxio_uart_destroy(context); - - mutex_unlock(&tile_uart->mutex); -} - - -/* - * Flush the buffer. - */ -static void tilegx_flush_buffer(struct uart_port *port) -{ - /* N/A */ -} - - -/* - * Change the port parameters. - */ -static void tilegx_set_termios(struct uart_port *port, - struct ktermios *termios, struct ktermios *old) -{ - int err; - UART_DIVISOR_t divisor; - UART_TYPE_t type; - unsigned int baud; - struct tile_uart_port *tile_uart; - gxio_uart_context_t *context; - - tile_uart = container_of(port, struct tile_uart_port, uart); - if (!mutex_trylock(&tile_uart->mutex)) - return; - context = &tile_uart->context; - - /* Open the hypervisor device if we haven't already. */ - if (context->fd < 0) { - err = gxio_uart_init(context, port->line); - if (err) { - mutex_unlock(&tile_uart->mutex); - return; - } - } - - divisor.word = gxio_uart_read(context, UART_DIVISOR); - type.word = gxio_uart_read(context, UART_TYPE); - - /* Divisor. */ - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); - divisor.divisor = uart_get_divisor(port, baud); - - /* Byte size. */ - if ((termios->c_cflag & CSIZE) == CS7) - type.dbits = UART_TYPE__DBITS_VAL_SEVEN_DBITS; - else - type.dbits = UART_TYPE__DBITS_VAL_EIGHT_DBITS; - - /* Parity. */ - if (termios->c_cflag & PARENB) { - /* Mark or Space parity. */ - if (termios->c_cflag & CMSPAR) - if (termios->c_cflag & PARODD) - type.ptype = UART_TYPE__PTYPE_VAL_MARK; - else - type.ptype = UART_TYPE__PTYPE_VAL_SPACE; - else if (termios->c_cflag & PARODD) - type.ptype = UART_TYPE__PTYPE_VAL_ODD; - else - type.ptype = UART_TYPE__PTYPE_VAL_EVEN; - } else - type.ptype = UART_TYPE__PTYPE_VAL_NONE; - - /* Stop bits. */ - if (termios->c_cflag & CSTOPB) - type.sbits = UART_TYPE__SBITS_VAL_TWO_SBITS; - else - type.sbits = UART_TYPE__SBITS_VAL_ONE_SBITS; - - /* Set the uart paramters. */ - gxio_uart_write(context, UART_DIVISOR, divisor.word); - gxio_uart_write(context, UART_TYPE, type.word); - - mutex_unlock(&tile_uart->mutex); -} - - -/* - * Return string describing the specified port. - */ -static const char *tilegx_type(struct uart_port *port) -{ - return port->type == PORT_TILEGX ? DRIVER_NAME_STRING : NULL; -} - - -/* - * Release the resources being used by 'port'. - */ -static void tilegx_release_port(struct uart_port *port) -{ - /* Nothing to release. */ -} - - -/* - * Request the resources being used by 'port'. - */ -static int tilegx_request_port(struct uart_port *port) -{ - /* Always present. */ - return 0; -} - - -/* - * Configure/autoconfigure the port. - */ -static void tilegx_config_port(struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) - port->type = PORT_TILEGX; -} - - -/* - * Verify the new serial_struct (for TIOCSSERIAL). - */ -static int tilegx_verify_port(struct uart_port *port, - struct serial_struct *ser) -{ - if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_TILEGX)) - return -EINVAL; - - return 0; -} - -#ifdef CONFIG_CONSOLE_POLL - -/* - * Console polling routines for writing and reading from the uart while - * in an interrupt or debug context. - */ - -static int tilegx_poll_get_char(struct uart_port *port) -{ - UART_FIFO_COUNT_t count; - gxio_uart_context_t *context; - struct tile_uart_port *tile_uart; - - tile_uart = container_of(port, struct tile_uart_port, uart); - context = &tile_uart->context; - count.word = gxio_uart_read(context, UART_FIFO_COUNT); - if (count.rfifo_count == 0) - return NO_POLL_CHAR; - return (char)gxio_uart_read(context, UART_RECEIVE_DATA); -} - -static void tilegx_poll_put_char(struct uart_port *port, unsigned char c) -{ - gxio_uart_context_t *context; - struct tile_uart_port *tile_uart; - - tile_uart = container_of(port, struct tile_uart_port, uart); - context = &tile_uart->context; - gxio_uart_write(context, UART_TRANSMIT_DATA, (unsigned long)c); -} - -#endif /* CONFIG_CONSOLE_POLL */ - - -static const struct uart_ops tilegx_ops = { - .tx_empty = tilegx_tx_empty, - .set_mctrl = tilegx_set_mctrl, - .get_mctrl = tilegx_get_mctrl, - .stop_tx = tilegx_stop_tx, - .start_tx = tilegx_start_tx, - .stop_rx = tilegx_stop_rx, - .break_ctl = tilegx_break_ctl, - .startup = tilegx_startup, - .shutdown = tilegx_shutdown, - .flush_buffer = tilegx_flush_buffer, - .set_termios = tilegx_set_termios, - .type = tilegx_type, - .release_port = tilegx_release_port, - .request_port = tilegx_request_port, - .config_port = tilegx_config_port, - .verify_port = tilegx_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = tilegx_poll_get_char, - .poll_put_char = tilegx_poll_put_char, -#endif -}; - - -static void tilegx_init_ports(void) -{ - int i; - struct uart_port *port; - - for (i = 0; i < TILEGX_UART_NR; i++) { - port = &tile_uart_ports[i].uart; - port->ops = &tilegx_ops; - port->line = i; - port->type = PORT_TILEGX; - port->uartclk = TILEGX_UART_REF_CLK; - port->flags = UPF_BOOT_AUTOCONF; - - tile_uart_ports[i].context.fd = -1; - mutex_init(&tile_uart_ports[i].mutex); - } -} - - -static struct uart_driver tilegx_uart_driver = { - .owner = THIS_MODULE, - .driver_name = DRIVER_NAME_STRING, - .dev_name = TILEGX_UART_NAME, - .major = TILEGX_UART_MAJOR, - .minor = TILEGX_UART_MINOR, - .nr = TILEGX_UART_NR, -}; - - -static int __init tilegx_init(void) -{ - int i; - int ret; - struct tty_driver *tty_drv; - - ret = uart_register_driver(&tilegx_uart_driver); - if (ret) - return ret; - tty_drv = tilegx_uart_driver.tty_driver; - tty_drv->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; - tty_drv->init_termios.c_ispeed = 115200; - tty_drv->init_termios.c_ospeed = 115200; - - tilegx_init_ports(); - - for (i = 0; i < TILEGX_UART_NR; i++) { - struct uart_port *port = &tile_uart_ports[i].uart; - ret = uart_add_one_port(&tilegx_uart_driver, port); - } - - return 0; -} - - -static void __exit tilegx_exit(void) -{ - int i; - struct uart_port *port; - - for (i = 0; i < TILEGX_UART_NR; i++) { - port = &tile_uart_ports[i].uart; - uart_remove_one_port(&tilegx_uart_driver, port); - } - - uart_unregister_driver(&tilegx_uart_driver); -} - - -module_init(tilegx_init); -module_exit(tilegx_exit); - -MODULE_AUTHOR("Tilera Corporation"); -MODULE_DESCRIPTION("TILEGx serial port driver"); -MODULE_LICENSE("GPL"); |