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