// SPDX-License-Identifier: GPL-2.0+/* * Cadence UART driver (found in Xilinx Zynq) * * Copyright (c) 2011 - 2014 Xilinx, Inc. * * This driver has originally been pushed by Xilinx using a Zynq-branding. This * still shows in the naming of this file, the kconfig symbols and some symbols * in the code. */ #include <linux/platform_device.h>#include <linux/serial.h>#include <linux/console.h>#include <linux/serial_core.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/clk.h>#include <linux/irq.h>#include <linux/io.h>#include <linux/of.h>#include <linux/module.h>#include <linux/pm_runtime.h>#include <linux/gpio/consumer.h>#include <linux/delay.h>#include <linux/reset.h> #define CDNS_UART_TTY_NAME "ttyPS"#define CDNS_UART_NAME "xuartps"#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */#define CDNS_UART_MINOR 0 /* works best with devtmpfs */#define CDNS_UART_NR_PORTS 16#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */#define TX_TIMEOUT 500000 /* Rx Trigger level */static int rx_trigger_level = 56;module_param(rx_trigger_level, uint, 0444);MODULE_PARM_DESC(rx_trigger_level, "Rx trigger level, 1-63 bytes"); /* Rx Timeout */static int rx_timeout = 10;module_param(rx_timeout, uint, 0444);MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); /* Register offsets for the UART. */#define CDNS_UART_CR 0x00 /* Control Register */#define CDNS_UART_MR 0x04 /* Mode Register */#define CDNS_UART_IER 0x08 /* Interrupt Enable */#define CDNS_UART_IDR 0x0C /* Interrupt Disable */#define CDNS_UART_IMR 0x10 /* Interrupt Mask */#define CDNS_UART_ISR 0x14 /* Interrupt Status */#define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */#define CDNS_UART_RXTOUT 0x1C /* RX Timeout */#define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */#define CDNS_UART_MODEMCR 0x24 /* Modem Control */#define CDNS_UART_MODEMSR 0x28 /* Modem Status */#define CDNS_UART_SR 0x2C /* Channel Status */#define CDNS_UART_FIFO 0x30 /* FIFO */#define CDNS_UART_BAUDDIV 0x34 /* Baud Rate Divider */#define CDNS_UART_FLOWDEL 0x38 /* Flow Delay */#define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */#define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */#define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */#define CDNS_UART_RXBS 0x48 /* RX FIFO byte status register */ /* Control Register Bit Definitions */#define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */#define CDNS_UART_CR_STARTBRK 0x00000080 /* Set TX break */#define CDNS_UART_CR_TX_DIS 0x00000020 /* TX disabled. */#define CDNS_UART_CR_TX_EN 0x00000010 /* TX enabled */#define CDNS_UART_CR_RX_DIS 0x00000008 /* RX disabled. */#define CDNS_UART_CR_RX_EN 0x00000004 /* RX enabled */#define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */#define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */#define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */#define CDNS_UART_RXBS_PARITY 0x00000001 /* Parity error status */#define CDNS_UART_RXBS_FRAMING 0x00000002 /* Framing error status */#define CDNS_UART_RXBS_BRK 0x00000004 /* Overrun error status */ /* * Mode Register: * The mode register (MR) defines the mode of transfer as well as the data * format. If this register is modified during transmission or reception, * data validity cannot be guaranteed. */#define CDNS_UART_MR_CLKSEL 0x00000001 /* Pre-scalar selection */#define CDNS_UART_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */#define CDNS_UART_MR_CHMODE_NORM 0x00000000 /* Normal mode */#define CDNS_UART_MR_CHMODE_MASK 0x00000300 /* Mask for mode bits */ #define CDNS_UART_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */#define CDNS_UART_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */ #define CDNS_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */#define CDNS_UART_MR_PARITY_MARK 0x00000018 /* Mark parity mode */#define CDNS_UART_MR_PARITY_SPACE 0x00000010 /* Space parity mode */#define CDNS_UART_MR_PARITY_ODD 0x00000008 /* Odd parity mode */#define CDNS_UART_MR_PARITY_EVEN 0x00000000 /* Even parity mode */ #define CDNS_UART_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */#define CDNS_UART_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */#define CDNS_UART_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */ /* * Interrupt Registers: * Interrupt control logic uses the interrupt enable register (IER) and the * interrupt disable register (IDR) to set the value of the bits in the * interrupt mask register (IMR). The IMR determines whether to pass an * interrupt to the interrupt status register (ISR). * Writing a 1 to IER Enables an interrupt, writing a 1 to IDR disables an * interrupt. IMR and ISR are read only, and IER and IDR are write only. * Reading either IER or IDR returns 0x00. * All four registers have the same bit definitions. */#define CDNS_UART_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */#define CDNS_UART_IXR_PARITY 0x00000080 /* Parity error interrupt */#define CDNS_UART_IXR_FRAMING 0x00000040 /* Framing error interrupt */#define CDNS_UART_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */#define CDNS_UART_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */#define CDNS_UART_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */#define CDNS_UART_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */#define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */#define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */#define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */#define CDNS_UART_IXR_RXMASK 0x000021e7 /* Valid RX bit mask */ /* * Do not enable parity error interrupt for the following * reason: When parity error interrupt is enabled, each Rx * parity error always results in 2 events. The first one * being parity error interrupt and the second one with a * proper Rx interrupt with the incoming data. Disabling * parity error interrupt ensures better handling of parity * error events. With this change, for a parity error case, we * get a Rx interrupt with parity error set in ISR register * and we still handle parity errors in the desired way. */ #define CDNS_UART_RX_IRQS (CDNS_UART_IXR_FRAMING | \ CDNS_UART_IXR_OVERRUN | \ CDNS_UART_IXR_RXTRIG | \ CDNS_UART_IXR_TOUT) /* Goes in read_status_mask for break detection as the HW doesn't do it*/#define CDNS_UART_IXR_BRK 0x00002000 #define CDNS_UART_RXBS_SUPPORT BIT(1)/* * Modem Control register: * The read/write Modem Control register controls the interface with the modem * or data set, or a peripheral device emulating a modem. */#define CDNS_UART_MODEMCR_FCM 0x00000020 /* Automatic flow control mode */#define CDNS_UART_MODEMCR_RTS 0x00000002 /* Request to send output control */#define CDNS_UART_MODEMCR_DTR 0x00000001 /* Data Terminal Ready */ /* * Modem Status register: * The read/write Modem Status register reports the interface with the modem * or data set, or a peripheral device emulating a modem. */#define CDNS_UART_MODEMSR_DCD BIT(7) /* Data Carrier Detect */#define CDNS_UART_MODEMSR_RI BIT(6) /* Ting Indicator */#define CDNS_UART_MODEMSR_DSR BIT(5) /* Data Set Ready */#define CDNS_UART_MODEMSR_CTS BIT(4) /* Clear To Send */ /* * Channel Status Register: * The channel status register (CSR) is provided to enable the control logic * to monitor the status of bits in the channel interrupt status register, * even if these are masked out by the interrupt mask register. */#define CDNS_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */#define CDNS_UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */#define CDNS_UART_SR_TXFULL 0x00000010 /* TX FIFO full */#define CDNS_UART_SR_RXTRIG 0x00000001 /* Rx Trigger */#define CDNS_UART_SR_TACTIVE 0x00000800 /* TX state machine active */ /* baud dividers min/max values */#define CDNS_UART_BDIV_MIN 4#define CDNS_UART_BDIV_MAX 255#define CDNS_UART_CD_MAX 65535#define UART_AUTOSUSPEND_TIMEOUT 3000 /** * struct cdns_uart - device data * @port: Pointer to the UART port * @uartclk: Reference clock * @pclk: APB clock * @baud: Current baud rate * @clk_rate_change_nb: Notifier block for clock changes * @quirks: Flags for RXBS support. * @cts_override: Modem control state override * @gpiod_rts: Pointer to the gpio descriptor * @rs485_tx_started: RS485 tx state * @tx_timer: Timer for tx * @rstc: Pointer to the reset control */struct cdns_uart { struct uart_port *port; struct clk *uartclk; struct clk *pclk; unsigned int baud; struct notifier_block clk_rate_change_nb; u32 quirks; bool cts_override; struct gpio_desc *gpiod_rts; bool rs485_tx_started; struct hrtimer tx_timer; struct reset_control *rstc;};struct cdns_platform_data { u32 quirks;}; static struct serial_rs485 cdns_rs485_supported = { .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, .delay_rts_before_send = 1, .delay_rts_after_send = 1,}; #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ clk_rate_change_nb) /** * cdns_uart_handle_rx - Handle the received bytes along with Rx errors. * @dev_id: Id of the UART port * @isrstatus: The interrupt status register value as read * Return: None */static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus){ struct uart_port *port = (struct uart_port *)dev_id; struct cdns_uart *cdns_uart = port->private_data; unsigned int data; unsigned int rxbs_status = 0; unsigned int status_mask; unsigned int framerrprocessed = 0; char status = TTY_NORMAL; bool is_rxbs_support; is_rxbs_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT; while ((readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { if (is_rxbs_support) rxbs_status = readl(port->membase + CDNS_UART_RXBS); data = readl(port->membase + CDNS_UART_FIFO); port->icount.rx++; /* * There is no hardware break detection in Zynq, so we interpret * framing error with all-zeros data as a break sequence. * Most of the time, there's another non-zero byte at the * end of the sequence. */ if (!is_rxbs_support && (isrstatus & CDNS_UART_IXR_FRAMING)) { if (!data) { port->read_status_mask |= CDNS_UART_IXR_BRK; framerrprocessed = 1; continue; } } if (is_rxbs_support && (rxbs_status & CDNS_UART_RXBS_BRK)) { port->icount.brk++; status = TTY_BREAK; if (uart_handle_break(port)) continue; } isrstatus &= port->read_status_mask; isrstatus &= ~port->ignore_status_mask; status_mask = port->read_status_mask; status_mask &= ~port->ignore_status_mask; if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) { port->read_status_mask &= ~CDNS_UART_IXR_BRK; port->icount.brk++; if (uart_handle_break(port)) continue; } if (uart_prepare_sysrq_char(port, data)) continue; if (is_rxbs_support) { if ((rxbs_status & CDNS_UART_RXBS_PARITY) && (status_mask & CDNS_UART_IXR_PARITY)) { port->icount.parity++; status = TTY_PARITY; } if ((rxbs_status & CDNS_UART_RXBS_FRAMING) && (status_mask & CDNS_UART_IXR_PARITY)) { port->icount.frame++; status = TTY_FRAME; } } else { if (isrstatus & CDNS_UART_IXR_PARITY) { port->icount.parity++; status = TTY_PARITY; } if ((isrstatus & CDNS_UART_IXR_FRAMING) && !framerrprocessed) { port->icount.frame++; status = TTY_FRAME; } } if (isrstatus & CDNS_UART_IXR_OVERRUN) { port->icount.overrun++; tty_insert_flip_char(&port->state->port, 0, TTY_OVERRUN); } tty_insert_flip_char(&port->state->port, data, status); isrstatus = 0; } tty_flip_buffer_push(&port->state->port);} /** * cdns_rts_gpio_enable - Configure RTS/GPIO to high/low * @cdns_uart: Handle to the cdns_uart * @enable: Value to be set to RTS/GPIO */static void cdns_rts_gpio_enable(struct cdns_uart *cdns_uart, bool enable){ u32 val; if (cdns_uart->gpiod_rts) { gpiod_set_value(cdns_uart->gpiod_rts, enable); } else { val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR); if (enable) val |= CDNS_UART_MODEMCR_RTS; else val &= ~CDNS_UART_MODEMCR_RTS; writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR); }} /** * cdns_rs485_tx_setup - Tx setup specific to rs485 * @cdns_uart: Handle to the cdns_uart */static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart){ bool enable; enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_ON_SEND; cdns_rts_gpio_enable(cdns_uart, enable); cdns_uart->rs485_tx_started = true;} /** * cdns_rs485_rx_setup - Rx setup specific to rs485 * @cdns_uart: Handle to the cdns_uart */static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart){ bool enable; enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_AFTER_SEND; cdns_rts_gpio_enable(cdns_uart, enable); cdns_uart->rs485_tx_started = false;} /** * cdns_uart_tx_empty - Check whether TX is empty * @port: Handle to the uart port structure * * Return: TIOCSER_TEMT on success, 0 otherwise */static unsigned int cdns_uart_tx_empty(struct uart_port *port){ unsigned int status; status = readl(port->membase + CDNS_UART_SR); status &= (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE); return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0;} /** * cdns_rs485_rx_callback - Timer rx callback handler for rs485. * @t: Handle to the hrtimer structure */static enum hrtimer_restart cdns_rs485_rx_callback(struct hrtimer *t){ struct cdns_uart *cdns_uart = container_of(t, struct cdns_uart, tx_timer); /* * Default Rx should be setup, because Rx signaling path * need to enable to receive data. */ cdns_rs485_rx_setup(cdns_uart); return HRTIMER_NORESTART;} /** * cdns_calc_after_tx_delay - calculate delay required for after tx. * @cdns_uart: Handle to the cdns_uart */static u64 cdns_calc_after_tx_delay(struct cdns_uart *cdns_uart){ /* * Frame time + stop bit time + rs485.delay_rts_after_send */ return cdns_uart->port->frame_time + DIV_ROUND_UP(cdns_uart->port->frame_time, 7) + (u64)cdns_uart->port->rs485.delay_rts_after_send * NSEC_PER_MSEC;} /** * cdns_uart_handle_tx - Handle the bytes to be transmitted. * @dev_id: Id of the UART port * Return: None */static void cdns_uart_handle_tx(void *dev_id){ struct uart_port *port = (struct uart_port *)dev_id; struct cdns_uart *cdns_uart = port->private_data; struct tty_port *tport = &port->state->port; unsigned int numbytes; unsigned char ch; ktime_t rts_delay; if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { /* Disable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); /* Set RTS line after delay */ if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) { cdns_uart->tx_timer.function = &cdns_rs485_rx_callback; rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)); hrtimer_start(&cdns_uart->tx_timer, rts_delay, HRTIMER_MODE_REL); } return; } numbytes = port->fifosize; while (numbytes && !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) && uart_fifo_get(port, &ch)) { writel(ch, port->membase + CDNS_UART_FIFO); numbytes--; } if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); /* Enable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER);} /** * cdns_uart_isr - Interrupt handler * @irq: Irq number * @dev_id: Id of the port * * Return: IRQHANDLED */static irqreturn_t cdns_uart_isr(int irq, void *dev_id){ struct uart_port *port = (struct uart_port *)dev_id; unsigned int isrstatus; uart_port_lock(port); /* Read the interrupt status register to determine which * interrupt(s) is/are active and clear them. */ isrstatus = readl(port->membase + CDNS_UART_ISR); writel(isrstatus, port->membase + CDNS_UART_ISR); if (isrstatus & CDNS_UART_IXR_TXEMPTY) { cdns_uart_handle_tx(dev_id); isrstatus &= ~CDNS_UART_IXR_TXEMPTY; } isrstatus &= port->read_status_mask; isrstatus &= ~port->ignore_status_mask; /* * Skip RX processing if RX is disabled as RXEMPTY will never be set * as read bytes will not be removed from the FIFO. */ if (isrstatus & CDNS_UART_IXR_RXMASK && !(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_RX_DIS)) cdns_uart_handle_rx(dev_id, isrstatus); uart_unlock_and_check_sysrq(port); return IRQ_HANDLED;} /** * cdns_uart_calc_baud_divs - Calculate baud rate divisors * @clk: UART module input clockLines 1–500 of 1924. Load more
// SPDX-License-Identifier: GPL-2.0+ /* * Cadence UART driver (found in Xilinx Zynq) * * Copyright (c) 2011 - 2014 Xilinx, Inc. * * This driver has originally been pushed by Xilinx using a Zynq-branding. This * still shows in the naming of this file, the kconfig symbols and some symbols * in the code. */ #include <linux/platform_device.h> #include <linux/serial.h> #include <linux/console.h> #include <linux/serial_core.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/clk.h> #include <linux/irq.h> #include <linux/io.h> #include <linux/of.h> #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/gpio/consumer.h> #include <linux/delay.h> #include <linux/reset.h> #define CDNS_UART_TTY_NAME "ttyPS" #define CDNS_UART_NAME "xuartps" #define CDNS_UART_MAJOR 0 /* use dynamic node allocation */ #define CDNS_UART_MINOR 0 /* works best with devtmpfs */ #define CDNS_UART_NR_PORTS 16 #define CDNS_UART_FIFO_SIZE 64 /* FIFO size */ #define TX_TIMEOUT 500000 /* Rx Trigger level */ static int rx_trigger_level = 56; module_param(rx_trigger_level, uint, 0444); MODULE_PARM_DESC(rx_trigger_level, "Rx trigger level, 1-63 bytes"); /* Rx Timeout */ static int rx_timeout = 10; module_param(rx_timeout, uint, 0444); MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); /* Register offsets for the UART. */ #define CDNS_UART_CR 0x00 /* Control Register */ #define CDNS_UART_MR 0x04 /* Mode Register */ #define CDNS_UART_IER 0x08 /* Interrupt Enable */ #define CDNS_UART_IDR 0x0C /* Interrupt Disable */ #define CDNS_UART_IMR 0x10 /* Interrupt Mask */ #define CDNS_UART_ISR 0x14 /* Interrupt Status */ #define CDNS_UART_BAUDGEN 0x18 /* Baud Rate Generator */ #define CDNS_UART_RXTOUT 0x1C /* RX Timeout */ #define CDNS_UART_RXWM 0x20 /* RX FIFO Trigger Level */ #define CDNS_UART_MODEMCR 0x24 /* Modem Control */ #define CDNS_UART_MODEMSR 0x28 /* Modem Status */ #define CDNS_UART_SR 0x2C /* Channel Status */ #define CDNS_UART_FIFO 0x30 /* FIFO */ #define CDNS_UART_BAUDDIV 0x34 /* Baud Rate Divider */ #define CDNS_UART_FLOWDEL 0x38 /* Flow Delay */ #define CDNS_UART_IRRX_PWIDTH 0x3C /* IR Min Received Pulse Width */ #define CDNS_UART_IRTX_PWIDTH 0x40 /* IR Transmitted pulse Width */ #define CDNS_UART_TXWM 0x44 /* TX FIFO Trigger Level */ #define CDNS_UART_RXBS 0x48 /* RX FIFO byte status register */ /* Control Register Bit Definitions */ #define CDNS_UART_CR_STOPBRK 0x00000100 /* Stop TX break */ #define CDNS_UART_CR_STARTBRK 0x00000080 /* Set TX break */ #define CDNS_UART_CR_TX_DIS 0x00000020 /* TX disabled. */ #define CDNS_UART_CR_TX_EN 0x00000010 /* TX enabled */ #define CDNS_UART_CR_RX_DIS 0x00000008 /* RX disabled. */ #define CDNS_UART_CR_RX_EN 0x00000004 /* RX enabled */ #define CDNS_UART_CR_TXRST 0x00000002 /* TX logic reset */ #define CDNS_UART_CR_RXRST 0x00000001 /* RX logic reset */ #define CDNS_UART_CR_RST_TO 0x00000040 /* Restart Timeout Counter */ #define CDNS_UART_RXBS_PARITY 0x00000001 /* Parity error status */ #define CDNS_UART_RXBS_FRAMING 0x00000002 /* Framing error status */ #define CDNS_UART_RXBS_BRK 0x00000004 /* Overrun error status */ /* * Mode Register: * The mode register (MR) defines the mode of transfer as well as the data * format. If this register is modified during transmission or reception, * data validity cannot be guaranteed. */ #define CDNS_UART_MR_CLKSEL 0x00000001 /* Pre-scalar selection */ #define CDNS_UART_MR_CHMODE_L_LOOP 0x00000200 /* Local loop back mode */ #define CDNS_UART_MR_CHMODE_NORM 0x00000000 /* Normal mode */ #define CDNS_UART_MR_CHMODE_MASK 0x00000300 /* Mask for mode bits */ #define CDNS_UART_MR_STOPMODE_2_BIT 0x00000080 /* 2 stop bits */ #define CDNS_UART_MR_STOPMODE_1_BIT 0x00000000 /* 1 stop bit */ #define CDNS_UART_MR_PARITY_NONE 0x00000020 /* No parity mode */ #define CDNS_UART_MR_PARITY_MARK 0x00000018 /* Mark parity mode */ #define CDNS_UART_MR_PARITY_SPACE 0x00000010 /* Space parity mode */ #define CDNS_UART_MR_PARITY_ODD 0x00000008 /* Odd parity mode */ #define CDNS_UART_MR_PARITY_EVEN 0x00000000 /* Even parity mode */ #define CDNS_UART_MR_CHARLEN_6_BIT 0x00000006 /* 6 bits data */ #define CDNS_UART_MR_CHARLEN_7_BIT 0x00000004 /* 7 bits data */ #define CDNS_UART_MR_CHARLEN_8_BIT 0x00000000 /* 8 bits data */ /* * Interrupt Registers: * Interrupt control logic uses the interrupt enable register (IER) and the * interrupt disable register (IDR) to set the value of the bits in the * interrupt mask register (IMR). The IMR determines whether to pass an * interrupt to the interrupt status register (ISR). * Writing a 1 to IER Enables an interrupt, writing a 1 to IDR disables an * interrupt. IMR and ISR are read only, and IER and IDR are write only. * Reading either IER or IDR returns 0x00. * All four registers have the same bit definitions. */ #define CDNS_UART_IXR_TOUT 0x00000100 /* RX Timeout error interrupt */ #define CDNS_UART_IXR_PARITY 0x00000080 /* Parity error interrupt */ #define CDNS_UART_IXR_FRAMING 0x00000040 /* Framing error interrupt */ #define CDNS_UART_IXR_OVERRUN 0x00000020 /* Overrun error interrupt */ #define CDNS_UART_IXR_TXFULL 0x00000010 /* TX FIFO Full interrupt */ #define CDNS_UART_IXR_TXEMPTY 0x00000008 /* TX FIFO empty interrupt */ #define CDNS_UART_ISR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt */ #define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */ #define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */ #define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ #define CDNS_UART_IXR_RXMASK 0x000021e7 /* Valid RX bit mask */ /* * Do not enable parity error interrupt for the following * reason: When parity error interrupt is enabled, each Rx * parity error always results in 2 events. The first one * being parity error interrupt and the second one with a * proper Rx interrupt with the incoming data. Disabling * parity error interrupt ensures better handling of parity * error events. With this change, for a parity error case, we * get a Rx interrupt with parity error set in ISR register * and we still handle parity errors in the desired way. */ #define CDNS_UART_RX_IRQS (CDNS_UART_IXR_FRAMING | \ CDNS_UART_IXR_OVERRUN | \ CDNS_UART_IXR_RXTRIG | \ CDNS_UART_IXR_TOUT) /* Goes in read_status_mask for break detection as the HW doesn't do it*/ #define CDNS_UART_IXR_BRK 0x00002000 #define CDNS_UART_RXBS_SUPPORT BIT(1) /* * Modem Control register: * The read/write Modem Control register controls the interface with the modem * or data set, or a peripheral device emulating a modem. */ #define CDNS_UART_MODEMCR_FCM 0x00000020 /* Automatic flow control mode */ #define CDNS_UART_MODEMCR_RTS 0x00000002 /* Request to send output control */ #define CDNS_UART_MODEMCR_DTR 0x00000001 /* Data Terminal Ready */ /* * Modem Status register: * The read/write Modem Status register reports the interface with the modem * or data set, or a peripheral device emulating a modem. */ #define CDNS_UART_MODEMSR_DCD BIT(7) /* Data Carrier Detect */ #define CDNS_UART_MODEMSR_RI BIT(6) /* Ting Indicator */ #define CDNS_UART_MODEMSR_DSR BIT(5) /* Data Set Ready */ #define CDNS_UART_MODEMSR_CTS BIT(4) /* Clear To Send */ /* * Channel Status Register: * The channel status register (CSR) is provided to enable the control logic * to monitor the status of bits in the channel interrupt status register, * even if these are masked out by the interrupt mask register. */ #define CDNS_UART_SR_RXEMPTY 0x00000002 /* RX FIFO empty */ #define CDNS_UART_SR_TXEMPTY 0x00000008 /* TX FIFO empty */ #define CDNS_UART_SR_TXFULL 0x00000010 /* TX FIFO full */ #define CDNS_UART_SR_RXTRIG 0x00000001 /* Rx Trigger */ #define CDNS_UART_SR_TACTIVE 0x00000800 /* TX state machine active */ /* baud dividers min/max values */ #define CDNS_UART_BDIV_MIN 4 #define CDNS_UART_BDIV_MAX 255 #define CDNS_UART_CD_MAX 65535 #define UART_AUTOSUSPEND_TIMEOUT 3000 /** * struct cdns_uart - device data * @port: Pointer to the UART port * @uartclk: Reference clock * @pclk: APB clock * @baud: Current baud rate * @clk_rate_change_nb: Notifier block for clock changes * @quirks: Flags for RXBS support. * @cts_override: Modem control state override * @gpiod_rts: Pointer to the gpio descriptor * @rs485_tx_started: RS485 tx state * @tx_timer: Timer for tx * @rstc: Pointer to the reset control */ struct cdns_uart { struct uart_port *port; struct clk *uartclk; struct clk *pclk; unsigned int baud; struct notifier_block clk_rate_change_nb; u32 quirks; bool cts_override; struct gpio_desc *gpiod_rts; bool rs485_tx_started; struct hrtimer tx_timer; struct reset_control *rstc; }; struct cdns_platform_data { u32 quirks; }; static struct serial_rs485 cdns_rs485_supported = { .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND, .delay_rts_before_send = 1, .delay_rts_after_send = 1, }; #define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \ clk_rate_change_nb) /** * cdns_uart_handle_rx - Handle the received bytes along with Rx errors. * @dev_id: Id of the UART port * @isrstatus: The interrupt status register value as read * Return: None */ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus) { struct uart_port *port = (struct uart_port *)dev_id; struct cdns_uart *cdns_uart = port->private_data; unsigned int data; unsigned int rxbs_status = 0; unsigned int status_mask; unsigned int framerrprocessed = 0; char status = TTY_NORMAL; bool is_rxbs_support; is_rxbs_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT; while ((readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) { if (is_rxbs_support) rxbs_status = readl(port->membase + CDNS_UART_RXBS); data = readl(port->membase + CDNS_UART_FIFO); port->icount.rx++; /* * There is no hardware break detection in Zynq, so we interpret * framing error with all-zeros data as a break sequence. * Most of the time, there's another non-zero byte at the * end of the sequence. */ if (!is_rxbs_support && (isrstatus & CDNS_UART_IXR_FRAMING)) { if (!data) { port->read_status_mask |= CDNS_UART_IXR_BRK; framerrprocessed = 1; continue; } } if (is_rxbs_support && (rxbs_status & CDNS_UART_RXBS_BRK)) { port->icount.brk++; status = TTY_BREAK; if (uart_handle_break(port)) continue; } isrstatus &= port->read_status_mask; isrstatus &= ~port->ignore_status_mask; status_mask = port->read_status_mask; status_mask &= ~port->ignore_status_mask; if (data && (port->read_status_mask & CDNS_UART_IXR_BRK)) { port->read_status_mask &= ~CDNS_UART_IXR_BRK; port->icount.brk++; if (uart_handle_break(port)) continue; } if (uart_prepare_sysrq_char(port, data)) continue; if (is_rxbs_support) { if ((rxbs_status & CDNS_UART_RXBS_PARITY) && (status_mask & CDNS_UART_IXR_PARITY)) { port->icount.parity++; status = TTY_PARITY; } if ((rxbs_status & CDNS_UART_RXBS_FRAMING) && (status_mask & CDNS_UART_IXR_PARITY)) { port->icount.frame++; status = TTY_FRAME; } } else { if (isrstatus & CDNS_UART_IXR_PARITY) { port->icount.parity++; status = TTY_PARITY; } if ((isrstatus & CDNS_UART_IXR_FRAMING) && !framerrprocessed) { port->icount.frame++; status = TTY_FRAME; } } if (isrstatus & CDNS_UART_IXR_OVERRUN) { port->icount.overrun++; tty_insert_flip_char(&port->state->port, 0, TTY_OVERRUN); } tty_insert_flip_char(&port->state->port, data, status); isrstatus = 0; } tty_flip_buffer_push(&port->state->port); } /** * cdns_rts_gpio_enable - Configure RTS/GPIO to high/low * @cdns_uart: Handle to the cdns_uart * @enable: Value to be set to RTS/GPIO */ static void cdns_rts_gpio_enable(struct cdns_uart *cdns_uart, bool enable) { u32 val; if (cdns_uart->gpiod_rts) { gpiod_set_value(cdns_uart->gpiod_rts, enable); } else { val = readl(cdns_uart->port->membase + CDNS_UART_MODEMCR); if (enable) val |= CDNS_UART_MODEMCR_RTS; else val &= ~CDNS_UART_MODEMCR_RTS; writel(val, cdns_uart->port->membase + CDNS_UART_MODEMCR); } } /** * cdns_rs485_tx_setup - Tx setup specific to rs485 * @cdns_uart: Handle to the cdns_uart */ static void cdns_rs485_tx_setup(struct cdns_uart *cdns_uart) { bool enable; enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_ON_SEND; cdns_rts_gpio_enable(cdns_uart, enable); cdns_uart->rs485_tx_started = true; } /** * cdns_rs485_rx_setup - Rx setup specific to rs485 * @cdns_uart: Handle to the cdns_uart */ static void cdns_rs485_rx_setup(struct cdns_uart *cdns_uart) { bool enable; enable = cdns_uart->port->rs485.flags & SER_RS485_RTS_AFTER_SEND; cdns_rts_gpio_enable(cdns_uart, enable); cdns_uart->rs485_tx_started = false; } /** * cdns_uart_tx_empty - Check whether TX is empty * @port: Handle to the uart port structure * * Return: TIOCSER_TEMT on success, 0 otherwise */ static unsigned int cdns_uart_tx_empty(struct uart_port *port) { unsigned int status; status = readl(port->membase + CDNS_UART_SR); status &= (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE); return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0; } /** * cdns_rs485_rx_callback - Timer rx callback handler for rs485. * @t: Handle to the hrtimer structure */ static enum hrtimer_restart cdns_rs485_rx_callback(struct hrtimer *t) { struct cdns_uart *cdns_uart = container_of(t, struct cdns_uart, tx_timer); /* * Default Rx should be setup, because Rx signaling path * need to enable to receive data. */ cdns_rs485_rx_setup(cdns_uart); return HRTIMER_NORESTART; } /** * cdns_calc_after_tx_delay - calculate delay required for after tx. * @cdns_uart: Handle to the cdns_uart */ static u64 cdns_calc_after_tx_delay(struct cdns_uart *cdns_uart) { /* * Frame time + stop bit time + rs485.delay_rts_after_send */ return cdns_uart->port->frame_time + DIV_ROUND_UP(cdns_uart->port->frame_time, 7) + (u64)cdns_uart->port->rs485.delay_rts_after_send * NSEC_PER_MSEC; } /** * cdns_uart_handle_tx - Handle the bytes to be transmitted. * @dev_id: Id of the UART port * Return: None */ static void cdns_uart_handle_tx(void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; struct cdns_uart *cdns_uart = port->private_data; struct tty_port *tport = &port->state->port; unsigned int numbytes; unsigned char ch; ktime_t rts_delay; if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { /* Disable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); /* Set RTS line after delay */ if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) { cdns_uart->tx_timer.function = &cdns_rs485_rx_callback; rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)); hrtimer_start(&cdns_uart->tx_timer, rts_delay, HRTIMER_MODE_REL); } return; } numbytes = port->fifosize; while (numbytes && !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) && uart_fifo_get(port, &ch)) { writel(ch, port->membase + CDNS_UART_FIFO); numbytes--; } if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(port); /* Enable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER); } /** * cdns_uart_isr - Interrupt handler * @irq: Irq number * @dev_id: Id of the port * * Return: IRQHANDLED */ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) { struct uart_port *port = (struct uart_port *)dev_id; unsigned int isrstatus; uart_port_lock(port); /* Read the interrupt status register to determine which * interrupt(s) is/are active and clear them. */ isrstatus = readl(port->membase + CDNS_UART_ISR); writel(isrstatus, port->membase + CDNS_UART_ISR); if (isrstatus & CDNS_UART_IXR_TXEMPTY) { cdns_uart_handle_tx(dev_id); isrstatus &= ~CDNS_UART_IXR_TXEMPTY; } isrstatus &= port->read_status_mask; isrstatus &= ~port->ignore_status_mask; /* * Skip RX processing if RX is disabled as RXEMPTY will never be set * as read bytes will not be removed from the FIFO. */ if (isrstatus & CDNS_UART_IXR_RXMASK && !(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_RX_DIS)) cdns_uart_handle_rx(dev_id, isrstatus); uart_unlock_and_check_sysrq(port); return IRQ_HANDLED; } /** * cdns_uart_calc_baud_divs - Calculate baud rate divisors * @clk: UART module input clock