1c4f52879SKarthikeyan Ramasubramanian // SPDX-License-Identifier: GPL-2.0 2c4f52879SKarthikeyan Ramasubramanian // Copyright (c) 2017-2018, The Linux foundation. All rights reserved. 3c4f52879SKarthikeyan Ramasubramanian 4c4f52879SKarthikeyan Ramasubramanian #include <linux/clk.h> 5c4f52879SKarthikeyan Ramasubramanian #include <linux/console.h> 6c4f52879SKarthikeyan Ramasubramanian #include <linux/io.h> 7c4f52879SKarthikeyan Ramasubramanian #include <linux/iopoll.h> 8c4f52879SKarthikeyan Ramasubramanian #include <linux/module.h> 9c4f52879SKarthikeyan Ramasubramanian #include <linux/of.h> 10c4f52879SKarthikeyan Ramasubramanian #include <linux/of_device.h> 11c4f52879SKarthikeyan Ramasubramanian #include <linux/platform_device.h> 12c4f52879SKarthikeyan Ramasubramanian #include <linux/qcom-geni-se.h> 13c4f52879SKarthikeyan Ramasubramanian #include <linux/serial.h> 14c4f52879SKarthikeyan Ramasubramanian #include <linux/serial_core.h> 15c4f52879SKarthikeyan Ramasubramanian #include <linux/slab.h> 16c4f52879SKarthikeyan Ramasubramanian #include <linux/tty.h> 17c4f52879SKarthikeyan Ramasubramanian #include <linux/tty_flip.h> 18c4f52879SKarthikeyan Ramasubramanian 19c4f52879SKarthikeyan Ramasubramanian /* UART specific GENI registers */ 20c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_TRANS_CFG 0x25c 21c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_WORD_LEN 0x268 22c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_STOP_BIT_LEN 0x26c 23c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_TRANS_LEN 0x270 24c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_TRANS_CFG 0x280 25c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_WORD_LEN 0x28c 26c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_STALE_CNT 0x294 27c4f52879SKarthikeyan Ramasubramanian #define SE_UART_TX_PARITY_CFG 0x2a4 28c4f52879SKarthikeyan Ramasubramanian #define SE_UART_RX_PARITY_CFG 0x2a8 29c4f52879SKarthikeyan Ramasubramanian 30c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TRANS_CFG */ 31c4f52879SKarthikeyan Ramasubramanian #define UART_TX_PAR_EN BIT(0) 32c4f52879SKarthikeyan Ramasubramanian #define UART_CTS_MASK BIT(1) 33c4f52879SKarthikeyan Ramasubramanian 34c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_WORD_LEN */ 35c4f52879SKarthikeyan Ramasubramanian #define TX_WORD_LEN_MSK GENMASK(9, 0) 36c4f52879SKarthikeyan Ramasubramanian 37c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_STOP_BIT_LEN */ 38c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_MSK GENMASK(23, 0) 39c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_1 0 40c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_1_5 1 41c4f52879SKarthikeyan Ramasubramanian #define TX_STOP_BIT_LEN_2 2 42c4f52879SKarthikeyan Ramasubramanian 43c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_TRANS_LEN */ 44c4f52879SKarthikeyan Ramasubramanian #define TX_TRANS_LEN_MSK GENMASK(23, 0) 45c4f52879SKarthikeyan Ramasubramanian 46c4f52879SKarthikeyan Ramasubramanian /* SE_UART_RX_TRANS_CFG */ 47c4f52879SKarthikeyan Ramasubramanian #define UART_RX_INS_STATUS_BIT BIT(2) 48c4f52879SKarthikeyan Ramasubramanian #define UART_RX_PAR_EN BIT(3) 49c4f52879SKarthikeyan Ramasubramanian 50c4f52879SKarthikeyan Ramasubramanian /* SE_UART_RX_WORD_LEN */ 51c4f52879SKarthikeyan Ramasubramanian #define RX_WORD_LEN_MASK GENMASK(9, 0) 52c4f52879SKarthikeyan Ramasubramanian 53c4f52879SKarthikeyan Ramasubramanian /* SE_UART_RX_STALE_CNT */ 54c4f52879SKarthikeyan Ramasubramanian #define RX_STALE_CNT GENMASK(23, 0) 55c4f52879SKarthikeyan Ramasubramanian 56c4f52879SKarthikeyan Ramasubramanian /* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */ 57c4f52879SKarthikeyan Ramasubramanian #define PAR_CALC_EN BIT(0) 58c4f52879SKarthikeyan Ramasubramanian #define PAR_MODE_MSK GENMASK(2, 1) 59c4f52879SKarthikeyan Ramasubramanian #define PAR_MODE_SHFT 1 60c4f52879SKarthikeyan Ramasubramanian #define PAR_EVEN 0x00 61c4f52879SKarthikeyan Ramasubramanian #define PAR_ODD 0x01 62c4f52879SKarthikeyan Ramasubramanian #define PAR_SPACE 0x10 63c4f52879SKarthikeyan Ramasubramanian #define PAR_MARK 0x11 64c4f52879SKarthikeyan Ramasubramanian 65c4f52879SKarthikeyan Ramasubramanian /* UART M_CMD OP codes */ 66c4f52879SKarthikeyan Ramasubramanian #define UART_START_TX 0x1 67c4f52879SKarthikeyan Ramasubramanian #define UART_START_BREAK 0x4 68c4f52879SKarthikeyan Ramasubramanian #define UART_STOP_BREAK 0x5 69c4f52879SKarthikeyan Ramasubramanian /* UART S_CMD OP codes */ 70c4f52879SKarthikeyan Ramasubramanian #define UART_START_READ 0x1 71c4f52879SKarthikeyan Ramasubramanian #define UART_PARAM 0x1 72c4f52879SKarthikeyan Ramasubramanian 73c4f52879SKarthikeyan Ramasubramanian #define UART_OVERSAMPLING 32 74c4f52879SKarthikeyan Ramasubramanian #define STALE_TIMEOUT 16 75c4f52879SKarthikeyan Ramasubramanian #define DEFAULT_BITS_PER_CHAR 10 76c4f52879SKarthikeyan Ramasubramanian #define GENI_UART_CONS_PORTS 1 77c4f52879SKarthikeyan Ramasubramanian #define DEF_FIFO_DEPTH_WORDS 16 78c4f52879SKarthikeyan Ramasubramanian #define DEF_TX_WM 2 79c4f52879SKarthikeyan Ramasubramanian #define DEF_FIFO_WIDTH_BITS 32 80c4f52879SKarthikeyan Ramasubramanian #define UART_CONSOLE_RX_WM 2 81c4f52879SKarthikeyan Ramasubramanian 82c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_CONSOLE_POLL 83c4f52879SKarthikeyan Ramasubramanian #define RX_BYTES_PW 1 84c4f52879SKarthikeyan Ramasubramanian #else 85c4f52879SKarthikeyan Ramasubramanian #define RX_BYTES_PW 4 86c4f52879SKarthikeyan Ramasubramanian #endif 87c4f52879SKarthikeyan Ramasubramanian 88c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port { 89c4f52879SKarthikeyan Ramasubramanian struct uart_port uport; 90c4f52879SKarthikeyan Ramasubramanian struct geni_se se; 91c4f52879SKarthikeyan Ramasubramanian char name[20]; 92c4f52879SKarthikeyan Ramasubramanian u32 tx_fifo_depth; 93c4f52879SKarthikeyan Ramasubramanian u32 tx_fifo_width; 94c4f52879SKarthikeyan Ramasubramanian u32 rx_fifo_depth; 95c4f52879SKarthikeyan Ramasubramanian u32 tx_wm; 96c4f52879SKarthikeyan Ramasubramanian u32 rx_wm; 97c4f52879SKarthikeyan Ramasubramanian u32 rx_rfr; 98c4f52879SKarthikeyan Ramasubramanian enum geni_se_xfer_mode xfer_mode; 99c4f52879SKarthikeyan Ramasubramanian bool setup; 100c4f52879SKarthikeyan Ramasubramanian int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop); 101c4f52879SKarthikeyan Ramasubramanian unsigned int xmit_size; 102c4f52879SKarthikeyan Ramasubramanian unsigned int baud; 103c4f52879SKarthikeyan Ramasubramanian unsigned int tx_bytes_pw; 104c4f52879SKarthikeyan Ramasubramanian unsigned int rx_bytes_pw; 105c4f52879SKarthikeyan Ramasubramanian bool brk; 106c4f52879SKarthikeyan Ramasubramanian }; 107c4f52879SKarthikeyan Ramasubramanian 108f7371750SKarthikeyan Ramasubramanian static const struct uart_ops qcom_geni_console_pops; 109c4f52879SKarthikeyan Ramasubramanian static struct uart_driver qcom_geni_console_driver; 110c4f52879SKarthikeyan Ramasubramanian static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop); 111c4f52879SKarthikeyan Ramasubramanian static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port); 112c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_stop_rx(struct uart_port *uport); 113c4f52879SKarthikeyan Ramasubramanian 114c4f52879SKarthikeyan Ramasubramanian static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200, 115c4f52879SKarthikeyan Ramasubramanian 32000000, 48000000, 64000000, 80000000, 116c4f52879SKarthikeyan Ramasubramanian 96000000, 100000000}; 117c4f52879SKarthikeyan Ramasubramanian 118c4f52879SKarthikeyan Ramasubramanian #define to_dev_port(ptr, member) \ 119c4f52879SKarthikeyan Ramasubramanian container_of(ptr, struct qcom_geni_serial_port, member) 120c4f52879SKarthikeyan Ramasubramanian 121f7371750SKarthikeyan Ramasubramanian static struct qcom_geni_serial_port qcom_geni_console_port = { 122f7371750SKarthikeyan Ramasubramanian .uport = { 123f7371750SKarthikeyan Ramasubramanian .iotype = UPIO_MEM, 124f7371750SKarthikeyan Ramasubramanian .ops = &qcom_geni_console_pops, 125f7371750SKarthikeyan Ramasubramanian .flags = UPF_BOOT_AUTOCONF, 126f7371750SKarthikeyan Ramasubramanian .line = 0, 127f7371750SKarthikeyan Ramasubramanian }, 128f7371750SKarthikeyan Ramasubramanian }; 129c4f52879SKarthikeyan Ramasubramanian 130c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_request_port(struct uart_port *uport) 131c4f52879SKarthikeyan Ramasubramanian { 132c4f52879SKarthikeyan Ramasubramanian struct platform_device *pdev = to_platform_device(uport->dev); 133c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 134c4f52879SKarthikeyan Ramasubramanian struct resource *res; 135c4f52879SKarthikeyan Ramasubramanian 136c4f52879SKarthikeyan Ramasubramanian res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 137c4f52879SKarthikeyan Ramasubramanian uport->membase = devm_ioremap_resource(&pdev->dev, res); 138c4f52879SKarthikeyan Ramasubramanian if (IS_ERR(uport->membase)) 139c4f52879SKarthikeyan Ramasubramanian return PTR_ERR(uport->membase); 140c4f52879SKarthikeyan Ramasubramanian port->se.base = uport->membase; 141c4f52879SKarthikeyan Ramasubramanian return 0; 142c4f52879SKarthikeyan Ramasubramanian } 143c4f52879SKarthikeyan Ramasubramanian 144c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_config_port(struct uart_port *uport, int cfg_flags) 145c4f52879SKarthikeyan Ramasubramanian { 146c4f52879SKarthikeyan Ramasubramanian if (cfg_flags & UART_CONFIG_TYPE) { 147c4f52879SKarthikeyan Ramasubramanian uport->type = PORT_MSM; 148c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_request_port(uport); 149c4f52879SKarthikeyan Ramasubramanian } 150c4f52879SKarthikeyan Ramasubramanian } 151c4f52879SKarthikeyan Ramasubramanian 152c4f52879SKarthikeyan Ramasubramanian static unsigned int qcom_geni_cons_get_mctrl(struct uart_port *uport) 153c4f52879SKarthikeyan Ramasubramanian { 154c4f52879SKarthikeyan Ramasubramanian return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; 155c4f52879SKarthikeyan Ramasubramanian } 156c4f52879SKarthikeyan Ramasubramanian 157c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_cons_set_mctrl(struct uart_port *uport, 158c4f52879SKarthikeyan Ramasubramanian unsigned int mctrl) 159c4f52879SKarthikeyan Ramasubramanian { 160c4f52879SKarthikeyan Ramasubramanian } 161c4f52879SKarthikeyan Ramasubramanian 162c4f52879SKarthikeyan Ramasubramanian static const char *qcom_geni_serial_get_type(struct uart_port *uport) 163c4f52879SKarthikeyan Ramasubramanian { 164c4f52879SKarthikeyan Ramasubramanian return "MSM"; 165c4f52879SKarthikeyan Ramasubramanian } 166c4f52879SKarthikeyan Ramasubramanian 167c4f52879SKarthikeyan Ramasubramanian static struct qcom_geni_serial_port *get_port_from_line(int line) 168c4f52879SKarthikeyan Ramasubramanian { 169c4f52879SKarthikeyan Ramasubramanian if (line < 0 || line >= GENI_UART_CONS_PORTS) 170c4f52879SKarthikeyan Ramasubramanian return ERR_PTR(-ENXIO); 171c4f52879SKarthikeyan Ramasubramanian return &qcom_geni_console_port; 172c4f52879SKarthikeyan Ramasubramanian } 173c4f52879SKarthikeyan Ramasubramanian 174c4f52879SKarthikeyan Ramasubramanian static bool qcom_geni_serial_poll_bit(struct uart_port *uport, 175c4f52879SKarthikeyan Ramasubramanian int offset, int field, bool set) 176c4f52879SKarthikeyan Ramasubramanian { 177c4f52879SKarthikeyan Ramasubramanian u32 reg; 178c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port; 179c4f52879SKarthikeyan Ramasubramanian unsigned int baud; 180c4f52879SKarthikeyan Ramasubramanian unsigned int fifo_bits; 181c4f52879SKarthikeyan Ramasubramanian unsigned long timeout_us = 20000; 182c4f52879SKarthikeyan Ramasubramanian 183c4f52879SKarthikeyan Ramasubramanian /* Ensure polling is not re-ordered before the prior writes/reads */ 184c4f52879SKarthikeyan Ramasubramanian mb(); 185c4f52879SKarthikeyan Ramasubramanian 186c4f52879SKarthikeyan Ramasubramanian if (uport->private_data) { 187c4f52879SKarthikeyan Ramasubramanian port = to_dev_port(uport, uport); 188c4f52879SKarthikeyan Ramasubramanian baud = port->baud; 189c4f52879SKarthikeyan Ramasubramanian if (!baud) 190c4f52879SKarthikeyan Ramasubramanian baud = 115200; 191c4f52879SKarthikeyan Ramasubramanian fifo_bits = port->tx_fifo_depth * port->tx_fifo_width; 192c4f52879SKarthikeyan Ramasubramanian /* 193c4f52879SKarthikeyan Ramasubramanian * Total polling iterations based on FIFO worth of bytes to be 194c4f52879SKarthikeyan Ramasubramanian * sent at current baud. Add a little fluff to the wait. 195c4f52879SKarthikeyan Ramasubramanian */ 196c4f52879SKarthikeyan Ramasubramanian timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500; 197c4f52879SKarthikeyan Ramasubramanian } 198c4f52879SKarthikeyan Ramasubramanian 199c4f52879SKarthikeyan Ramasubramanian return !readl_poll_timeout_atomic(uport->membase + offset, reg, 200c4f52879SKarthikeyan Ramasubramanian (bool)(reg & field) == set, 10, timeout_us); 201c4f52879SKarthikeyan Ramasubramanian } 202c4f52879SKarthikeyan Ramasubramanian 203c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size) 204c4f52879SKarthikeyan Ramasubramanian { 205c4f52879SKarthikeyan Ramasubramanian u32 m_cmd; 206c4f52879SKarthikeyan Ramasubramanian 207c4f52879SKarthikeyan Ramasubramanian writel_relaxed(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN); 208c4f52879SKarthikeyan Ramasubramanian m_cmd = UART_START_TX << M_OPCODE_SHFT; 209c4f52879SKarthikeyan Ramasubramanian writel(m_cmd, uport->membase + SE_GENI_M_CMD0); 210c4f52879SKarthikeyan Ramasubramanian } 211c4f52879SKarthikeyan Ramasubramanian 212c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_poll_tx_done(struct uart_port *uport) 213c4f52879SKarthikeyan Ramasubramanian { 214c4f52879SKarthikeyan Ramasubramanian int done; 215c4f52879SKarthikeyan Ramasubramanian u32 irq_clear = M_CMD_DONE_EN; 216c4f52879SKarthikeyan Ramasubramanian 217c4f52879SKarthikeyan Ramasubramanian done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, 218c4f52879SKarthikeyan Ramasubramanian M_CMD_DONE_EN, true); 219c4f52879SKarthikeyan Ramasubramanian if (!done) { 220c4f52879SKarthikeyan Ramasubramanian writel_relaxed(M_GENI_CMD_ABORT, uport->membase + 221c4f52879SKarthikeyan Ramasubramanian SE_GENI_M_CMD_CTRL_REG); 222c4f52879SKarthikeyan Ramasubramanian irq_clear |= M_CMD_ABORT_EN; 223c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, 224c4f52879SKarthikeyan Ramasubramanian M_CMD_ABORT_EN, true); 225c4f52879SKarthikeyan Ramasubramanian } 226c4f52879SKarthikeyan Ramasubramanian writel_relaxed(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR); 227c4f52879SKarthikeyan Ramasubramanian } 228c4f52879SKarthikeyan Ramasubramanian 229c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_abort_rx(struct uart_port *uport) 230c4f52879SKarthikeyan Ramasubramanian { 231c4f52879SKarthikeyan Ramasubramanian u32 irq_clear = S_CMD_DONE_EN | S_CMD_ABORT_EN; 232c4f52879SKarthikeyan Ramasubramanian 233c4f52879SKarthikeyan Ramasubramanian writel(S_GENI_CMD_ABORT, uport->membase + SE_GENI_S_CMD_CTRL_REG); 234c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, 235c4f52879SKarthikeyan Ramasubramanian S_GENI_CMD_ABORT, false); 236c4f52879SKarthikeyan Ramasubramanian writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); 237c4f52879SKarthikeyan Ramasubramanian writel_relaxed(FORCE_DEFAULT, uport->membase + GENI_FORCE_DEFAULT_REG); 238c4f52879SKarthikeyan Ramasubramanian } 239c4f52879SKarthikeyan Ramasubramanian 240c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_CONSOLE_POLL 241c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_get_char(struct uart_port *uport) 242c4f52879SKarthikeyan Ramasubramanian { 243c4f52879SKarthikeyan Ramasubramanian u32 rx_fifo; 244c4f52879SKarthikeyan Ramasubramanian u32 status; 245c4f52879SKarthikeyan Ramasubramanian 246c4f52879SKarthikeyan Ramasubramanian status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS); 247c4f52879SKarthikeyan Ramasubramanian writel_relaxed(status, uport->membase + SE_GENI_M_IRQ_CLEAR); 248c4f52879SKarthikeyan Ramasubramanian 249c4f52879SKarthikeyan Ramasubramanian status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS); 250c4f52879SKarthikeyan Ramasubramanian writel_relaxed(status, uport->membase + SE_GENI_S_IRQ_CLEAR); 251c4f52879SKarthikeyan Ramasubramanian 252c4f52879SKarthikeyan Ramasubramanian /* 253c4f52879SKarthikeyan Ramasubramanian * Ensure the writes to clear interrupts is not re-ordered after 254c4f52879SKarthikeyan Ramasubramanian * reading the data. 255c4f52879SKarthikeyan Ramasubramanian */ 256c4f52879SKarthikeyan Ramasubramanian mb(); 257c4f52879SKarthikeyan Ramasubramanian 258c4f52879SKarthikeyan Ramasubramanian status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS); 259c4f52879SKarthikeyan Ramasubramanian if (!(status & RX_FIFO_WC_MSK)) 260c4f52879SKarthikeyan Ramasubramanian return NO_POLL_CHAR; 261c4f52879SKarthikeyan Ramasubramanian 262c4f52879SKarthikeyan Ramasubramanian rx_fifo = readl(uport->membase + SE_GENI_RX_FIFOn); 263c4f52879SKarthikeyan Ramasubramanian return rx_fifo & 0xff; 264c4f52879SKarthikeyan Ramasubramanian } 265c4f52879SKarthikeyan Ramasubramanian 266c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_poll_put_char(struct uart_port *uport, 267c4f52879SKarthikeyan Ramasubramanian unsigned char c) 268c4f52879SKarthikeyan Ramasubramanian { 269c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 270c4f52879SKarthikeyan Ramasubramanian 271c4f52879SKarthikeyan Ramasubramanian writel_relaxed(port->tx_wm, uport->membase + SE_GENI_TX_WATERMARK_REG); 272c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_setup_tx(uport, 1); 273c4f52879SKarthikeyan Ramasubramanian WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, 274c4f52879SKarthikeyan Ramasubramanian M_TX_FIFO_WATERMARK_EN, true)); 275c4f52879SKarthikeyan Ramasubramanian writel_relaxed(c, uport->membase + SE_GENI_TX_FIFOn); 276c4f52879SKarthikeyan Ramasubramanian writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase + 277c4f52879SKarthikeyan Ramasubramanian SE_GENI_M_IRQ_CLEAR); 278c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_poll_tx_done(uport); 279c4f52879SKarthikeyan Ramasubramanian } 280c4f52879SKarthikeyan Ramasubramanian #endif 281c4f52879SKarthikeyan Ramasubramanian 282c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE 283c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch) 284c4f52879SKarthikeyan Ramasubramanian { 285c4f52879SKarthikeyan Ramasubramanian writel_relaxed(ch, uport->membase + SE_GENI_TX_FIFOn); 286c4f52879SKarthikeyan Ramasubramanian } 287c4f52879SKarthikeyan Ramasubramanian 288c4f52879SKarthikeyan Ramasubramanian static void 289c4f52879SKarthikeyan Ramasubramanian __qcom_geni_serial_console_write(struct uart_port *uport, const char *s, 290c4f52879SKarthikeyan Ramasubramanian unsigned int count) 291c4f52879SKarthikeyan Ramasubramanian { 292c4f52879SKarthikeyan Ramasubramanian int i; 293c4f52879SKarthikeyan Ramasubramanian u32 bytes_to_send = count; 294c4f52879SKarthikeyan Ramasubramanian 295c4f52879SKarthikeyan Ramasubramanian for (i = 0; i < count; i++) { 296f0262568SKarthikeyan Ramasubramanian /* 297f0262568SKarthikeyan Ramasubramanian * uart_console_write() adds a carriage return for each newline. 298f0262568SKarthikeyan Ramasubramanian * Account for additional bytes to be written. 299f0262568SKarthikeyan Ramasubramanian */ 300c4f52879SKarthikeyan Ramasubramanian if (s[i] == '\n') 301c4f52879SKarthikeyan Ramasubramanian bytes_to_send++; 302c4f52879SKarthikeyan Ramasubramanian } 303c4f52879SKarthikeyan Ramasubramanian 304c4f52879SKarthikeyan Ramasubramanian writel_relaxed(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); 305c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_setup_tx(uport, bytes_to_send); 306c4f52879SKarthikeyan Ramasubramanian for (i = 0; i < count; ) { 307c4f52879SKarthikeyan Ramasubramanian size_t chars_to_write = 0; 308c4f52879SKarthikeyan Ramasubramanian size_t avail = DEF_FIFO_DEPTH_WORDS - DEF_TX_WM; 309c4f52879SKarthikeyan Ramasubramanian 310c4f52879SKarthikeyan Ramasubramanian /* 311c4f52879SKarthikeyan Ramasubramanian * If the WM bit never set, then the Tx state machine is not 312c4f52879SKarthikeyan Ramasubramanian * in a valid state, so break, cancel/abort any existing 313c4f52879SKarthikeyan Ramasubramanian * command. Unfortunately the current data being written is 314c4f52879SKarthikeyan Ramasubramanian * lost. 315c4f52879SKarthikeyan Ramasubramanian */ 316c4f52879SKarthikeyan Ramasubramanian if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, 317c4f52879SKarthikeyan Ramasubramanian M_TX_FIFO_WATERMARK_EN, true)) 318c4f52879SKarthikeyan Ramasubramanian break; 3196a10635eSKarthikeyan Ramasubramanian chars_to_write = min_t(size_t, count - i, avail / 2); 320c4f52879SKarthikeyan Ramasubramanian uart_console_write(uport, s + i, chars_to_write, 321c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_wr_char); 322c4f52879SKarthikeyan Ramasubramanian writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase + 323c4f52879SKarthikeyan Ramasubramanian SE_GENI_M_IRQ_CLEAR); 324c4f52879SKarthikeyan Ramasubramanian i += chars_to_write; 325c4f52879SKarthikeyan Ramasubramanian } 326c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_poll_tx_done(uport); 327c4f52879SKarthikeyan Ramasubramanian } 328c4f52879SKarthikeyan Ramasubramanian 329c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_console_write(struct console *co, const char *s, 330c4f52879SKarthikeyan Ramasubramanian unsigned int count) 331c4f52879SKarthikeyan Ramasubramanian { 332c4f52879SKarthikeyan Ramasubramanian struct uart_port *uport; 333c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port; 334c4f52879SKarthikeyan Ramasubramanian bool locked = true; 335c4f52879SKarthikeyan Ramasubramanian unsigned long flags; 336c4f52879SKarthikeyan Ramasubramanian 337c4f52879SKarthikeyan Ramasubramanian WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS); 338c4f52879SKarthikeyan Ramasubramanian 339c4f52879SKarthikeyan Ramasubramanian port = get_port_from_line(co->index); 340c4f52879SKarthikeyan Ramasubramanian if (IS_ERR(port)) 341c4f52879SKarthikeyan Ramasubramanian return; 342c4f52879SKarthikeyan Ramasubramanian 343c4f52879SKarthikeyan Ramasubramanian uport = &port->uport; 344c4f52879SKarthikeyan Ramasubramanian if (oops_in_progress) 345c4f52879SKarthikeyan Ramasubramanian locked = spin_trylock_irqsave(&uport->lock, flags); 346c4f52879SKarthikeyan Ramasubramanian else 347c4f52879SKarthikeyan Ramasubramanian spin_lock_irqsave(&uport->lock, flags); 348c4f52879SKarthikeyan Ramasubramanian 349c4f52879SKarthikeyan Ramasubramanian /* Cancel the current write to log the fault */ 350c4f52879SKarthikeyan Ramasubramanian if (!locked) { 351c4f52879SKarthikeyan Ramasubramanian geni_se_cancel_m_cmd(&port->se); 352c4f52879SKarthikeyan Ramasubramanian if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, 353c4f52879SKarthikeyan Ramasubramanian M_CMD_CANCEL_EN, true)) { 354c4f52879SKarthikeyan Ramasubramanian geni_se_abort_m_cmd(&port->se); 355c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, 356c4f52879SKarthikeyan Ramasubramanian M_CMD_ABORT_EN, true); 357c4f52879SKarthikeyan Ramasubramanian writel_relaxed(M_CMD_ABORT_EN, uport->membase + 358c4f52879SKarthikeyan Ramasubramanian SE_GENI_M_IRQ_CLEAR); 359c4f52879SKarthikeyan Ramasubramanian } 360c4f52879SKarthikeyan Ramasubramanian writel_relaxed(M_CMD_CANCEL_EN, uport->membase + 361c4f52879SKarthikeyan Ramasubramanian SE_GENI_M_IRQ_CLEAR); 362c4f52879SKarthikeyan Ramasubramanian } 363c4f52879SKarthikeyan Ramasubramanian 364c4f52879SKarthikeyan Ramasubramanian __qcom_geni_serial_console_write(uport, s, count); 365c4f52879SKarthikeyan Ramasubramanian if (locked) 366c4f52879SKarthikeyan Ramasubramanian spin_unlock_irqrestore(&uport->lock, flags); 367c4f52879SKarthikeyan Ramasubramanian } 368c4f52879SKarthikeyan Ramasubramanian 369c4f52879SKarthikeyan Ramasubramanian static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) 370c4f52879SKarthikeyan Ramasubramanian { 371c4f52879SKarthikeyan Ramasubramanian u32 i; 372c4f52879SKarthikeyan Ramasubramanian unsigned char buf[sizeof(u32)]; 373c4f52879SKarthikeyan Ramasubramanian struct tty_port *tport; 374c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 375c4f52879SKarthikeyan Ramasubramanian 376c4f52879SKarthikeyan Ramasubramanian tport = &uport->state->port; 377c4f52879SKarthikeyan Ramasubramanian for (i = 0; i < bytes; ) { 378c4f52879SKarthikeyan Ramasubramanian int c; 379c4f52879SKarthikeyan Ramasubramanian int chunk = min_t(int, bytes - i, port->rx_bytes_pw); 380c4f52879SKarthikeyan Ramasubramanian 381c4f52879SKarthikeyan Ramasubramanian ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, buf, 1); 382c4f52879SKarthikeyan Ramasubramanian i += chunk; 383c4f52879SKarthikeyan Ramasubramanian if (drop) 384c4f52879SKarthikeyan Ramasubramanian continue; 385c4f52879SKarthikeyan Ramasubramanian 386c4f52879SKarthikeyan Ramasubramanian for (c = 0; c < chunk; c++) { 387c4f52879SKarthikeyan Ramasubramanian int sysrq; 388c4f52879SKarthikeyan Ramasubramanian 389c4f52879SKarthikeyan Ramasubramanian uport->icount.rx++; 390c4f52879SKarthikeyan Ramasubramanian if (port->brk && buf[c] == 0) { 391c4f52879SKarthikeyan Ramasubramanian port->brk = false; 392c4f52879SKarthikeyan Ramasubramanian if (uart_handle_break(uport)) 393c4f52879SKarthikeyan Ramasubramanian continue; 394c4f52879SKarthikeyan Ramasubramanian } 395c4f52879SKarthikeyan Ramasubramanian 396c4f52879SKarthikeyan Ramasubramanian sysrq = uart_handle_sysrq_char(uport, buf[c]); 397c4f52879SKarthikeyan Ramasubramanian if (!sysrq) 398c4f52879SKarthikeyan Ramasubramanian tty_insert_flip_char(tport, buf[c], TTY_NORMAL); 399c4f52879SKarthikeyan Ramasubramanian } 400c4f52879SKarthikeyan Ramasubramanian } 401c4f52879SKarthikeyan Ramasubramanian if (!drop) 402c4f52879SKarthikeyan Ramasubramanian tty_flip_buffer_push(tport); 403c4f52879SKarthikeyan Ramasubramanian return 0; 404c4f52879SKarthikeyan Ramasubramanian } 405c4f52879SKarthikeyan Ramasubramanian #else 406c4f52879SKarthikeyan Ramasubramanian static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) 407c4f52879SKarthikeyan Ramasubramanian { 408c4f52879SKarthikeyan Ramasubramanian return -EPERM; 409c4f52879SKarthikeyan Ramasubramanian } 410c4f52879SKarthikeyan Ramasubramanian 411c4f52879SKarthikeyan Ramasubramanian #endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */ 412c4f52879SKarthikeyan Ramasubramanian 413c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_start_tx(struct uart_port *uport) 414c4f52879SKarthikeyan Ramasubramanian { 415c4f52879SKarthikeyan Ramasubramanian u32 irq_en; 416c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 417c4f52879SKarthikeyan Ramasubramanian u32 status; 418c4f52879SKarthikeyan Ramasubramanian 419c4f52879SKarthikeyan Ramasubramanian if (port->xfer_mode == GENI_SE_FIFO) { 4207fb5b880SKarthikeyan Ramasubramanian /* 4217fb5b880SKarthikeyan Ramasubramanian * readl ensures reading & writing of IRQ_EN register 4227fb5b880SKarthikeyan Ramasubramanian * is not re-ordered before checking the status of the 4237fb5b880SKarthikeyan Ramasubramanian * Serial Engine. 4247fb5b880SKarthikeyan Ramasubramanian */ 4257fb5b880SKarthikeyan Ramasubramanian status = readl(uport->membase + SE_GENI_STATUS); 426c4f52879SKarthikeyan Ramasubramanian if (status & M_GENI_CMD_ACTIVE) 427c4f52879SKarthikeyan Ramasubramanian return; 428c4f52879SKarthikeyan Ramasubramanian 429c4f52879SKarthikeyan Ramasubramanian if (!qcom_geni_serial_tx_empty(uport)) 430c4f52879SKarthikeyan Ramasubramanian return; 431c4f52879SKarthikeyan Ramasubramanian 432c4f52879SKarthikeyan Ramasubramanian irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); 433c4f52879SKarthikeyan Ramasubramanian irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; 434c4f52879SKarthikeyan Ramasubramanian 435c4f52879SKarthikeyan Ramasubramanian writel_relaxed(port->tx_wm, uport->membase + 436c4f52879SKarthikeyan Ramasubramanian SE_GENI_TX_WATERMARK_REG); 437c4f52879SKarthikeyan Ramasubramanian writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); 438c4f52879SKarthikeyan Ramasubramanian } 439c4f52879SKarthikeyan Ramasubramanian } 440c4f52879SKarthikeyan Ramasubramanian 441c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_stop_tx(struct uart_port *uport) 442c4f52879SKarthikeyan Ramasubramanian { 443c4f52879SKarthikeyan Ramasubramanian u32 irq_en; 444c4f52879SKarthikeyan Ramasubramanian u32 status; 445c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 446c4f52879SKarthikeyan Ramasubramanian 447c4f52879SKarthikeyan Ramasubramanian irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); 448c4f52879SKarthikeyan Ramasubramanian irq_en &= ~M_CMD_DONE_EN; 449c4f52879SKarthikeyan Ramasubramanian if (port->xfer_mode == GENI_SE_FIFO) { 450c4f52879SKarthikeyan Ramasubramanian irq_en &= ~M_TX_FIFO_WATERMARK_EN; 451c4f52879SKarthikeyan Ramasubramanian writel_relaxed(0, uport->membase + 452c4f52879SKarthikeyan Ramasubramanian SE_GENI_TX_WATERMARK_REG); 453c4f52879SKarthikeyan Ramasubramanian } 454c4f52879SKarthikeyan Ramasubramanian port->xmit_size = 0; 455c4f52879SKarthikeyan Ramasubramanian writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); 456c4f52879SKarthikeyan Ramasubramanian status = readl_relaxed(uport->membase + SE_GENI_STATUS); 457c4f52879SKarthikeyan Ramasubramanian /* Possible stop tx is called multiple times. */ 458c4f52879SKarthikeyan Ramasubramanian if (!(status & M_GENI_CMD_ACTIVE)) 459c4f52879SKarthikeyan Ramasubramanian return; 460c4f52879SKarthikeyan Ramasubramanian 461c4f52879SKarthikeyan Ramasubramanian /* 462c4f52879SKarthikeyan Ramasubramanian * Ensure cancel command write is not re-ordered before checking 463c4f52879SKarthikeyan Ramasubramanian * the status of the Primary Sequencer. 464c4f52879SKarthikeyan Ramasubramanian */ 465c4f52879SKarthikeyan Ramasubramanian mb(); 466c4f52879SKarthikeyan Ramasubramanian 467c4f52879SKarthikeyan Ramasubramanian geni_se_cancel_m_cmd(&port->se); 468c4f52879SKarthikeyan Ramasubramanian if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, 469c4f52879SKarthikeyan Ramasubramanian M_CMD_CANCEL_EN, true)) { 470c4f52879SKarthikeyan Ramasubramanian geni_se_abort_m_cmd(&port->se); 471c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, 472c4f52879SKarthikeyan Ramasubramanian M_CMD_ABORT_EN, true); 473c4f52879SKarthikeyan Ramasubramanian writel_relaxed(M_CMD_ABORT_EN, uport->membase + 474c4f52879SKarthikeyan Ramasubramanian SE_GENI_M_IRQ_CLEAR); 475c4f52879SKarthikeyan Ramasubramanian } 476c4f52879SKarthikeyan Ramasubramanian writel_relaxed(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); 477c4f52879SKarthikeyan Ramasubramanian } 478c4f52879SKarthikeyan Ramasubramanian 479c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_start_rx(struct uart_port *uport) 480c4f52879SKarthikeyan Ramasubramanian { 481c4f52879SKarthikeyan Ramasubramanian u32 irq_en; 482c4f52879SKarthikeyan Ramasubramanian u32 status; 483c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 484c4f52879SKarthikeyan Ramasubramanian 485c4f52879SKarthikeyan Ramasubramanian status = readl_relaxed(uport->membase + SE_GENI_STATUS); 486c4f52879SKarthikeyan Ramasubramanian if (status & S_GENI_CMD_ACTIVE) 487c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_stop_rx(uport); 488c4f52879SKarthikeyan Ramasubramanian 489c4f52879SKarthikeyan Ramasubramanian /* 490c4f52879SKarthikeyan Ramasubramanian * Ensure setup command write is not re-ordered before checking 491c4f52879SKarthikeyan Ramasubramanian * the status of the Secondary Sequencer. 492c4f52879SKarthikeyan Ramasubramanian */ 493c4f52879SKarthikeyan Ramasubramanian mb(); 494c4f52879SKarthikeyan Ramasubramanian 495c4f52879SKarthikeyan Ramasubramanian geni_se_setup_s_cmd(&port->se, UART_START_READ, 0); 496c4f52879SKarthikeyan Ramasubramanian 497c4f52879SKarthikeyan Ramasubramanian if (port->xfer_mode == GENI_SE_FIFO) { 498c4f52879SKarthikeyan Ramasubramanian irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN); 499c4f52879SKarthikeyan Ramasubramanian irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; 500c4f52879SKarthikeyan Ramasubramanian writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN); 501c4f52879SKarthikeyan Ramasubramanian 502c4f52879SKarthikeyan Ramasubramanian irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); 503c4f52879SKarthikeyan Ramasubramanian irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; 504c4f52879SKarthikeyan Ramasubramanian writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); 505c4f52879SKarthikeyan Ramasubramanian } 506c4f52879SKarthikeyan Ramasubramanian } 507c4f52879SKarthikeyan Ramasubramanian 508c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_stop_rx(struct uart_port *uport) 509c4f52879SKarthikeyan Ramasubramanian { 510c4f52879SKarthikeyan Ramasubramanian u32 irq_en; 511c4f52879SKarthikeyan Ramasubramanian u32 status; 512c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 513c4f52879SKarthikeyan Ramasubramanian u32 irq_clear = S_CMD_DONE_EN; 514c4f52879SKarthikeyan Ramasubramanian 515c4f52879SKarthikeyan Ramasubramanian if (port->xfer_mode == GENI_SE_FIFO) { 516c4f52879SKarthikeyan Ramasubramanian irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN); 517c4f52879SKarthikeyan Ramasubramanian irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); 518c4f52879SKarthikeyan Ramasubramanian writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN); 519c4f52879SKarthikeyan Ramasubramanian 520c4f52879SKarthikeyan Ramasubramanian irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); 521c4f52879SKarthikeyan Ramasubramanian irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); 522c4f52879SKarthikeyan Ramasubramanian writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); 523c4f52879SKarthikeyan Ramasubramanian } 524c4f52879SKarthikeyan Ramasubramanian 525c4f52879SKarthikeyan Ramasubramanian status = readl_relaxed(uport->membase + SE_GENI_STATUS); 526c4f52879SKarthikeyan Ramasubramanian /* Possible stop rx is called multiple times. */ 527c4f52879SKarthikeyan Ramasubramanian if (!(status & S_GENI_CMD_ACTIVE)) 528c4f52879SKarthikeyan Ramasubramanian return; 529c4f52879SKarthikeyan Ramasubramanian 530c4f52879SKarthikeyan Ramasubramanian /* 531c4f52879SKarthikeyan Ramasubramanian * Ensure cancel command write is not re-ordered before checking 532c4f52879SKarthikeyan Ramasubramanian * the status of the Secondary Sequencer. 533c4f52879SKarthikeyan Ramasubramanian */ 534c4f52879SKarthikeyan Ramasubramanian mb(); 535c4f52879SKarthikeyan Ramasubramanian 536c4f52879SKarthikeyan Ramasubramanian geni_se_cancel_s_cmd(&port->se); 537c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, 538c4f52879SKarthikeyan Ramasubramanian S_GENI_CMD_CANCEL, false); 539c4f52879SKarthikeyan Ramasubramanian status = readl_relaxed(uport->membase + SE_GENI_STATUS); 540c4f52879SKarthikeyan Ramasubramanian writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); 541c4f52879SKarthikeyan Ramasubramanian if (status & S_GENI_CMD_ACTIVE) 542c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_abort_rx(uport); 543c4f52879SKarthikeyan Ramasubramanian } 544c4f52879SKarthikeyan Ramasubramanian 545c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop) 546c4f52879SKarthikeyan Ramasubramanian { 547c4f52879SKarthikeyan Ramasubramanian u32 status; 548c4f52879SKarthikeyan Ramasubramanian u32 word_cnt; 549c4f52879SKarthikeyan Ramasubramanian u32 last_word_byte_cnt; 550c4f52879SKarthikeyan Ramasubramanian u32 last_word_partial; 551c4f52879SKarthikeyan Ramasubramanian u32 total_bytes; 552c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 553c4f52879SKarthikeyan Ramasubramanian 554c4f52879SKarthikeyan Ramasubramanian status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS); 555c4f52879SKarthikeyan Ramasubramanian word_cnt = status & RX_FIFO_WC_MSK; 556c4f52879SKarthikeyan Ramasubramanian last_word_partial = status & RX_LAST; 557c4f52879SKarthikeyan Ramasubramanian last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >> 558c4f52879SKarthikeyan Ramasubramanian RX_LAST_BYTE_VALID_SHFT; 559c4f52879SKarthikeyan Ramasubramanian 560c4f52879SKarthikeyan Ramasubramanian if (!word_cnt) 561c4f52879SKarthikeyan Ramasubramanian return; 562c4f52879SKarthikeyan Ramasubramanian total_bytes = port->rx_bytes_pw * (word_cnt - 1); 563c4f52879SKarthikeyan Ramasubramanian if (last_word_partial && last_word_byte_cnt) 564c4f52879SKarthikeyan Ramasubramanian total_bytes += last_word_byte_cnt; 565c4f52879SKarthikeyan Ramasubramanian else 566c4f52879SKarthikeyan Ramasubramanian total_bytes += port->rx_bytes_pw; 567c4f52879SKarthikeyan Ramasubramanian port->handle_rx(uport, total_bytes, drop); 568c4f52879SKarthikeyan Ramasubramanian } 569c4f52879SKarthikeyan Ramasubramanian 570c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_handle_tx(struct uart_port *uport) 571c4f52879SKarthikeyan Ramasubramanian { 572c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 573c4f52879SKarthikeyan Ramasubramanian struct circ_buf *xmit = &uport->state->xmit; 574c4f52879SKarthikeyan Ramasubramanian size_t avail; 575c4f52879SKarthikeyan Ramasubramanian size_t remaining; 576c4f52879SKarthikeyan Ramasubramanian int i; 577c4f52879SKarthikeyan Ramasubramanian u32 status; 578c4f52879SKarthikeyan Ramasubramanian unsigned int chunk; 579c4f52879SKarthikeyan Ramasubramanian int tail; 580c4f52879SKarthikeyan Ramasubramanian 581c4f52879SKarthikeyan Ramasubramanian chunk = uart_circ_chars_pending(xmit); 582c4f52879SKarthikeyan Ramasubramanian status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS); 583c4f52879SKarthikeyan Ramasubramanian /* Both FIFO and framework buffer are drained */ 584c4f52879SKarthikeyan Ramasubramanian if (chunk == port->xmit_size && !status) { 585c4f52879SKarthikeyan Ramasubramanian port->xmit_size = 0; 586c4f52879SKarthikeyan Ramasubramanian uart_circ_clear(xmit); 587c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_stop_tx(uport); 588c4f52879SKarthikeyan Ramasubramanian goto out_write_wakeup; 589c4f52879SKarthikeyan Ramasubramanian } 590c4f52879SKarthikeyan Ramasubramanian chunk -= port->xmit_size; 591c4f52879SKarthikeyan Ramasubramanian 592c4f52879SKarthikeyan Ramasubramanian avail = (port->tx_fifo_depth - port->tx_wm) * port->tx_bytes_pw; 593c4f52879SKarthikeyan Ramasubramanian tail = (xmit->tail + port->xmit_size) & (UART_XMIT_SIZE - 1); 5948e70c47cSKarthikeyan Ramasubramanian chunk = min3((size_t)chunk, (size_t)(UART_XMIT_SIZE - tail), avail); 595c4f52879SKarthikeyan Ramasubramanian if (!chunk) 596c4f52879SKarthikeyan Ramasubramanian goto out_write_wakeup; 597c4f52879SKarthikeyan Ramasubramanian 598c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_setup_tx(uport, chunk); 599c4f52879SKarthikeyan Ramasubramanian 600c4f52879SKarthikeyan Ramasubramanian remaining = chunk; 601c4f52879SKarthikeyan Ramasubramanian for (i = 0; i < chunk; ) { 602c4f52879SKarthikeyan Ramasubramanian unsigned int tx_bytes; 60369736b57SKarthikeyan Ramasubramanian u8 buf[sizeof(u32)]; 604c4f52879SKarthikeyan Ramasubramanian int c; 605c4f52879SKarthikeyan Ramasubramanian 60669736b57SKarthikeyan Ramasubramanian memset(buf, 0, ARRAY_SIZE(buf)); 6076a10635eSKarthikeyan Ramasubramanian tx_bytes = min_t(size_t, remaining, port->tx_bytes_pw); 608c4f52879SKarthikeyan Ramasubramanian for (c = 0; c < tx_bytes ; c++) 60969736b57SKarthikeyan Ramasubramanian buf[c] = xmit->buf[tail + c]; 610c4f52879SKarthikeyan Ramasubramanian 61169736b57SKarthikeyan Ramasubramanian iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1); 612c4f52879SKarthikeyan Ramasubramanian 613c4f52879SKarthikeyan Ramasubramanian i += tx_bytes; 614c4f52879SKarthikeyan Ramasubramanian tail = (tail + tx_bytes) & (UART_XMIT_SIZE - 1); 615c4f52879SKarthikeyan Ramasubramanian uport->icount.tx += tx_bytes; 616c4f52879SKarthikeyan Ramasubramanian remaining -= tx_bytes; 617c4f52879SKarthikeyan Ramasubramanian } 618c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_poll_tx_done(uport); 619c4f52879SKarthikeyan Ramasubramanian port->xmit_size += chunk; 620c4f52879SKarthikeyan Ramasubramanian out_write_wakeup: 621c4f52879SKarthikeyan Ramasubramanian uart_write_wakeup(uport); 622c4f52879SKarthikeyan Ramasubramanian } 623c4f52879SKarthikeyan Ramasubramanian 624c4f52879SKarthikeyan Ramasubramanian static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) 625c4f52879SKarthikeyan Ramasubramanian { 626c4f52879SKarthikeyan Ramasubramanian unsigned int m_irq_status; 627c4f52879SKarthikeyan Ramasubramanian unsigned int s_irq_status; 628c4f52879SKarthikeyan Ramasubramanian struct uart_port *uport = dev; 629c4f52879SKarthikeyan Ramasubramanian unsigned long flags; 630c4f52879SKarthikeyan Ramasubramanian unsigned int m_irq_en; 631c4f52879SKarthikeyan Ramasubramanian bool drop_rx = false; 632c4f52879SKarthikeyan Ramasubramanian struct tty_port *tport = &uport->state->port; 633c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 634c4f52879SKarthikeyan Ramasubramanian 635c4f52879SKarthikeyan Ramasubramanian if (uport->suspended) 636*ec91df8dSKarthikeyan Ramasubramanian return IRQ_NONE; 637c4f52879SKarthikeyan Ramasubramanian 638c4f52879SKarthikeyan Ramasubramanian spin_lock_irqsave(&uport->lock, flags); 639c4f52879SKarthikeyan Ramasubramanian m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS); 640c4f52879SKarthikeyan Ramasubramanian s_irq_status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS); 641c4f52879SKarthikeyan Ramasubramanian m_irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); 642c4f52879SKarthikeyan Ramasubramanian writel_relaxed(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR); 643c4f52879SKarthikeyan Ramasubramanian writel_relaxed(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR); 644c4f52879SKarthikeyan Ramasubramanian 645c4f52879SKarthikeyan Ramasubramanian if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN)) 646c4f52879SKarthikeyan Ramasubramanian goto out_unlock; 647c4f52879SKarthikeyan Ramasubramanian 648c4f52879SKarthikeyan Ramasubramanian if (s_irq_status & S_RX_FIFO_WR_ERR_EN) { 649c4f52879SKarthikeyan Ramasubramanian uport->icount.overrun++; 650c4f52879SKarthikeyan Ramasubramanian tty_insert_flip_char(tport, 0, TTY_OVERRUN); 651c4f52879SKarthikeyan Ramasubramanian } 652c4f52879SKarthikeyan Ramasubramanian 653c4f52879SKarthikeyan Ramasubramanian if (m_irq_status & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN) && 654c4f52879SKarthikeyan Ramasubramanian m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN)) 655c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_handle_tx(uport); 656c4f52879SKarthikeyan Ramasubramanian 657c4f52879SKarthikeyan Ramasubramanian if (s_irq_status & S_GP_IRQ_0_EN || s_irq_status & S_GP_IRQ_1_EN) { 658c4f52879SKarthikeyan Ramasubramanian if (s_irq_status & S_GP_IRQ_0_EN) 659c4f52879SKarthikeyan Ramasubramanian uport->icount.parity++; 660c4f52879SKarthikeyan Ramasubramanian drop_rx = true; 661c4f52879SKarthikeyan Ramasubramanian } else if (s_irq_status & S_GP_IRQ_2_EN || 662c4f52879SKarthikeyan Ramasubramanian s_irq_status & S_GP_IRQ_3_EN) { 663c4f52879SKarthikeyan Ramasubramanian uport->icount.brk++; 664c4f52879SKarthikeyan Ramasubramanian port->brk = true; 665c4f52879SKarthikeyan Ramasubramanian } 666c4f52879SKarthikeyan Ramasubramanian 667c4f52879SKarthikeyan Ramasubramanian if (s_irq_status & S_RX_FIFO_WATERMARK_EN || 668c4f52879SKarthikeyan Ramasubramanian s_irq_status & S_RX_FIFO_LAST_EN) 669c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_handle_rx(uport, drop_rx); 670c4f52879SKarthikeyan Ramasubramanian 671c4f52879SKarthikeyan Ramasubramanian out_unlock: 672c4f52879SKarthikeyan Ramasubramanian spin_unlock_irqrestore(&uport->lock, flags); 673c4f52879SKarthikeyan Ramasubramanian return IRQ_HANDLED; 674c4f52879SKarthikeyan Ramasubramanian } 675c4f52879SKarthikeyan Ramasubramanian 6766a10635eSKarthikeyan Ramasubramanian static void get_tx_fifo_size(struct qcom_geni_serial_port *port) 677c4f52879SKarthikeyan Ramasubramanian { 678c4f52879SKarthikeyan Ramasubramanian struct uart_port *uport; 679c4f52879SKarthikeyan Ramasubramanian 680c4f52879SKarthikeyan Ramasubramanian uport = &port->uport; 681c4f52879SKarthikeyan Ramasubramanian port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se); 682c4f52879SKarthikeyan Ramasubramanian port->tx_fifo_width = geni_se_get_tx_fifo_width(&port->se); 683c4f52879SKarthikeyan Ramasubramanian port->rx_fifo_depth = geni_se_get_rx_fifo_depth(&port->se); 684c4f52879SKarthikeyan Ramasubramanian uport->fifosize = 685c4f52879SKarthikeyan Ramasubramanian (port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE; 686c4f52879SKarthikeyan Ramasubramanian } 687c4f52879SKarthikeyan Ramasubramanian 688c4f52879SKarthikeyan Ramasubramanian static void set_rfr_wm(struct qcom_geni_serial_port *port) 689c4f52879SKarthikeyan Ramasubramanian { 690c4f52879SKarthikeyan Ramasubramanian /* 691c4f52879SKarthikeyan Ramasubramanian * Set RFR (Flow off) to FIFO_DEPTH - 2. 692c4f52879SKarthikeyan Ramasubramanian * RX WM level at 10% RX_FIFO_DEPTH. 693c4f52879SKarthikeyan Ramasubramanian * TX WM level at 10% TX_FIFO_DEPTH. 694c4f52879SKarthikeyan Ramasubramanian */ 695c4f52879SKarthikeyan Ramasubramanian port->rx_rfr = port->rx_fifo_depth - 2; 696c4f52879SKarthikeyan Ramasubramanian port->rx_wm = UART_CONSOLE_RX_WM; 697c4f52879SKarthikeyan Ramasubramanian port->tx_wm = DEF_TX_WM; 698c4f52879SKarthikeyan Ramasubramanian } 699c4f52879SKarthikeyan Ramasubramanian 700c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_shutdown(struct uart_port *uport) 701c4f52879SKarthikeyan Ramasubramanian { 702c4f52879SKarthikeyan Ramasubramanian unsigned long flags; 703c4f52879SKarthikeyan Ramasubramanian 704c4f52879SKarthikeyan Ramasubramanian /* Stop the console before stopping the current tx */ 705c4f52879SKarthikeyan Ramasubramanian console_stop(uport->cons); 706c4f52879SKarthikeyan Ramasubramanian 707c4f52879SKarthikeyan Ramasubramanian free_irq(uport->irq, uport); 708c4f52879SKarthikeyan Ramasubramanian spin_lock_irqsave(&uport->lock, flags); 709c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_stop_tx(uport); 710c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_stop_rx(uport); 711c4f52879SKarthikeyan Ramasubramanian spin_unlock_irqrestore(&uport->lock, flags); 712c4f52879SKarthikeyan Ramasubramanian } 713c4f52879SKarthikeyan Ramasubramanian 714c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_port_setup(struct uart_port *uport) 715c4f52879SKarthikeyan Ramasubramanian { 716c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 717c4f52879SKarthikeyan Ramasubramanian unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; 718c4f52879SKarthikeyan Ramasubramanian 719c4f52879SKarthikeyan Ramasubramanian set_rfr_wm(port); 720c4f52879SKarthikeyan Ramasubramanian writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT); 721c4f52879SKarthikeyan Ramasubramanian /* 722c4f52879SKarthikeyan Ramasubramanian * Make an unconditional cancel on the main sequencer to reset 723c4f52879SKarthikeyan Ramasubramanian * it else we could end up in data loss scenarios. 724c4f52879SKarthikeyan Ramasubramanian */ 725c4f52879SKarthikeyan Ramasubramanian port->xfer_mode = GENI_SE_FIFO; 726c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_poll_tx_done(uport); 727c4f52879SKarthikeyan Ramasubramanian geni_se_config_packing(&port->se, BITS_PER_BYTE, port->tx_bytes_pw, 728c4f52879SKarthikeyan Ramasubramanian false, true, false); 729c4f52879SKarthikeyan Ramasubramanian geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw, 730c4f52879SKarthikeyan Ramasubramanian false, false, true); 731c4f52879SKarthikeyan Ramasubramanian geni_se_init(&port->se, port->rx_wm, port->rx_rfr); 732c4f52879SKarthikeyan Ramasubramanian geni_se_select_mode(&port->se, port->xfer_mode); 733c4f52879SKarthikeyan Ramasubramanian port->setup = true; 734c4f52879SKarthikeyan Ramasubramanian return 0; 735c4f52879SKarthikeyan Ramasubramanian } 736c4f52879SKarthikeyan Ramasubramanian 737c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_startup(struct uart_port *uport) 738c4f52879SKarthikeyan Ramasubramanian { 739c4f52879SKarthikeyan Ramasubramanian int ret; 740c4f52879SKarthikeyan Ramasubramanian u32 proto; 741c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 742c4f52879SKarthikeyan Ramasubramanian 743c4f52879SKarthikeyan Ramasubramanian scnprintf(port->name, sizeof(port->name), 744c4f52879SKarthikeyan Ramasubramanian "qcom_serial_geni%d", uport->line); 745c4f52879SKarthikeyan Ramasubramanian 746c4f52879SKarthikeyan Ramasubramanian proto = geni_se_read_proto(&port->se); 747c4f52879SKarthikeyan Ramasubramanian if (proto != GENI_SE_UART) { 748c4f52879SKarthikeyan Ramasubramanian dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto); 749c4f52879SKarthikeyan Ramasubramanian return -ENXIO; 750c4f52879SKarthikeyan Ramasubramanian } 751c4f52879SKarthikeyan Ramasubramanian 752c4f52879SKarthikeyan Ramasubramanian get_tx_fifo_size(port); 753c4f52879SKarthikeyan Ramasubramanian if (!port->setup) { 754c4f52879SKarthikeyan Ramasubramanian ret = qcom_geni_serial_port_setup(uport); 755c4f52879SKarthikeyan Ramasubramanian if (ret) 756c4f52879SKarthikeyan Ramasubramanian return ret; 757c4f52879SKarthikeyan Ramasubramanian } 758c4f52879SKarthikeyan Ramasubramanian 759c4f52879SKarthikeyan Ramasubramanian ret = request_irq(uport->irq, qcom_geni_serial_isr, IRQF_TRIGGER_HIGH, 760c4f52879SKarthikeyan Ramasubramanian port->name, uport); 761c4f52879SKarthikeyan Ramasubramanian if (ret) 762c4f52879SKarthikeyan Ramasubramanian dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret); 763c4f52879SKarthikeyan Ramasubramanian return ret; 764c4f52879SKarthikeyan Ramasubramanian } 765c4f52879SKarthikeyan Ramasubramanian 766c4f52879SKarthikeyan Ramasubramanian static unsigned long get_clk_cfg(unsigned long clk_freq) 767c4f52879SKarthikeyan Ramasubramanian { 768c4f52879SKarthikeyan Ramasubramanian int i; 769c4f52879SKarthikeyan Ramasubramanian 770c4f52879SKarthikeyan Ramasubramanian for (i = 0; i < ARRAY_SIZE(root_freq); i++) { 771c4f52879SKarthikeyan Ramasubramanian if (!(root_freq[i] % clk_freq)) 772c4f52879SKarthikeyan Ramasubramanian return root_freq[i]; 773c4f52879SKarthikeyan Ramasubramanian } 774c4f52879SKarthikeyan Ramasubramanian return 0; 775c4f52879SKarthikeyan Ramasubramanian } 776c4f52879SKarthikeyan Ramasubramanian 777c4f52879SKarthikeyan Ramasubramanian static unsigned long get_clk_div_rate(unsigned int baud, unsigned int *clk_div) 778c4f52879SKarthikeyan Ramasubramanian { 779c4f52879SKarthikeyan Ramasubramanian unsigned long ser_clk; 780c4f52879SKarthikeyan Ramasubramanian unsigned long desired_clk; 781c4f52879SKarthikeyan Ramasubramanian 782c4f52879SKarthikeyan Ramasubramanian desired_clk = baud * UART_OVERSAMPLING; 783c4f52879SKarthikeyan Ramasubramanian ser_clk = get_clk_cfg(desired_clk); 784c4f52879SKarthikeyan Ramasubramanian if (!ser_clk) { 785c4f52879SKarthikeyan Ramasubramanian pr_err("%s: Can't find matching DFS entry for baud %d\n", 786c4f52879SKarthikeyan Ramasubramanian __func__, baud); 787c4f52879SKarthikeyan Ramasubramanian return ser_clk; 788c4f52879SKarthikeyan Ramasubramanian } 789c4f52879SKarthikeyan Ramasubramanian 790c4f52879SKarthikeyan Ramasubramanian *clk_div = ser_clk / desired_clk; 791c4f52879SKarthikeyan Ramasubramanian return ser_clk; 792c4f52879SKarthikeyan Ramasubramanian } 793c4f52879SKarthikeyan Ramasubramanian 794c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_set_termios(struct uart_port *uport, 795c4f52879SKarthikeyan Ramasubramanian struct ktermios *termios, struct ktermios *old) 796c4f52879SKarthikeyan Ramasubramanian { 797c4f52879SKarthikeyan Ramasubramanian unsigned int baud; 798c4f52879SKarthikeyan Ramasubramanian unsigned int bits_per_char; 799c4f52879SKarthikeyan Ramasubramanian unsigned int tx_trans_cfg; 800c4f52879SKarthikeyan Ramasubramanian unsigned int tx_parity_cfg; 801c4f52879SKarthikeyan Ramasubramanian unsigned int rx_trans_cfg; 802c4f52879SKarthikeyan Ramasubramanian unsigned int rx_parity_cfg; 803c4f52879SKarthikeyan Ramasubramanian unsigned int stop_bit_len; 804c4f52879SKarthikeyan Ramasubramanian unsigned int clk_div; 805c4f52879SKarthikeyan Ramasubramanian unsigned long ser_clk_cfg; 806c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 807c4f52879SKarthikeyan Ramasubramanian unsigned long clk_rate; 808c4f52879SKarthikeyan Ramasubramanian 809c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_stop_rx(uport); 810c4f52879SKarthikeyan Ramasubramanian /* baud rate */ 811c4f52879SKarthikeyan Ramasubramanian baud = uart_get_baud_rate(uport, termios, old, 300, 4000000); 812c4f52879SKarthikeyan Ramasubramanian port->baud = baud; 813c4f52879SKarthikeyan Ramasubramanian clk_rate = get_clk_div_rate(baud, &clk_div); 814c4f52879SKarthikeyan Ramasubramanian if (!clk_rate) 815c4f52879SKarthikeyan Ramasubramanian goto out_restart_rx; 816c4f52879SKarthikeyan Ramasubramanian 817c4f52879SKarthikeyan Ramasubramanian uport->uartclk = clk_rate; 818c4f52879SKarthikeyan Ramasubramanian clk_set_rate(port->se.clk, clk_rate); 819c4f52879SKarthikeyan Ramasubramanian ser_clk_cfg = SER_CLK_EN; 820c4f52879SKarthikeyan Ramasubramanian ser_clk_cfg |= clk_div << CLK_DIV_SHFT; 821c4f52879SKarthikeyan Ramasubramanian 822c4f52879SKarthikeyan Ramasubramanian /* parity */ 823c4f52879SKarthikeyan Ramasubramanian tx_trans_cfg = readl_relaxed(uport->membase + SE_UART_TX_TRANS_CFG); 824c4f52879SKarthikeyan Ramasubramanian tx_parity_cfg = readl_relaxed(uport->membase + SE_UART_TX_PARITY_CFG); 825c4f52879SKarthikeyan Ramasubramanian rx_trans_cfg = readl_relaxed(uport->membase + SE_UART_RX_TRANS_CFG); 826c4f52879SKarthikeyan Ramasubramanian rx_parity_cfg = readl_relaxed(uport->membase + SE_UART_RX_PARITY_CFG); 827c4f52879SKarthikeyan Ramasubramanian if (termios->c_cflag & PARENB) { 828c4f52879SKarthikeyan Ramasubramanian tx_trans_cfg |= UART_TX_PAR_EN; 829c4f52879SKarthikeyan Ramasubramanian rx_trans_cfg |= UART_RX_PAR_EN; 830c4f52879SKarthikeyan Ramasubramanian tx_parity_cfg |= PAR_CALC_EN; 831c4f52879SKarthikeyan Ramasubramanian rx_parity_cfg |= PAR_CALC_EN; 832c4f52879SKarthikeyan Ramasubramanian if (termios->c_cflag & PARODD) { 833c4f52879SKarthikeyan Ramasubramanian tx_parity_cfg |= PAR_ODD; 834c4f52879SKarthikeyan Ramasubramanian rx_parity_cfg |= PAR_ODD; 835c4f52879SKarthikeyan Ramasubramanian } else if (termios->c_cflag & CMSPAR) { 836c4f52879SKarthikeyan Ramasubramanian tx_parity_cfg |= PAR_SPACE; 837c4f52879SKarthikeyan Ramasubramanian rx_parity_cfg |= PAR_SPACE; 838c4f52879SKarthikeyan Ramasubramanian } else { 839c4f52879SKarthikeyan Ramasubramanian tx_parity_cfg |= PAR_EVEN; 840c4f52879SKarthikeyan Ramasubramanian rx_parity_cfg |= PAR_EVEN; 841c4f52879SKarthikeyan Ramasubramanian } 842c4f52879SKarthikeyan Ramasubramanian } else { 843c4f52879SKarthikeyan Ramasubramanian tx_trans_cfg &= ~UART_TX_PAR_EN; 844c4f52879SKarthikeyan Ramasubramanian rx_trans_cfg &= ~UART_RX_PAR_EN; 845c4f52879SKarthikeyan Ramasubramanian tx_parity_cfg &= ~PAR_CALC_EN; 846c4f52879SKarthikeyan Ramasubramanian rx_parity_cfg &= ~PAR_CALC_EN; 847c4f52879SKarthikeyan Ramasubramanian } 848c4f52879SKarthikeyan Ramasubramanian 849c4f52879SKarthikeyan Ramasubramanian /* bits per char */ 850c4f52879SKarthikeyan Ramasubramanian switch (termios->c_cflag & CSIZE) { 851c4f52879SKarthikeyan Ramasubramanian case CS5: 852c4f52879SKarthikeyan Ramasubramanian bits_per_char = 5; 853c4f52879SKarthikeyan Ramasubramanian break; 854c4f52879SKarthikeyan Ramasubramanian case CS6: 855c4f52879SKarthikeyan Ramasubramanian bits_per_char = 6; 856c4f52879SKarthikeyan Ramasubramanian break; 857c4f52879SKarthikeyan Ramasubramanian case CS7: 858c4f52879SKarthikeyan Ramasubramanian bits_per_char = 7; 859c4f52879SKarthikeyan Ramasubramanian break; 860c4f52879SKarthikeyan Ramasubramanian case CS8: 861c4f52879SKarthikeyan Ramasubramanian default: 862c4f52879SKarthikeyan Ramasubramanian bits_per_char = 8; 863c4f52879SKarthikeyan Ramasubramanian break; 864c4f52879SKarthikeyan Ramasubramanian } 865c4f52879SKarthikeyan Ramasubramanian 866c4f52879SKarthikeyan Ramasubramanian /* stop bits */ 867c4f52879SKarthikeyan Ramasubramanian if (termios->c_cflag & CSTOPB) 868c4f52879SKarthikeyan Ramasubramanian stop_bit_len = TX_STOP_BIT_LEN_2; 869c4f52879SKarthikeyan Ramasubramanian else 870c4f52879SKarthikeyan Ramasubramanian stop_bit_len = TX_STOP_BIT_LEN_1; 871c4f52879SKarthikeyan Ramasubramanian 872c4f52879SKarthikeyan Ramasubramanian /* flow control, clear the CTS_MASK bit if using flow control. */ 873c4f52879SKarthikeyan Ramasubramanian if (termios->c_cflag & CRTSCTS) 874c4f52879SKarthikeyan Ramasubramanian tx_trans_cfg &= ~UART_CTS_MASK; 875c4f52879SKarthikeyan Ramasubramanian else 876c4f52879SKarthikeyan Ramasubramanian tx_trans_cfg |= UART_CTS_MASK; 877c4f52879SKarthikeyan Ramasubramanian 878c4f52879SKarthikeyan Ramasubramanian if (baud) 879c4f52879SKarthikeyan Ramasubramanian uart_update_timeout(uport, termios->c_cflag, baud); 880c4f52879SKarthikeyan Ramasubramanian 881c4f52879SKarthikeyan Ramasubramanian writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); 882c4f52879SKarthikeyan Ramasubramanian writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); 883c4f52879SKarthikeyan Ramasubramanian writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); 884c4f52879SKarthikeyan Ramasubramanian writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); 885c4f52879SKarthikeyan Ramasubramanian writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); 886c4f52879SKarthikeyan Ramasubramanian writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); 887c4f52879SKarthikeyan Ramasubramanian writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); 888c4f52879SKarthikeyan Ramasubramanian writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); 889c4f52879SKarthikeyan Ramasubramanian writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); 890c4f52879SKarthikeyan Ramasubramanian out_restart_rx: 891c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_start_rx(uport); 892c4f52879SKarthikeyan Ramasubramanian } 893c4f52879SKarthikeyan Ramasubramanian 894c4f52879SKarthikeyan Ramasubramanian static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport) 895c4f52879SKarthikeyan Ramasubramanian { 8967fb5b880SKarthikeyan Ramasubramanian return !readl(uport->membase + SE_GENI_TX_FIFO_STATUS); 897c4f52879SKarthikeyan Ramasubramanian } 898c4f52879SKarthikeyan Ramasubramanian 899c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE 900c4f52879SKarthikeyan Ramasubramanian static int __init qcom_geni_console_setup(struct console *co, char *options) 901c4f52879SKarthikeyan Ramasubramanian { 902c4f52879SKarthikeyan Ramasubramanian struct uart_port *uport; 903c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port; 904c4f52879SKarthikeyan Ramasubramanian int baud; 905c4f52879SKarthikeyan Ramasubramanian int bits = 8; 906c4f52879SKarthikeyan Ramasubramanian int parity = 'n'; 907c4f52879SKarthikeyan Ramasubramanian int flow = 'n'; 908c4f52879SKarthikeyan Ramasubramanian 909c4f52879SKarthikeyan Ramasubramanian if (co->index >= GENI_UART_CONS_PORTS || co->index < 0) 910c4f52879SKarthikeyan Ramasubramanian return -ENXIO; 911c4f52879SKarthikeyan Ramasubramanian 912c4f52879SKarthikeyan Ramasubramanian port = get_port_from_line(co->index); 913c4f52879SKarthikeyan Ramasubramanian if (IS_ERR(port)) { 9146a10635eSKarthikeyan Ramasubramanian pr_err("Invalid line %d\n", co->index); 915c4f52879SKarthikeyan Ramasubramanian return PTR_ERR(port); 916c4f52879SKarthikeyan Ramasubramanian } 917c4f52879SKarthikeyan Ramasubramanian 918c4f52879SKarthikeyan Ramasubramanian uport = &port->uport; 919c4f52879SKarthikeyan Ramasubramanian 920c4f52879SKarthikeyan Ramasubramanian if (unlikely(!uport->membase)) 921c4f52879SKarthikeyan Ramasubramanian return -ENXIO; 922c4f52879SKarthikeyan Ramasubramanian 923c4f52879SKarthikeyan Ramasubramanian if (geni_se_resources_on(&port->se)) { 924c4f52879SKarthikeyan Ramasubramanian dev_err(port->se.dev, "Error turning on resources\n"); 925c4f52879SKarthikeyan Ramasubramanian return -ENXIO; 926c4f52879SKarthikeyan Ramasubramanian } 927c4f52879SKarthikeyan Ramasubramanian 928c4f52879SKarthikeyan Ramasubramanian if (unlikely(geni_se_read_proto(&port->se) != GENI_SE_UART)) { 929c4f52879SKarthikeyan Ramasubramanian geni_se_resources_off(&port->se); 930c4f52879SKarthikeyan Ramasubramanian return -ENXIO; 931c4f52879SKarthikeyan Ramasubramanian } 932c4f52879SKarthikeyan Ramasubramanian 933c4f52879SKarthikeyan Ramasubramanian if (!port->setup) { 934c4f52879SKarthikeyan Ramasubramanian port->tx_bytes_pw = 1; 935c4f52879SKarthikeyan Ramasubramanian port->rx_bytes_pw = RX_BYTES_PW; 936c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_stop_rx(uport); 937c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_port_setup(uport); 938c4f52879SKarthikeyan Ramasubramanian } 939c4f52879SKarthikeyan Ramasubramanian 940c4f52879SKarthikeyan Ramasubramanian if (options) 941c4f52879SKarthikeyan Ramasubramanian uart_parse_options(options, &baud, &parity, &bits, &flow); 942c4f52879SKarthikeyan Ramasubramanian 943c4f52879SKarthikeyan Ramasubramanian return uart_set_options(uport, co, baud, parity, bits, flow); 944c4f52879SKarthikeyan Ramasubramanian } 945c4f52879SKarthikeyan Ramasubramanian 946c4f52879SKarthikeyan Ramasubramanian static int __init console_register(struct uart_driver *drv) 947c4f52879SKarthikeyan Ramasubramanian { 948c4f52879SKarthikeyan Ramasubramanian return uart_register_driver(drv); 949c4f52879SKarthikeyan Ramasubramanian } 950c4f52879SKarthikeyan Ramasubramanian 951c4f52879SKarthikeyan Ramasubramanian static void console_unregister(struct uart_driver *drv) 952c4f52879SKarthikeyan Ramasubramanian { 953c4f52879SKarthikeyan Ramasubramanian uart_unregister_driver(drv); 954c4f52879SKarthikeyan Ramasubramanian } 955c4f52879SKarthikeyan Ramasubramanian 956c4f52879SKarthikeyan Ramasubramanian static struct console cons_ops = { 957c4f52879SKarthikeyan Ramasubramanian .name = "ttyMSM", 958c4f52879SKarthikeyan Ramasubramanian .write = qcom_geni_serial_console_write, 959c4f52879SKarthikeyan Ramasubramanian .device = uart_console_device, 960c4f52879SKarthikeyan Ramasubramanian .setup = qcom_geni_console_setup, 961c4f52879SKarthikeyan Ramasubramanian .flags = CON_PRINTBUFFER, 962c4f52879SKarthikeyan Ramasubramanian .index = -1, 963c4f52879SKarthikeyan Ramasubramanian .data = &qcom_geni_console_driver, 964c4f52879SKarthikeyan Ramasubramanian }; 965c4f52879SKarthikeyan Ramasubramanian 966c4f52879SKarthikeyan Ramasubramanian static struct uart_driver qcom_geni_console_driver = { 967c4f52879SKarthikeyan Ramasubramanian .owner = THIS_MODULE, 968c4f52879SKarthikeyan Ramasubramanian .driver_name = "qcom_geni_console", 969c4f52879SKarthikeyan Ramasubramanian .dev_name = "ttyMSM", 970c4f52879SKarthikeyan Ramasubramanian .nr = GENI_UART_CONS_PORTS, 971c4f52879SKarthikeyan Ramasubramanian .cons = &cons_ops, 972c4f52879SKarthikeyan Ramasubramanian }; 973c4f52879SKarthikeyan Ramasubramanian #else 974c4f52879SKarthikeyan Ramasubramanian static int console_register(struct uart_driver *drv) 975c4f52879SKarthikeyan Ramasubramanian { 976c4f52879SKarthikeyan Ramasubramanian return 0; 977c4f52879SKarthikeyan Ramasubramanian } 978c4f52879SKarthikeyan Ramasubramanian 979c4f52879SKarthikeyan Ramasubramanian static void console_unregister(struct uart_driver *drv) 980c4f52879SKarthikeyan Ramasubramanian { 981c4f52879SKarthikeyan Ramasubramanian } 982c4f52879SKarthikeyan Ramasubramanian #endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */ 983c4f52879SKarthikeyan Ramasubramanian 984c4f52879SKarthikeyan Ramasubramanian static void qcom_geni_serial_cons_pm(struct uart_port *uport, 985c4f52879SKarthikeyan Ramasubramanian unsigned int new_state, unsigned int old_state) 986c4f52879SKarthikeyan Ramasubramanian { 987c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = to_dev_port(uport, uport); 988c4f52879SKarthikeyan Ramasubramanian 989c4f52879SKarthikeyan Ramasubramanian if (unlikely(!uart_console(uport))) 990c4f52879SKarthikeyan Ramasubramanian return; 991c4f52879SKarthikeyan Ramasubramanian 992c4f52879SKarthikeyan Ramasubramanian if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) 993c4f52879SKarthikeyan Ramasubramanian geni_se_resources_on(&port->se); 994c4f52879SKarthikeyan Ramasubramanian else if (new_state == UART_PM_STATE_OFF && 995c4f52879SKarthikeyan Ramasubramanian old_state == UART_PM_STATE_ON) 996c4f52879SKarthikeyan Ramasubramanian geni_se_resources_off(&port->se); 997c4f52879SKarthikeyan Ramasubramanian } 998c4f52879SKarthikeyan Ramasubramanian 999c4f52879SKarthikeyan Ramasubramanian static const struct uart_ops qcom_geni_console_pops = { 1000c4f52879SKarthikeyan Ramasubramanian .tx_empty = qcom_geni_serial_tx_empty, 1001c4f52879SKarthikeyan Ramasubramanian .stop_tx = qcom_geni_serial_stop_tx, 1002c4f52879SKarthikeyan Ramasubramanian .start_tx = qcom_geni_serial_start_tx, 1003c4f52879SKarthikeyan Ramasubramanian .stop_rx = qcom_geni_serial_stop_rx, 1004c4f52879SKarthikeyan Ramasubramanian .set_termios = qcom_geni_serial_set_termios, 1005c4f52879SKarthikeyan Ramasubramanian .startup = qcom_geni_serial_startup, 1006c4f52879SKarthikeyan Ramasubramanian .request_port = qcom_geni_serial_request_port, 1007c4f52879SKarthikeyan Ramasubramanian .config_port = qcom_geni_serial_config_port, 1008c4f52879SKarthikeyan Ramasubramanian .shutdown = qcom_geni_serial_shutdown, 1009c4f52879SKarthikeyan Ramasubramanian .type = qcom_geni_serial_get_type, 1010c4f52879SKarthikeyan Ramasubramanian .set_mctrl = qcom_geni_cons_set_mctrl, 1011c4f52879SKarthikeyan Ramasubramanian .get_mctrl = qcom_geni_cons_get_mctrl, 1012c4f52879SKarthikeyan Ramasubramanian #ifdef CONFIG_CONSOLE_POLL 1013c4f52879SKarthikeyan Ramasubramanian .poll_get_char = qcom_geni_serial_get_char, 1014c4f52879SKarthikeyan Ramasubramanian .poll_put_char = qcom_geni_serial_poll_put_char, 1015c4f52879SKarthikeyan Ramasubramanian #endif 1016c4f52879SKarthikeyan Ramasubramanian .pm = qcom_geni_serial_cons_pm, 1017c4f52879SKarthikeyan Ramasubramanian }; 1018c4f52879SKarthikeyan Ramasubramanian 1019c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_probe(struct platform_device *pdev) 1020c4f52879SKarthikeyan Ramasubramanian { 1021c4f52879SKarthikeyan Ramasubramanian int ret = 0; 1022c4f52879SKarthikeyan Ramasubramanian int line = -1; 1023c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port; 1024c4f52879SKarthikeyan Ramasubramanian struct uart_port *uport; 1025c4f52879SKarthikeyan Ramasubramanian struct resource *res; 1026066cd1c4SKarthikeyan Ramasubramanian int irq; 1027c4f52879SKarthikeyan Ramasubramanian 1028c4f52879SKarthikeyan Ramasubramanian if (pdev->dev.of_node) 1029c4f52879SKarthikeyan Ramasubramanian line = of_alias_get_id(pdev->dev.of_node, "serial"); 1030c4f52879SKarthikeyan Ramasubramanian 1031c4f52879SKarthikeyan Ramasubramanian if (line < 0 || line >= GENI_UART_CONS_PORTS) 1032c4f52879SKarthikeyan Ramasubramanian return -ENXIO; 1033c4f52879SKarthikeyan Ramasubramanian port = get_port_from_line(line); 1034c4f52879SKarthikeyan Ramasubramanian if (IS_ERR(port)) { 10356a10635eSKarthikeyan Ramasubramanian dev_err(&pdev->dev, "Invalid line %d\n", line); 10366a10635eSKarthikeyan Ramasubramanian return PTR_ERR(port); 1037c4f52879SKarthikeyan Ramasubramanian } 1038c4f52879SKarthikeyan Ramasubramanian 1039c4f52879SKarthikeyan Ramasubramanian uport = &port->uport; 1040c4f52879SKarthikeyan Ramasubramanian /* Don't allow 2 drivers to access the same port */ 1041c4f52879SKarthikeyan Ramasubramanian if (uport->private_data) 1042c4f52879SKarthikeyan Ramasubramanian return -ENODEV; 1043c4f52879SKarthikeyan Ramasubramanian 1044c4f52879SKarthikeyan Ramasubramanian uport->dev = &pdev->dev; 1045c4f52879SKarthikeyan Ramasubramanian port->se.dev = &pdev->dev; 1046c4f52879SKarthikeyan Ramasubramanian port->se.wrapper = dev_get_drvdata(pdev->dev.parent); 1047c4f52879SKarthikeyan Ramasubramanian port->se.clk = devm_clk_get(&pdev->dev, "se"); 1048c4f52879SKarthikeyan Ramasubramanian if (IS_ERR(port->se.clk)) { 1049c4f52879SKarthikeyan Ramasubramanian ret = PTR_ERR(port->se.clk); 1050c4f52879SKarthikeyan Ramasubramanian dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret); 1051c4f52879SKarthikeyan Ramasubramanian return ret; 1052c4f52879SKarthikeyan Ramasubramanian } 1053c4f52879SKarthikeyan Ramasubramanian 1054c4f52879SKarthikeyan Ramasubramanian res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10557693b331SWei Yongjun if (!res) 10567693b331SWei Yongjun return -EINVAL; 1057c4f52879SKarthikeyan Ramasubramanian uport->mapbase = res->start; 1058c4f52879SKarthikeyan Ramasubramanian 1059c4f52879SKarthikeyan Ramasubramanian port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS; 1060c4f52879SKarthikeyan Ramasubramanian port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS; 1061c4f52879SKarthikeyan Ramasubramanian port->tx_fifo_width = DEF_FIFO_WIDTH_BITS; 1062c4f52879SKarthikeyan Ramasubramanian 1063066cd1c4SKarthikeyan Ramasubramanian irq = platform_get_irq(pdev, 0); 1064066cd1c4SKarthikeyan Ramasubramanian if (irq < 0) { 1065066cd1c4SKarthikeyan Ramasubramanian dev_err(&pdev->dev, "Failed to get IRQ %d\n", irq); 1066066cd1c4SKarthikeyan Ramasubramanian return irq; 1067c4f52879SKarthikeyan Ramasubramanian } 1068066cd1c4SKarthikeyan Ramasubramanian uport->irq = irq; 1069c4f52879SKarthikeyan Ramasubramanian 1070c4f52879SKarthikeyan Ramasubramanian uport->private_data = &qcom_geni_console_driver; 1071c4f52879SKarthikeyan Ramasubramanian platform_set_drvdata(pdev, port); 1072c4f52879SKarthikeyan Ramasubramanian port->handle_rx = handle_rx_console; 1073c4f52879SKarthikeyan Ramasubramanian return uart_add_one_port(&qcom_geni_console_driver, uport); 1074c4f52879SKarthikeyan Ramasubramanian } 1075c4f52879SKarthikeyan Ramasubramanian 1076c4f52879SKarthikeyan Ramasubramanian static int qcom_geni_serial_remove(struct platform_device *pdev) 1077c4f52879SKarthikeyan Ramasubramanian { 1078c4f52879SKarthikeyan Ramasubramanian struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); 1079c4f52879SKarthikeyan Ramasubramanian struct uart_driver *drv = port->uport.private_data; 1080c4f52879SKarthikeyan Ramasubramanian 1081c4f52879SKarthikeyan Ramasubramanian uart_remove_one_port(drv, &port->uport); 1082c4f52879SKarthikeyan Ramasubramanian return 0; 1083c4f52879SKarthikeyan Ramasubramanian } 1084c4f52879SKarthikeyan Ramasubramanian 1085c4f52879SKarthikeyan Ramasubramanian static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev) 1086c4f52879SKarthikeyan Ramasubramanian { 1087a406c4b8SWolfram Sang struct qcom_geni_serial_port *port = dev_get_drvdata(dev); 1088c4f52879SKarthikeyan Ramasubramanian struct uart_port *uport = &port->uport; 1089c4f52879SKarthikeyan Ramasubramanian 1090c4f52879SKarthikeyan Ramasubramanian uart_suspend_port(uport->private_data, uport); 1091c4f52879SKarthikeyan Ramasubramanian return 0; 1092c4f52879SKarthikeyan Ramasubramanian } 1093c4f52879SKarthikeyan Ramasubramanian 1094c4f52879SKarthikeyan Ramasubramanian static int __maybe_unused qcom_geni_serial_sys_resume_noirq(struct device *dev) 1095c4f52879SKarthikeyan Ramasubramanian { 1096a406c4b8SWolfram Sang struct qcom_geni_serial_port *port = dev_get_drvdata(dev); 1097c4f52879SKarthikeyan Ramasubramanian struct uart_port *uport = &port->uport; 1098c4f52879SKarthikeyan Ramasubramanian 1099c4f52879SKarthikeyan Ramasubramanian if (console_suspend_enabled && uport->suspended) { 1100c4f52879SKarthikeyan Ramasubramanian uart_resume_port(uport->private_data, uport); 1101f0262568SKarthikeyan Ramasubramanian /* 1102f0262568SKarthikeyan Ramasubramanian * uart_suspend_port() invokes port shutdown which in turn 1103f0262568SKarthikeyan Ramasubramanian * frees the irq. uart_resume_port invokes port startup which 1104f0262568SKarthikeyan Ramasubramanian * performs request_irq. The request_irq auto-enables the IRQ. 1105f0262568SKarthikeyan Ramasubramanian * In addition, resume_noirq implicitly enables the IRQ and 1106f0262568SKarthikeyan Ramasubramanian * leads to an unbalanced IRQ enable warning. Disable the IRQ 1107f0262568SKarthikeyan Ramasubramanian * before returning so that the warning is suppressed. 1108f0262568SKarthikeyan Ramasubramanian */ 1109c4f52879SKarthikeyan Ramasubramanian disable_irq(uport->irq); 1110c4f52879SKarthikeyan Ramasubramanian } 1111c4f52879SKarthikeyan Ramasubramanian return 0; 1112c4f52879SKarthikeyan Ramasubramanian } 1113c4f52879SKarthikeyan Ramasubramanian 1114c4f52879SKarthikeyan Ramasubramanian static const struct dev_pm_ops qcom_geni_serial_pm_ops = { 1115c4f52879SKarthikeyan Ramasubramanian SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend_noirq, 1116c4f52879SKarthikeyan Ramasubramanian qcom_geni_serial_sys_resume_noirq) 1117c4f52879SKarthikeyan Ramasubramanian }; 1118c4f52879SKarthikeyan Ramasubramanian 1119c4f52879SKarthikeyan Ramasubramanian static const struct of_device_id qcom_geni_serial_match_table[] = { 1120c4f52879SKarthikeyan Ramasubramanian { .compatible = "qcom,geni-debug-uart", }, 1121c4f52879SKarthikeyan Ramasubramanian {} 1122c4f52879SKarthikeyan Ramasubramanian }; 1123c4f52879SKarthikeyan Ramasubramanian MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table); 1124c4f52879SKarthikeyan Ramasubramanian 1125c4f52879SKarthikeyan Ramasubramanian static struct platform_driver qcom_geni_serial_platform_driver = { 1126c4f52879SKarthikeyan Ramasubramanian .remove = qcom_geni_serial_remove, 1127c4f52879SKarthikeyan Ramasubramanian .probe = qcom_geni_serial_probe, 1128c4f52879SKarthikeyan Ramasubramanian .driver = { 1129c4f52879SKarthikeyan Ramasubramanian .name = "qcom_geni_serial", 1130c4f52879SKarthikeyan Ramasubramanian .of_match_table = qcom_geni_serial_match_table, 1131c4f52879SKarthikeyan Ramasubramanian .pm = &qcom_geni_serial_pm_ops, 1132c4f52879SKarthikeyan Ramasubramanian }, 1133c4f52879SKarthikeyan Ramasubramanian }; 1134c4f52879SKarthikeyan Ramasubramanian 1135c4f52879SKarthikeyan Ramasubramanian static int __init qcom_geni_serial_init(void) 1136c4f52879SKarthikeyan Ramasubramanian { 1137c4f52879SKarthikeyan Ramasubramanian int ret; 1138c4f52879SKarthikeyan Ramasubramanian 1139c4f52879SKarthikeyan Ramasubramanian ret = console_register(&qcom_geni_console_driver); 1140c4f52879SKarthikeyan Ramasubramanian if (ret) 1141c4f52879SKarthikeyan Ramasubramanian return ret; 1142c4f52879SKarthikeyan Ramasubramanian 1143c4f52879SKarthikeyan Ramasubramanian ret = platform_driver_register(&qcom_geni_serial_platform_driver); 1144c4f52879SKarthikeyan Ramasubramanian if (ret) 1145c4f52879SKarthikeyan Ramasubramanian console_unregister(&qcom_geni_console_driver); 1146c4f52879SKarthikeyan Ramasubramanian return ret; 1147c4f52879SKarthikeyan Ramasubramanian } 1148c4f52879SKarthikeyan Ramasubramanian module_init(qcom_geni_serial_init); 1149c4f52879SKarthikeyan Ramasubramanian 1150c4f52879SKarthikeyan Ramasubramanian static void __exit qcom_geni_serial_exit(void) 1151c4f52879SKarthikeyan Ramasubramanian { 1152c4f52879SKarthikeyan Ramasubramanian platform_driver_unregister(&qcom_geni_serial_platform_driver); 1153c4f52879SKarthikeyan Ramasubramanian console_unregister(&qcom_geni_console_driver); 1154c4f52879SKarthikeyan Ramasubramanian } 1155c4f52879SKarthikeyan Ramasubramanian module_exit(qcom_geni_serial_exit); 1156c4f52879SKarthikeyan Ramasubramanian 1157c4f52879SKarthikeyan Ramasubramanian MODULE_DESCRIPTION("Serial driver for GENI based QUP cores"); 1158c4f52879SKarthikeyan Ramasubramanian MODULE_LICENSE("GPL v2"); 1159