Loading drivers/tty/serial/msm_geni_serial.c +332 −92 Original line number Diff line number Diff line Loading @@ -109,7 +109,7 @@ #define UART_CONSOLE_CORE2X_VOTE (960) #define WAKEBYTE_TIMEOUT_MSEC (2000) #define WAIT_XFER_MAX_ITER (50) #define WAIT_XFER_MAX_ITER (2) #define WAIT_XFER_MAX_TIMEOUT_US (10000) #define WAIT_XFER_MIN_TIMEOUT_US (9000) #define IPC_LOG_PWR_PAGES (6) Loading @@ -121,7 +121,15 @@ #define DMA_RX_BUF_SIZE (2048) #define UART_CONSOLE_RX_WM (2) #define QUP_VER (0x20050000) struct msm_geni_serial_ver_info { int hw_major_ver; int hw_minor_ver; int hw_step_ver; int m_fw_ver; int s_fw_ver; }; struct msm_geni_serial_port { struct uart_port uport; char name[20]; Loading Loading @@ -154,10 +162,14 @@ struct msm_geni_serial_port { void *ipc_log_rx; void *ipc_log_pwr; void *ipc_log_misc; void *console_log; unsigned int cur_baud; int ioctl_count; int edge_count; bool manual_flow; struct msm_geni_serial_ver_info ver_info; u32 cur_tx_remaining; bool startup_in_progress; }; static const struct uart_ops msm_geni_serial_pops; Loading @@ -181,8 +193,8 @@ static int msm_geni_serial_poll_bit(struct uart_port *uport, static void msm_geni_serial_stop_rx(struct uart_port *uport); static int msm_geni_serial_runtime_resume(struct device *dev); static int msm_geni_serial_runtime_suspend(struct device *dev); static atomic_t uart_line_id = ATOMIC_INIT(0); static int msm_geni_serial_get_ver_info(struct uart_port *uport); static int uart_line_id; #define GET_DEV_PORT(uport) \ container_of(uport, struct msm_geni_serial_port, uport) Loading @@ -190,11 +202,6 @@ static atomic_t uart_line_id = ATOMIC_INIT(0); static struct msm_geni_serial_port msm_geni_console_port; static struct msm_geni_serial_port msm_geni_serial_ports[GENI_UART_NR_PORTS]; static int hw_version_info(void __iomem *base_addr) { return geni_read_reg(base_addr, QUPV3_HW_VER); } static void msm_geni_serial_config_port(struct uart_port *uport, int cfg_flags) { if (cfg_flags & UART_CONFIG_TYPE) Loading Loading @@ -313,7 +320,7 @@ static void wait_for_transfers_inflight(struct uart_port *uport) static int vote_clock_on(struct uart_port *uport) { struct msm_geni_serial_port *port = GET_DEV_PORT(uport); int usage_count = atomic_read(&uport->dev->power.usage_count); int usage_count; int ret = 0; ret = msm_geni_serial_power_on(uport); Loading @@ -322,15 +329,18 @@ static int vote_clock_on(struct uart_port *uport) return ret; } port->ioctl_count++; IPC_LOG_MSG(port->ipc_log_pwr, "%s%s ioctl %d usage_count %d\n", __func__, current->comm, port->ioctl_count, usage_count); usage_count = atomic_read(&uport->dev->power.usage_count); IPC_LOG_MSG(port->ipc_log_pwr, "%s :%s ioctl:%d usage_count:%d edge-Count:%d\n", __func__, current->comm, port->ioctl_count, usage_count, port->edge_count); return 0; } static int vote_clock_off(struct uart_port *uport) { struct msm_geni_serial_port *port = GET_DEV_PORT(uport); int usage_count = atomic_read(&uport->dev->power.usage_count); int usage_count; if (!pm_runtime_enabled(uport->dev)) { dev_err(uport->dev, "RPM not available.Can't enable clocks\n"); Loading @@ -347,7 +357,8 @@ static int vote_clock_off(struct uart_port *uport) wait_for_transfers_inflight(uport); port->ioctl_count--; msm_geni_serial_power_off(uport); IPC_LOG_MSG(port->ipc_log_pwr, "%s%s ioctl %d usage_count %d\n", usage_count = atomic_read(&uport->dev->power.usage_count); IPC_LOG_MSG(port->ipc_log_pwr, "%s:%s ioctl:%d usage_count:%d\n", __func__, current->comm, port->ioctl_count, usage_count); return 0; }; Loading Loading @@ -382,7 +393,8 @@ static void msm_geni_serial_break_ctl(struct uart_port *uport, int ctl) if (!uart_console(uport) && device_pending_suspend(uport)) { IPC_LOG_MSG(port->ipc_log_misc, "%s.Device is suspended.\n", __func__); "%s.Device is suspended, %s\n", __func__, current->comm); return; } Loading @@ -405,9 +417,14 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport) { u32 geni_ios = 0; unsigned int mctrl = TIOCM_DSR | TIOCM_CAR; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); if (device_pending_suspend(uport)) if (!uart_console(uport) && device_pending_suspend(uport)) { IPC_LOG_MSG(port->ipc_log_misc, "%s.Device is suspended, %s\n", __func__, current->comm); return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; } geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) Loading @@ -429,7 +446,8 @@ static void msm_geni_serial_set_mctrl(struct uart_port *uport, if (device_pending_suspend(uport)) { IPC_LOG_MSG(port->ipc_log_misc, "%s.Device is suspended.\n", __func__); "%s.Device is suspended, %s: mctrl=0x%x\n", __func__, current->comm, mctrl); return; } if (!(mctrl & TIOCM_RTS)) { Loading @@ -442,6 +460,10 @@ static void msm_geni_serial_set_mctrl(struct uart_port *uport, SE_UART_MANUAL_RFR); /* Write to flow control must complete before return to client*/ mb(); IPC_LOG_MSG(port->ipc_log_misc, "%s:%s, mctrl=0x%x, manual_rfr=0x%x, flow=%s\n", __func__, current->comm, mctrl, uart_manual_rfr, (port->manual_flow ? "OFF" : "ON")); } static const char *msm_geni_serial_get_type(struct uart_port *uport) Loading @@ -455,8 +477,9 @@ static struct msm_geni_serial_port *get_port_from_line(int line, struct msm_geni_serial_port *port = NULL; if (is_console) { /* Max 1 port supported as of now */ if ((line < 0) || (line >= GENI_UART_CONS_PORTS)) port = ERR_PTR(-ENXIO); return ERR_PTR(-ENXIO); port = &msm_geni_console_port; } else { if ((line < 0) || (line >= GENI_UART_NR_PORTS)) Loading Loading @@ -747,10 +770,13 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, { struct uart_port *uport; struct msm_geni_serial_port *port; int locked = 1; bool locked = true; unsigned long flags; unsigned int geni_status; int irq_en; WARN_ON(co->index < 0 || co->index >= GENI_UART_NR_PORTS); /* Max 1 port supported as of now */ WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS); port = get_port_from_line(co->index, true); if (IS_ERR_OR_NULL(port)) Loading @@ -762,11 +788,45 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, else spin_lock_irqsave(&uport->lock, flags); if (locked) { geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); /* Cancel the current write to log the fault */ if (!locked) { geni_cancel_m_cmd(uport->membase); if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_CANCEL_EN, true)) { geni_abort_m_cmd(uport->membase); msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); geni_write_reg_nolog(M_CMD_ABORT_EN, uport->membase, SE_GENI_M_IRQ_CLEAR); } writel_relaxed(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->cur_tx_remaining) { /* It seems we can interrupt existing transfers unless all data * has been sent, in which case we need to look for done first. */ msm_geni_serial_poll_cancel_tx(uport); /* Enable WM interrupt for every new console write op */ if (uart_circ_chars_pending(&uport->state->xmit)) { irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); geni_write_reg_nolog(irq_en | M_TX_FIFO_WATERMARK_EN, uport->membase, SE_GENI_M_IRQ_EN); } } __msm_geni_serial_console_write(uport, s, count); if (port->cur_tx_remaining) msm_geni_serial_setup_tx(uport, port->cur_tx_remaining); if (locked) spin_unlock_irqrestore(&uport->lock, flags); } } static int handle_rx_console(struct uart_port *uport, unsigned int rx_fifo_wc, Loading Loading @@ -871,6 +931,7 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned int geni_status; unsigned int geni_ios; static unsigned int ios_log_limit; if (!uart_console(uport) && !pm_runtime_active(uport->dev)) { IPC_LOG_MSG(msm_port->ipc_log_misc, Loading Loading @@ -913,9 +974,11 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) return; check_flow_ctrl: geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) if (++ios_log_limit % 5 == 0) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: ios: 0x%08x\n", __func__, geni_ios); ios_log_limit = 0; } exit_start_tx: if (!uart_console(uport)) msm_geni_serial_power_off(uport); Loading Loading @@ -1015,9 +1078,25 @@ static void start_rx_sequencer(struct uart_port *uport) int ret; u32 geni_se_param = UART_PARAM_RFR_OPEN; if (port->startup_in_progress) return; geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); if (geni_status & S_GENI_CMD_ACTIVE) if (geni_status & S_GENI_CMD_ACTIVE) { if (port->xfer_mode == SE_DMA && !port->rx_dma) { IPC_LOG_MSG(port->ipc_log_misc, "%s: GENI: 0x%x\n", __func__, geni_status); ret = geni_se_rx_dma_prep(port->wrapper_dev, uport->membase, port->rx_buf, DMA_RX_BUF_SIZE, &port->rx_dma); if (ret) { IPC_LOG_MSG(port->ipc_log_misc, "%s: RX buff Fail %d\n", __func__, ret); goto exit_start_rx_sequencer; } } msm_geni_serial_stop_rx(uport); } /* Start RX with the RFR_OPEN to keep RFR in always ready state */ geni_setup_s_cmd(uport->membase, UART_START_READ, geni_se_param); Loading Loading @@ -1050,9 +1129,10 @@ static void start_rx_sequencer(struct uart_port *uport) * go through. */ mb(); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); exit_start_rx_sequencer: IPC_LOG_MSG(port->ipc_log_misc, "%s 0x%x\n", __func__, geni_status); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x, dma_dbg:0x%x\n", __func__, geni_status, geni_read_reg(uport->membase, SE_DMA_DEBUG_REG0)); } static void msm_geni_serial_start_rx(struct uart_port *uport) Loading Loading @@ -1088,6 +1168,38 @@ static void msm_geni_serial_rx_fsm_rst(struct uart_port *uport) geni_write_reg_nolog(rx_irq_en, uport->membase, SE_DMA_RX_IRQ_EN_SET); } static void msm_geni_serial_set_manual_flow(bool enable, struct msm_geni_serial_port *port) { u32 uart_manual_rfr = 0; if (!enable) { uart_manual_rfr |= (UART_MANUAL_RFR_EN); geni_write_reg_nolog(uart_manual_rfr, port->uport.membase, SE_UART_MANUAL_RFR); /* UART FW needs delay per HW experts recommendation */ udelay(10); uart_manual_rfr |= (UART_RFR_NOT_READY); geni_write_reg_nolog(uart_manual_rfr, port->uport.membase, SE_UART_MANUAL_RFR); /* * Ensure that the manual flow on writes go through before * doing a stop_rx. */ mb(); IPC_LOG_MSG(port->ipc_log_pwr, "%s: Manual Flow Enabled, HW Flow OFF\n", __func__); } else { geni_write_reg_nolog(0, port->uport.membase, SE_UART_MANUAL_RFR); /* Ensure that the manual flow off writes go through */ mb(); IPC_LOG_MSG(port->ipc_log_pwr, "%s: Manual Flow Disabled, HW Flow ON\n", __func__); } } static void stop_rx_sequencer(struct uart_port *uport) { unsigned int geni_s_irq_en; Loading Loading @@ -1150,6 +1262,8 @@ static void stop_rx_sequencer(struct uart_port *uport) DMA_RX_BUF_SIZE); port->rx_dma = (dma_addr_t)NULL; } geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x\n", __func__, geni_status); } static void msm_geni_serial_stop_rx(struct uart_port *uport) Loading Loading @@ -1223,40 +1337,59 @@ static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx) return ret; } static int msm_geni_serial_handle_tx(struct uart_port *uport) static int msm_geni_serial_handle_tx(struct uart_port *uport, bool done, bool active) { struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); struct circ_buf *xmit = &uport->state->xmit; unsigned int avail_fifo_bytes = 0; int avail_fifo_bytes = 0; unsigned int bytes_remaining = 0; unsigned int pending; int i = 0; unsigned int tx_fifo_status; unsigned int xmit_size; unsigned int fifo_width_bytes = (uart_console(uport) ? 1 : (msm_port->tx_fifo_width >> 3)); int temp_tail = 0; int irq_en; xmit_size = uart_circ_chars_pending(xmit); tx_fifo_status = geni_read_reg_nolog(uport->membase, SE_GENI_TX_FIFO_STATUS); /* Both FIFO and framework buffer are drained */ if (!xmit_size && !tx_fifo_status) { /* Complete the current tx command before taking newly added data */ if (active) pending = msm_port->cur_tx_remaining; else pending = uart_circ_chars_pending(xmit); /* All data has been transmitted and acknowledged as received */ if (!pending && !tx_fifo_status && done) { msm_geni_serial_stop_tx(uport); goto exit_handle_tx; } avail_fifo_bytes = (msm_port->tx_fifo_depth - msm_port->tx_wm) * fifo_width_bytes; temp_tail = xmit->tail & (UART_XMIT_SIZE - 1); avail_fifo_bytes = msm_port->tx_fifo_depth - (tx_fifo_status & TX_FIFO_WC); avail_fifo_bytes *= fifo_width_bytes; if (avail_fifo_bytes < 0) avail_fifo_bytes = 0; if (xmit_size > (UART_XMIT_SIZE - temp_tail)) xmit_size = (UART_XMIT_SIZE - temp_tail); if (xmit_size > avail_fifo_bytes) xmit_size = avail_fifo_bytes; temp_tail = xmit->tail; xmit_size = min_t(unsigned int, avail_fifo_bytes, pending); if (!xmit_size) goto exit_handle_tx; msm_geni_serial_setup_tx(uport, xmit_size); if (!msm_port->cur_tx_remaining) { msm_geni_serial_setup_tx(uport, pending); msm_port->cur_tx_remaining = pending; /* Re-enable WM interrupt when starting new transfer */ irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); if (!(irq_en & M_TX_FIFO_WATERMARK_EN)) geni_write_reg_nolog(irq_en | M_TX_FIFO_WATERMARK_EN, uport->membase, SE_GENI_M_IRQ_EN); } bytes_remaining = xmit_size; while (i < xmit_size) { unsigned int tx_bytes; Loading @@ -1266,20 +1399,39 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport) tx_bytes = ((bytes_remaining < fifo_width_bytes) ? bytes_remaining : fifo_width_bytes); for (c = 0; c < tx_bytes ; c++) buf |= (xmit->buf[temp_tail + c] << (c * 8)); for (c = 0; c < tx_bytes ; c++) { buf |= (xmit->buf[temp_tail++] << (c * 8)); temp_tail &= UART_XMIT_SIZE - 1; } geni_write_reg_nolog(buf, uport->membase, SE_GENI_TX_FIFOn); i += tx_bytes; bytes_remaining -= tx_bytes; uport->icount.tx += tx_bytes; temp_tail += tx_bytes; msm_port->cur_tx_remaining -= tx_bytes; /* Ensure FIFO write goes through */ wmb(); } xmit->tail = temp_tail & (UART_XMIT_SIZE - 1); if (uart_console(uport)) msm_geni_serial_poll_cancel_tx(uport); xmit->tail = temp_tail; /* * The tx fifo watermark is level triggered and latched. Though we had * cleared it in qcom_geni_serial_isr it will have already reasserted * so we must clear it again here after our writes. */ geni_write_reg_nolog(M_TX_FIFO_WATERMARK_EN, uport->membase, SE_GENI_M_IRQ_CLEAR); exit_handle_tx: if (!msm_port->cur_tx_remaining) { irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); /* Clear WM interrupt post each transfer completion */ if (irq_en & M_TX_FIFO_WATERMARK_EN) geni_write_reg_nolog(irq_en & ~M_TX_FIFO_WATERMARK_EN, uport->membase, SE_GENI_M_IRQ_EN); } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(uport); return 0; Loading Loading @@ -1375,13 +1527,17 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) struct uart_port *uport = dev; unsigned long flags; unsigned int m_irq_en; unsigned int geni_status; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); struct tty_port *tport = &uport->state->port; bool drop_rx = false; spin_lock_irqsave(&uport->lock, flags); if (uart_console(uport) && uport->suspended) if (uart_console(uport) && uport->suspended) { IPC_LOG_MSG(msm_port->console_log, "%s. Console in suspend state\n", __func__); goto exit_geni_serial_isr; } if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) { dev_err(uport->dev, "%s.Device is suspended.\n", __func__); IPC_LOG_MSG(msm_port->ipc_log_misc, Loading @@ -1392,10 +1548,15 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) SE_GENI_M_IRQ_STATUS); s_irq_status = geni_read_reg_nolog(uport->membase, SE_GENI_S_IRQ_STATUS); if (uart_console(uport)) IPC_LOG_MSG(msm_port->console_log, "%s. sirq 0x%x mirq:0x%x\n", __func__, s_irq_status, m_irq_status); m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); dma = geni_read_reg_nolog(uport->membase, SE_GENI_DMA_MODE_EN); dma_tx_status = geni_read_reg_nolog(uport->membase, SE_DMA_TX_IRQ_STAT); dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT); geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); geni_write_reg_nolog(m_irq_status, uport->membase, SE_GENI_M_IRQ_CLEAR); geni_write_reg_nolog(s_irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR); Loading @@ -1416,7 +1577,9 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) if (!dma) { if ((m_irq_status & m_irq_en) & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN)) msm_geni_serial_handle_tx(uport); msm_geni_serial_handle_tx(uport, m_irq_status & M_CMD_DONE_EN, geni_status & M_GENI_CMD_ACTIVE); if ((s_irq_status & S_GP_IRQ_0_EN) || (s_irq_status & S_GP_IRQ_1_EN)) { Loading Loading @@ -1557,6 +1720,7 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) { struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned long flags; int ret; /* Stop the console before stopping the current tx */ if (uart_console(uport)) { Loading Loading @@ -1585,7 +1749,13 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) } msm_port->ioctl_count = 0; } msm_geni_serial_power_off(uport); ret = pm_runtime_put_sync_suspend(uport->dev); if (ret) { IPC_LOG_MSG(msm_port->ipc_log_pwr, "%s: Failed to suspend:%d\n", __func__, ret); } if (msm_port->wakeup_irq > 0) { irq_set_irq_wake(msm_port->wakeup_irq, 0); disable_irq(msm_port->wakeup_irq); Loading Loading @@ -1679,6 +1849,8 @@ static int msm_geni_serial_startup(struct uart_port *uport) scnprintf(msm_port->name, sizeof(msm_port->name), "msm_serial_geni%d", uport->line); msm_port->startup_in_progress = true; if (likely(!uart_console(uport))) { ret = msm_geni_serial_power_on(&msm_port->uport); if (ret) { Loading @@ -1688,16 +1860,6 @@ static int msm_geni_serial_startup(struct uart_port *uport) } } if (unlikely(get_se_proto(uport->membase) != UART)) { dev_err(uport->dev, "%s: Invalid FW %d loaded.\n", __func__, get_se_proto(uport->membase)); ret = -ENXIO; goto exit_startup; } IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: FW Ver:0x%x%x\n", __func__, get_se_m_fw(uport->membase), get_se_s_fw(uport->membase)); get_tx_fifo_size(msm_port); if (!msm_port->port_setup) { if (msm_geni_serial_port_setup(uport)) Loading Loading @@ -1738,6 +1900,8 @@ static int msm_geni_serial_startup(struct uart_port *uport) exit_startup: if (likely(!uart_console(uport))) msm_geni_serial_power_off(&msm_port->uport); msm_port->startup_in_progress = false; return ret; } Loading Loading @@ -1809,9 +1973,6 @@ static int get_clk_div_rate(unsigned int baud, unsigned long *desired_clk_rate) clk_div = ser_clk / *desired_clk_rate; *desired_clk_rate = ser_clk; exit_get_clk_div_rate: if (clk_div) clk_div = clk_div*2; return clk_div; } Loading Loading @@ -1840,6 +2001,8 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, __func__, ret); return; } disable_irq(uport->irq); msm_geni_serial_set_manual_flow(false, port); } /* Take a spinlock else stop_rx causes a race with an ISR due to Cancel * and FSM_RESET. This also has a potential race with the dma_map/unmap Loading @@ -1855,7 +2018,7 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, if (clk_div <= 0) goto exit_set_termios; if (hw_version_info(uport->membase) >= QUP_VER) if (IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING)) clk_div *= 2; uport->uartclk = clk_rate; clk_set_rate(port->serial_rsc.se_clk, clk_rate); Loading Loading @@ -1935,8 +2098,8 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, if (termios->c_cflag & CRTSCTS) { geni_write_reg_nolog(0x0, uport->membase, SE_UART_MANUAL_RFR); IPC_LOG_MSG(port->ipc_log_misc, "%s: Manual flow off\n", __func__); IPC_LOG_MSG(port->ipc_log_misc, "%s: Manual flow Disabled, HW Flow ON\n", __func__); } IPC_LOG_MSG(port->ipc_log_misc, "%s: baud %d\n", __func__, baud); Loading @@ -1947,6 +2110,10 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, IPC_LOG_MSG(port->ipc_log_misc, "BitsChar%d stop bit%d\n", bits_per_char, stop_bit_len); exit_set_termios: if (!uart_console(uport)) { msm_geni_serial_set_manual_flow(true, port); enable_irq(uport->irq); } msm_geni_serial_start_rx(uport); if (!uart_console(uport)) msm_geni_serial_power_off(uport); Loading Loading @@ -1982,9 +2149,9 @@ static ssize_t xfer_mode_show(struct device *dev, ssize_t ret = 0; if (port->xfer_mode == FIFO_MODE) ret = scnprintf(buf, PAGE_SIZE, "FIFO\n"); ret = snprintf(buf, sizeof("FIFO\n"), "FIFO\n"); else if (port->xfer_mode == SE_DMA) ret = scnprintf(buf, PAGE_SIZE, "SE_DMA\n"); ret = snprintf(buf, sizeof("SE_DMA\n"), "SE_DMA\n"); return ret; } Loading Loading @@ -2028,6 +2195,23 @@ static ssize_t xfer_mode_store(struct device *dev, static DEVICE_ATTR_RW(xfer_mode); static ssize_t ver_info_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct msm_geni_serial_port *port = platform_get_drvdata(pdev); ssize_t ret = 0; int len = (sizeof(struct msm_geni_serial_ver_info) * 2); ret = snprintf(buf, len, "FW ver=0x%x%x, HW ver=%d.%d.%d\n", port->ver_info.m_fw_ver, port->ver_info.m_fw_ver, port->ver_info.hw_major_ver, port->ver_info.hw_minor_ver, port->ver_info.hw_step_ver); return ret; } static DEVICE_ATTR_RO(ver_info); #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) static int __init msm_geni_console_setup(struct console *co, char *options) { Loading @@ -2039,7 +2223,8 @@ static int __init msm_geni_console_setup(struct console *co, char *options) int flow = 'n'; int ret = 0; if (unlikely(co->index >= GENI_UART_NR_PORTS || co->index < 0)) /* Max 1 port supported as of now */ if (unlikely(co->index >= GENI_UART_CONS_PORTS || co->index < 0)) return -ENXIO; dev_port = get_port_from_line(co->index, true); Loading Loading @@ -2133,8 +2318,9 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, goto exit_geni_serial_earlyconsetup; } if (hw_version_info(uport->membase) >= QUP_VER) if (IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING)) clk_div *= 2; s_clk_cfg |= SER_CLK_EN; s_clk_cfg |= (clk_div << CLK_DIV_SHFT); Loading @@ -2143,7 +2329,6 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, * it else we could end up in data loss scenarios. */ msm_geni_serial_poll_cancel_tx(uport); msm_geni_serial_abort_rx(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); geni_se_init(uport->membase, (DEF_FIFO_DEPTH_WORDS >> 1), Loading @@ -2155,14 +2340,8 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, SE_UART_TX_TRANS_CFG); geni_write_reg_nolog(tx_parity_cfg, uport->membase, SE_UART_TX_PARITY_CFG); geni_write_reg_nolog(rx_trans_cfg, uport->membase, SE_UART_RX_TRANS_CFG); geni_write_reg_nolog(rx_parity_cfg, uport->membase, SE_UART_RX_PARITY_CFG); geni_write_reg_nolog(bits_per_char, uport->membase, SE_UART_TX_WORD_LEN); geni_write_reg_nolog(bits_per_char, uport->membase, SE_UART_RX_WORD_LEN); geni_write_reg_nolog(stop_bit, uport->membase, SE_UART_TX_STOP_BIT_LEN); geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_M_CLK_CFG); geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_S_CLK_CFG); Loading Loading @@ -2204,7 +2383,7 @@ static struct uart_driver msm_geni_console_driver = { .owner = THIS_MODULE, .driver_name = "msm_geni_console", .dev_name = "ttyMSM", .nr = GENI_UART_NR_PORTS, .nr = GENI_UART_CONS_PORTS, .cons = &cons_ops, }; #else Loading @@ -2221,14 +2400,13 @@ static void console_unregister(struct uart_driver *drv) static void msm_geni_serial_debug_init(struct uart_port *uport, bool console) { struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); char name[30]; msm_port->dbg = debugfs_create_dir(dev_name(uport->dev), NULL); if (IS_ERR_OR_NULL(msm_port->dbg)) dev_err(uport->dev, "Failed to create dbg dir\n"); if (!console) { char name[30]; memset(name, 0, sizeof(name)); if (!msm_port->ipc_log_rx) { scnprintf(name, sizeof(name), "%s%s", Loading Loading @@ -2265,6 +2443,16 @@ static void msm_geni_serial_debug_init(struct uart_port *uport, bool console) if (!msm_port->ipc_log_misc) dev_info(uport->dev, "Err in Misc IPC Log\n"); } } else { memset(name, 0, sizeof(name)); if (!msm_port->console_log) { scnprintf(name, sizeof(name), "%s%s", dev_name(uport->dev), "_console"); msm_port->console_log = ipc_log_context_create( IPC_LOG_MISC_PAGES, name, 0); if (!msm_port->console_log) dev_info(uport->dev, "Err in Misc IPC Log\n"); } } } Loading Loading @@ -2329,6 +2517,43 @@ static const struct of_device_id msm_geni_device_tbl[] = { {}, }; static int msm_geni_serial_get_ver_info(struct uart_port *uport) { int hw_ver, ret = 0; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); se_geni_clks_on(&msm_port->serial_rsc); /* Basic HW and FW info */ if (unlikely(get_se_proto(uport->membase) != UART)) { dev_err(uport->dev, "%s: Invalid FW %d loaded.\n", __func__, get_se_proto(uport->membase)); ret = -ENXIO; goto exit_ver_info; } msm_port->ver_info.m_fw_ver = get_se_m_fw(uport->membase); msm_port->ver_info.s_fw_ver = get_se_s_fw(uport->membase); IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: FW Ver:0x%x%x\n", __func__, msm_port->ver_info.m_fw_ver, msm_port->ver_info.s_fw_ver); hw_ver = geni_se_qupv3_hw_version(msm_port->wrapper_dev, &msm_port->ver_info.hw_major_ver, &msm_port->ver_info.hw_minor_ver, &msm_port->ver_info.hw_step_ver); if (hw_ver) dev_err(uport->dev, "%s:Err getting HW version %d\n", __func__, hw_ver); else IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: HW Ver:%x.%x.%x\n", __func__, msm_port->ver_info.hw_major_ver, msm_port->ver_info.hw_minor_ver, msm_port->ver_info.hw_step_ver); exit_ver_info: se_geni_clks_off(&msm_port->serial_rsc); return ret; } static int msm_geni_serial_probe(struct platform_device *pdev) { int ret = 0; Loading @@ -2354,19 +2579,21 @@ static int msm_geni_serial_probe(struct platform_device *pdev) } if (pdev->dev.of_node) { if (drv->cons) if (drv->cons) { line = of_alias_get_id(pdev->dev.of_node, "serial"); else if (line < 0) line = 0; } else { line = of_alias_get_id(pdev->dev.of_node, "hsuart"); if (line < 0) line = uart_line_id++; else uart_line_id++; } } else { line = pdev->id; } if (line < 0) line = atomic_inc_return(&uart_line_id) - 1; if ((line < 0) || (line >= GENI_UART_NR_PORTS)) return -ENXIO; is_console = (drv->cons ? true : false); dev_port = get_port_from_line(line, is_console); if (IS_ERR_OR_NULL(dev_port)) { Loading Loading @@ -2473,6 +2700,15 @@ static int msm_geni_serial_probe(struct platform_device *pdev) ret = PTR_ERR(dev_port->serial_rsc.geni_pinctrl); goto exit_geni_serial_probe; } dev_port->serial_rsc.geni_gpio_active = pinctrl_lookup_state(dev_port->serial_rsc.geni_pinctrl, PINCTRL_ACTIVE); if (IS_ERR_OR_NULL(dev_port->serial_rsc.geni_gpio_active)) { /* * Backward compatible : In case few chips doesn't have ACTIVE * state defined. */ dev_port->serial_rsc.geni_gpio_active = pinctrl_lookup_state(dev_port->serial_rsc.geni_pinctrl, PINCTRL_DEFAULT); Loading @@ -2481,7 +2717,7 @@ static int msm_geni_serial_probe(struct platform_device *pdev) ret = PTR_ERR(dev_port->serial_rsc.geni_gpio_active); goto exit_geni_serial_probe; } } /* * For clients who setup an Inband wakeup, leave the GPIO pins * always connected to the core, else move the pins to their Loading Loading @@ -2542,8 +2778,12 @@ static int msm_geni_serial_probe(struct platform_device *pdev) line, uport->fifosize, is_console); device_create_file(uport->dev, &dev_attr_loopback); device_create_file(uport->dev, &dev_attr_xfer_mode); device_create_file(uport->dev, &dev_attr_ver_info); msm_geni_serial_debug_init(uport, is_console); dev_port->port_setup = false; ret = msm_geni_serial_get_ver_info(uport); if (ret) goto exit_geni_serial_probe; return uart_add_one_port(drv, uport); exit_geni_serial_probe: Loading Loading
drivers/tty/serial/msm_geni_serial.c +332 −92 Original line number Diff line number Diff line Loading @@ -109,7 +109,7 @@ #define UART_CONSOLE_CORE2X_VOTE (960) #define WAKEBYTE_TIMEOUT_MSEC (2000) #define WAIT_XFER_MAX_ITER (50) #define WAIT_XFER_MAX_ITER (2) #define WAIT_XFER_MAX_TIMEOUT_US (10000) #define WAIT_XFER_MIN_TIMEOUT_US (9000) #define IPC_LOG_PWR_PAGES (6) Loading @@ -121,7 +121,15 @@ #define DMA_RX_BUF_SIZE (2048) #define UART_CONSOLE_RX_WM (2) #define QUP_VER (0x20050000) struct msm_geni_serial_ver_info { int hw_major_ver; int hw_minor_ver; int hw_step_ver; int m_fw_ver; int s_fw_ver; }; struct msm_geni_serial_port { struct uart_port uport; char name[20]; Loading Loading @@ -154,10 +162,14 @@ struct msm_geni_serial_port { void *ipc_log_rx; void *ipc_log_pwr; void *ipc_log_misc; void *console_log; unsigned int cur_baud; int ioctl_count; int edge_count; bool manual_flow; struct msm_geni_serial_ver_info ver_info; u32 cur_tx_remaining; bool startup_in_progress; }; static const struct uart_ops msm_geni_serial_pops; Loading @@ -181,8 +193,8 @@ static int msm_geni_serial_poll_bit(struct uart_port *uport, static void msm_geni_serial_stop_rx(struct uart_port *uport); static int msm_geni_serial_runtime_resume(struct device *dev); static int msm_geni_serial_runtime_suspend(struct device *dev); static atomic_t uart_line_id = ATOMIC_INIT(0); static int msm_geni_serial_get_ver_info(struct uart_port *uport); static int uart_line_id; #define GET_DEV_PORT(uport) \ container_of(uport, struct msm_geni_serial_port, uport) Loading @@ -190,11 +202,6 @@ static atomic_t uart_line_id = ATOMIC_INIT(0); static struct msm_geni_serial_port msm_geni_console_port; static struct msm_geni_serial_port msm_geni_serial_ports[GENI_UART_NR_PORTS]; static int hw_version_info(void __iomem *base_addr) { return geni_read_reg(base_addr, QUPV3_HW_VER); } static void msm_geni_serial_config_port(struct uart_port *uport, int cfg_flags) { if (cfg_flags & UART_CONFIG_TYPE) Loading Loading @@ -313,7 +320,7 @@ static void wait_for_transfers_inflight(struct uart_port *uport) static int vote_clock_on(struct uart_port *uport) { struct msm_geni_serial_port *port = GET_DEV_PORT(uport); int usage_count = atomic_read(&uport->dev->power.usage_count); int usage_count; int ret = 0; ret = msm_geni_serial_power_on(uport); Loading @@ -322,15 +329,18 @@ static int vote_clock_on(struct uart_port *uport) return ret; } port->ioctl_count++; IPC_LOG_MSG(port->ipc_log_pwr, "%s%s ioctl %d usage_count %d\n", __func__, current->comm, port->ioctl_count, usage_count); usage_count = atomic_read(&uport->dev->power.usage_count); IPC_LOG_MSG(port->ipc_log_pwr, "%s :%s ioctl:%d usage_count:%d edge-Count:%d\n", __func__, current->comm, port->ioctl_count, usage_count, port->edge_count); return 0; } static int vote_clock_off(struct uart_port *uport) { struct msm_geni_serial_port *port = GET_DEV_PORT(uport); int usage_count = atomic_read(&uport->dev->power.usage_count); int usage_count; if (!pm_runtime_enabled(uport->dev)) { dev_err(uport->dev, "RPM not available.Can't enable clocks\n"); Loading @@ -347,7 +357,8 @@ static int vote_clock_off(struct uart_port *uport) wait_for_transfers_inflight(uport); port->ioctl_count--; msm_geni_serial_power_off(uport); IPC_LOG_MSG(port->ipc_log_pwr, "%s%s ioctl %d usage_count %d\n", usage_count = atomic_read(&uport->dev->power.usage_count); IPC_LOG_MSG(port->ipc_log_pwr, "%s:%s ioctl:%d usage_count:%d\n", __func__, current->comm, port->ioctl_count, usage_count); return 0; }; Loading Loading @@ -382,7 +393,8 @@ static void msm_geni_serial_break_ctl(struct uart_port *uport, int ctl) if (!uart_console(uport) && device_pending_suspend(uport)) { IPC_LOG_MSG(port->ipc_log_misc, "%s.Device is suspended.\n", __func__); "%s.Device is suspended, %s\n", __func__, current->comm); return; } Loading @@ -405,9 +417,14 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport) { u32 geni_ios = 0; unsigned int mctrl = TIOCM_DSR | TIOCM_CAR; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); if (device_pending_suspend(uport)) if (!uart_console(uport) && device_pending_suspend(uport)) { IPC_LOG_MSG(port->ipc_log_misc, "%s.Device is suspended, %s\n", __func__, current->comm); return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; } geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) Loading @@ -429,7 +446,8 @@ static void msm_geni_serial_set_mctrl(struct uart_port *uport, if (device_pending_suspend(uport)) { IPC_LOG_MSG(port->ipc_log_misc, "%s.Device is suspended.\n", __func__); "%s.Device is suspended, %s: mctrl=0x%x\n", __func__, current->comm, mctrl); return; } if (!(mctrl & TIOCM_RTS)) { Loading @@ -442,6 +460,10 @@ static void msm_geni_serial_set_mctrl(struct uart_port *uport, SE_UART_MANUAL_RFR); /* Write to flow control must complete before return to client*/ mb(); IPC_LOG_MSG(port->ipc_log_misc, "%s:%s, mctrl=0x%x, manual_rfr=0x%x, flow=%s\n", __func__, current->comm, mctrl, uart_manual_rfr, (port->manual_flow ? "OFF" : "ON")); } static const char *msm_geni_serial_get_type(struct uart_port *uport) Loading @@ -455,8 +477,9 @@ static struct msm_geni_serial_port *get_port_from_line(int line, struct msm_geni_serial_port *port = NULL; if (is_console) { /* Max 1 port supported as of now */ if ((line < 0) || (line >= GENI_UART_CONS_PORTS)) port = ERR_PTR(-ENXIO); return ERR_PTR(-ENXIO); port = &msm_geni_console_port; } else { if ((line < 0) || (line >= GENI_UART_NR_PORTS)) Loading Loading @@ -747,10 +770,13 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, { struct uart_port *uport; struct msm_geni_serial_port *port; int locked = 1; bool locked = true; unsigned long flags; unsigned int geni_status; int irq_en; WARN_ON(co->index < 0 || co->index >= GENI_UART_NR_PORTS); /* Max 1 port supported as of now */ WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS); port = get_port_from_line(co->index, true); if (IS_ERR_OR_NULL(port)) Loading @@ -762,11 +788,45 @@ static void msm_geni_serial_console_write(struct console *co, const char *s, else spin_lock_irqsave(&uport->lock, flags); if (locked) { geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); /* Cancel the current write to log the fault */ if (!locked) { geni_cancel_m_cmd(uport->membase); if (!msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_CANCEL_EN, true)) { geni_abort_m_cmd(uport->membase); msm_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); geni_write_reg_nolog(M_CMD_ABORT_EN, uport->membase, SE_GENI_M_IRQ_CLEAR); } writel_relaxed(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->cur_tx_remaining) { /* It seems we can interrupt existing transfers unless all data * has been sent, in which case we need to look for done first. */ msm_geni_serial_poll_cancel_tx(uport); /* Enable WM interrupt for every new console write op */ if (uart_circ_chars_pending(&uport->state->xmit)) { irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); geni_write_reg_nolog(irq_en | M_TX_FIFO_WATERMARK_EN, uport->membase, SE_GENI_M_IRQ_EN); } } __msm_geni_serial_console_write(uport, s, count); if (port->cur_tx_remaining) msm_geni_serial_setup_tx(uport, port->cur_tx_remaining); if (locked) spin_unlock_irqrestore(&uport->lock, flags); } } static int handle_rx_console(struct uart_port *uport, unsigned int rx_fifo_wc, Loading Loading @@ -871,6 +931,7 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned int geni_status; unsigned int geni_ios; static unsigned int ios_log_limit; if (!uart_console(uport) && !pm_runtime_active(uport->dev)) { IPC_LOG_MSG(msm_port->ipc_log_misc, Loading Loading @@ -913,9 +974,11 @@ static void msm_geni_serial_start_tx(struct uart_port *uport) return; check_flow_ctrl: geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) if (++ios_log_limit % 5 == 0) { IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: ios: 0x%08x\n", __func__, geni_ios); ios_log_limit = 0; } exit_start_tx: if (!uart_console(uport)) msm_geni_serial_power_off(uport); Loading Loading @@ -1015,9 +1078,25 @@ static void start_rx_sequencer(struct uart_port *uport) int ret; u32 geni_se_param = UART_PARAM_RFR_OPEN; if (port->startup_in_progress) return; geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); if (geni_status & S_GENI_CMD_ACTIVE) if (geni_status & S_GENI_CMD_ACTIVE) { if (port->xfer_mode == SE_DMA && !port->rx_dma) { IPC_LOG_MSG(port->ipc_log_misc, "%s: GENI: 0x%x\n", __func__, geni_status); ret = geni_se_rx_dma_prep(port->wrapper_dev, uport->membase, port->rx_buf, DMA_RX_BUF_SIZE, &port->rx_dma); if (ret) { IPC_LOG_MSG(port->ipc_log_misc, "%s: RX buff Fail %d\n", __func__, ret); goto exit_start_rx_sequencer; } } msm_geni_serial_stop_rx(uport); } /* Start RX with the RFR_OPEN to keep RFR in always ready state */ geni_setup_s_cmd(uport->membase, UART_START_READ, geni_se_param); Loading Loading @@ -1050,9 +1129,10 @@ static void start_rx_sequencer(struct uart_port *uport) * go through. */ mb(); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); exit_start_rx_sequencer: IPC_LOG_MSG(port->ipc_log_misc, "%s 0x%x\n", __func__, geni_status); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x, dma_dbg:0x%x\n", __func__, geni_status, geni_read_reg(uport->membase, SE_DMA_DEBUG_REG0)); } static void msm_geni_serial_start_rx(struct uart_port *uport) Loading Loading @@ -1088,6 +1168,38 @@ static void msm_geni_serial_rx_fsm_rst(struct uart_port *uport) geni_write_reg_nolog(rx_irq_en, uport->membase, SE_DMA_RX_IRQ_EN_SET); } static void msm_geni_serial_set_manual_flow(bool enable, struct msm_geni_serial_port *port) { u32 uart_manual_rfr = 0; if (!enable) { uart_manual_rfr |= (UART_MANUAL_RFR_EN); geni_write_reg_nolog(uart_manual_rfr, port->uport.membase, SE_UART_MANUAL_RFR); /* UART FW needs delay per HW experts recommendation */ udelay(10); uart_manual_rfr |= (UART_RFR_NOT_READY); geni_write_reg_nolog(uart_manual_rfr, port->uport.membase, SE_UART_MANUAL_RFR); /* * Ensure that the manual flow on writes go through before * doing a stop_rx. */ mb(); IPC_LOG_MSG(port->ipc_log_pwr, "%s: Manual Flow Enabled, HW Flow OFF\n", __func__); } else { geni_write_reg_nolog(0, port->uport.membase, SE_UART_MANUAL_RFR); /* Ensure that the manual flow off writes go through */ mb(); IPC_LOG_MSG(port->ipc_log_pwr, "%s: Manual Flow Disabled, HW Flow ON\n", __func__); } } static void stop_rx_sequencer(struct uart_port *uport) { unsigned int geni_s_irq_en; Loading Loading @@ -1150,6 +1262,8 @@ static void stop_rx_sequencer(struct uart_port *uport) DMA_RX_BUF_SIZE); port->rx_dma = (dma_addr_t)NULL; } geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x\n", __func__, geni_status); } static void msm_geni_serial_stop_rx(struct uart_port *uport) Loading Loading @@ -1223,40 +1337,59 @@ static int msm_geni_serial_handle_rx(struct uart_port *uport, bool drop_rx) return ret; } static int msm_geni_serial_handle_tx(struct uart_port *uport) static int msm_geni_serial_handle_tx(struct uart_port *uport, bool done, bool active) { struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); struct circ_buf *xmit = &uport->state->xmit; unsigned int avail_fifo_bytes = 0; int avail_fifo_bytes = 0; unsigned int bytes_remaining = 0; unsigned int pending; int i = 0; unsigned int tx_fifo_status; unsigned int xmit_size; unsigned int fifo_width_bytes = (uart_console(uport) ? 1 : (msm_port->tx_fifo_width >> 3)); int temp_tail = 0; int irq_en; xmit_size = uart_circ_chars_pending(xmit); tx_fifo_status = geni_read_reg_nolog(uport->membase, SE_GENI_TX_FIFO_STATUS); /* Both FIFO and framework buffer are drained */ if (!xmit_size && !tx_fifo_status) { /* Complete the current tx command before taking newly added data */ if (active) pending = msm_port->cur_tx_remaining; else pending = uart_circ_chars_pending(xmit); /* All data has been transmitted and acknowledged as received */ if (!pending && !tx_fifo_status && done) { msm_geni_serial_stop_tx(uport); goto exit_handle_tx; } avail_fifo_bytes = (msm_port->tx_fifo_depth - msm_port->tx_wm) * fifo_width_bytes; temp_tail = xmit->tail & (UART_XMIT_SIZE - 1); avail_fifo_bytes = msm_port->tx_fifo_depth - (tx_fifo_status & TX_FIFO_WC); avail_fifo_bytes *= fifo_width_bytes; if (avail_fifo_bytes < 0) avail_fifo_bytes = 0; if (xmit_size > (UART_XMIT_SIZE - temp_tail)) xmit_size = (UART_XMIT_SIZE - temp_tail); if (xmit_size > avail_fifo_bytes) xmit_size = avail_fifo_bytes; temp_tail = xmit->tail; xmit_size = min_t(unsigned int, avail_fifo_bytes, pending); if (!xmit_size) goto exit_handle_tx; msm_geni_serial_setup_tx(uport, xmit_size); if (!msm_port->cur_tx_remaining) { msm_geni_serial_setup_tx(uport, pending); msm_port->cur_tx_remaining = pending; /* Re-enable WM interrupt when starting new transfer */ irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); if (!(irq_en & M_TX_FIFO_WATERMARK_EN)) geni_write_reg_nolog(irq_en | M_TX_FIFO_WATERMARK_EN, uport->membase, SE_GENI_M_IRQ_EN); } bytes_remaining = xmit_size; while (i < xmit_size) { unsigned int tx_bytes; Loading @@ -1266,20 +1399,39 @@ static int msm_geni_serial_handle_tx(struct uart_port *uport) tx_bytes = ((bytes_remaining < fifo_width_bytes) ? bytes_remaining : fifo_width_bytes); for (c = 0; c < tx_bytes ; c++) buf |= (xmit->buf[temp_tail + c] << (c * 8)); for (c = 0; c < tx_bytes ; c++) { buf |= (xmit->buf[temp_tail++] << (c * 8)); temp_tail &= UART_XMIT_SIZE - 1; } geni_write_reg_nolog(buf, uport->membase, SE_GENI_TX_FIFOn); i += tx_bytes; bytes_remaining -= tx_bytes; uport->icount.tx += tx_bytes; temp_tail += tx_bytes; msm_port->cur_tx_remaining -= tx_bytes; /* Ensure FIFO write goes through */ wmb(); } xmit->tail = temp_tail & (UART_XMIT_SIZE - 1); if (uart_console(uport)) msm_geni_serial_poll_cancel_tx(uport); xmit->tail = temp_tail; /* * The tx fifo watermark is level triggered and latched. Though we had * cleared it in qcom_geni_serial_isr it will have already reasserted * so we must clear it again here after our writes. */ geni_write_reg_nolog(M_TX_FIFO_WATERMARK_EN, uport->membase, SE_GENI_M_IRQ_CLEAR); exit_handle_tx: if (!msm_port->cur_tx_remaining) { irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); /* Clear WM interrupt post each transfer completion */ if (irq_en & M_TX_FIFO_WATERMARK_EN) geni_write_reg_nolog(irq_en & ~M_TX_FIFO_WATERMARK_EN, uport->membase, SE_GENI_M_IRQ_EN); } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(uport); return 0; Loading Loading @@ -1375,13 +1527,17 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) struct uart_port *uport = dev; unsigned long flags; unsigned int m_irq_en; unsigned int geni_status; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); struct tty_port *tport = &uport->state->port; bool drop_rx = false; spin_lock_irqsave(&uport->lock, flags); if (uart_console(uport) && uport->suspended) if (uart_console(uport) && uport->suspended) { IPC_LOG_MSG(msm_port->console_log, "%s. Console in suspend state\n", __func__); goto exit_geni_serial_isr; } if (!uart_console(uport) && pm_runtime_status_suspended(uport->dev)) { dev_err(uport->dev, "%s.Device is suspended.\n", __func__); IPC_LOG_MSG(msm_port->ipc_log_misc, Loading @@ -1392,10 +1548,15 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) SE_GENI_M_IRQ_STATUS); s_irq_status = geni_read_reg_nolog(uport->membase, SE_GENI_S_IRQ_STATUS); if (uart_console(uport)) IPC_LOG_MSG(msm_port->console_log, "%s. sirq 0x%x mirq:0x%x\n", __func__, s_irq_status, m_irq_status); m_irq_en = geni_read_reg_nolog(uport->membase, SE_GENI_M_IRQ_EN); dma = geni_read_reg_nolog(uport->membase, SE_GENI_DMA_MODE_EN); dma_tx_status = geni_read_reg_nolog(uport->membase, SE_DMA_TX_IRQ_STAT); dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT); geni_status = readl_relaxed(uport->membase + SE_GENI_STATUS); geni_write_reg_nolog(m_irq_status, uport->membase, SE_GENI_M_IRQ_CLEAR); geni_write_reg_nolog(s_irq_status, uport->membase, SE_GENI_S_IRQ_CLEAR); Loading @@ -1416,7 +1577,9 @@ static irqreturn_t msm_geni_serial_isr(int isr, void *dev) if (!dma) { if ((m_irq_status & m_irq_en) & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN)) msm_geni_serial_handle_tx(uport); msm_geni_serial_handle_tx(uport, m_irq_status & M_CMD_DONE_EN, geni_status & M_GENI_CMD_ACTIVE); if ((s_irq_status & S_GP_IRQ_0_EN) || (s_irq_status & S_GP_IRQ_1_EN)) { Loading Loading @@ -1557,6 +1720,7 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) { struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned long flags; int ret; /* Stop the console before stopping the current tx */ if (uart_console(uport)) { Loading Loading @@ -1585,7 +1749,13 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) } msm_port->ioctl_count = 0; } msm_geni_serial_power_off(uport); ret = pm_runtime_put_sync_suspend(uport->dev); if (ret) { IPC_LOG_MSG(msm_port->ipc_log_pwr, "%s: Failed to suspend:%d\n", __func__, ret); } if (msm_port->wakeup_irq > 0) { irq_set_irq_wake(msm_port->wakeup_irq, 0); disable_irq(msm_port->wakeup_irq); Loading Loading @@ -1679,6 +1849,8 @@ static int msm_geni_serial_startup(struct uart_port *uport) scnprintf(msm_port->name, sizeof(msm_port->name), "msm_serial_geni%d", uport->line); msm_port->startup_in_progress = true; if (likely(!uart_console(uport))) { ret = msm_geni_serial_power_on(&msm_port->uport); if (ret) { Loading @@ -1688,16 +1860,6 @@ static int msm_geni_serial_startup(struct uart_port *uport) } } if (unlikely(get_se_proto(uport->membase) != UART)) { dev_err(uport->dev, "%s: Invalid FW %d loaded.\n", __func__, get_se_proto(uport->membase)); ret = -ENXIO; goto exit_startup; } IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: FW Ver:0x%x%x\n", __func__, get_se_m_fw(uport->membase), get_se_s_fw(uport->membase)); get_tx_fifo_size(msm_port); if (!msm_port->port_setup) { if (msm_geni_serial_port_setup(uport)) Loading Loading @@ -1738,6 +1900,8 @@ static int msm_geni_serial_startup(struct uart_port *uport) exit_startup: if (likely(!uart_console(uport))) msm_geni_serial_power_off(&msm_port->uport); msm_port->startup_in_progress = false; return ret; } Loading Loading @@ -1809,9 +1973,6 @@ static int get_clk_div_rate(unsigned int baud, unsigned long *desired_clk_rate) clk_div = ser_clk / *desired_clk_rate; *desired_clk_rate = ser_clk; exit_get_clk_div_rate: if (clk_div) clk_div = clk_div*2; return clk_div; } Loading Loading @@ -1840,6 +2001,8 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, __func__, ret); return; } disable_irq(uport->irq); msm_geni_serial_set_manual_flow(false, port); } /* Take a spinlock else stop_rx causes a race with an ISR due to Cancel * and FSM_RESET. This also has a potential race with the dma_map/unmap Loading @@ -1855,7 +2018,7 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, if (clk_div <= 0) goto exit_set_termios; if (hw_version_info(uport->membase) >= QUP_VER) if (IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING)) clk_div *= 2; uport->uartclk = clk_rate; clk_set_rate(port->serial_rsc.se_clk, clk_rate); Loading Loading @@ -1935,8 +2098,8 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, if (termios->c_cflag & CRTSCTS) { geni_write_reg_nolog(0x0, uport->membase, SE_UART_MANUAL_RFR); IPC_LOG_MSG(port->ipc_log_misc, "%s: Manual flow off\n", __func__); IPC_LOG_MSG(port->ipc_log_misc, "%s: Manual flow Disabled, HW Flow ON\n", __func__); } IPC_LOG_MSG(port->ipc_log_misc, "%s: baud %d\n", __func__, baud); Loading @@ -1947,6 +2110,10 @@ static void msm_geni_serial_set_termios(struct uart_port *uport, IPC_LOG_MSG(port->ipc_log_misc, "BitsChar%d stop bit%d\n", bits_per_char, stop_bit_len); exit_set_termios: if (!uart_console(uport)) { msm_geni_serial_set_manual_flow(true, port); enable_irq(uport->irq); } msm_geni_serial_start_rx(uport); if (!uart_console(uport)) msm_geni_serial_power_off(uport); Loading Loading @@ -1982,9 +2149,9 @@ static ssize_t xfer_mode_show(struct device *dev, ssize_t ret = 0; if (port->xfer_mode == FIFO_MODE) ret = scnprintf(buf, PAGE_SIZE, "FIFO\n"); ret = snprintf(buf, sizeof("FIFO\n"), "FIFO\n"); else if (port->xfer_mode == SE_DMA) ret = scnprintf(buf, PAGE_SIZE, "SE_DMA\n"); ret = snprintf(buf, sizeof("SE_DMA\n"), "SE_DMA\n"); return ret; } Loading Loading @@ -2028,6 +2195,23 @@ static ssize_t xfer_mode_store(struct device *dev, static DEVICE_ATTR_RW(xfer_mode); static ssize_t ver_info_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct msm_geni_serial_port *port = platform_get_drvdata(pdev); ssize_t ret = 0; int len = (sizeof(struct msm_geni_serial_ver_info) * 2); ret = snprintf(buf, len, "FW ver=0x%x%x, HW ver=%d.%d.%d\n", port->ver_info.m_fw_ver, port->ver_info.m_fw_ver, port->ver_info.hw_major_ver, port->ver_info.hw_minor_ver, port->ver_info.hw_step_ver); return ret; } static DEVICE_ATTR_RO(ver_info); #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) static int __init msm_geni_console_setup(struct console *co, char *options) { Loading @@ -2039,7 +2223,8 @@ static int __init msm_geni_console_setup(struct console *co, char *options) int flow = 'n'; int ret = 0; if (unlikely(co->index >= GENI_UART_NR_PORTS || co->index < 0)) /* Max 1 port supported as of now */ if (unlikely(co->index >= GENI_UART_CONS_PORTS || co->index < 0)) return -ENXIO; dev_port = get_port_from_line(co->index, true); Loading Loading @@ -2133,8 +2318,9 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, goto exit_geni_serial_earlyconsetup; } if (hw_version_info(uport->membase) >= QUP_VER) if (IS_ENABLED(CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING)) clk_div *= 2; s_clk_cfg |= SER_CLK_EN; s_clk_cfg |= (clk_div << CLK_DIV_SHFT); Loading @@ -2143,7 +2329,6 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, * it else we could end up in data loss scenarios. */ msm_geni_serial_poll_cancel_tx(uport); msm_geni_serial_abort_rx(uport); se_get_packing_config(8, 1, false, &cfg0, &cfg1); geni_se_init(uport->membase, (DEF_FIFO_DEPTH_WORDS >> 1), Loading @@ -2155,14 +2340,8 @@ msm_geni_serial_earlycon_setup(struct earlycon_device *dev, SE_UART_TX_TRANS_CFG); geni_write_reg_nolog(tx_parity_cfg, uport->membase, SE_UART_TX_PARITY_CFG); geni_write_reg_nolog(rx_trans_cfg, uport->membase, SE_UART_RX_TRANS_CFG); geni_write_reg_nolog(rx_parity_cfg, uport->membase, SE_UART_RX_PARITY_CFG); geni_write_reg_nolog(bits_per_char, uport->membase, SE_UART_TX_WORD_LEN); geni_write_reg_nolog(bits_per_char, uport->membase, SE_UART_RX_WORD_LEN); geni_write_reg_nolog(stop_bit, uport->membase, SE_UART_TX_STOP_BIT_LEN); geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_M_CLK_CFG); geni_write_reg_nolog(s_clk_cfg, uport->membase, GENI_SER_S_CLK_CFG); Loading Loading @@ -2204,7 +2383,7 @@ static struct uart_driver msm_geni_console_driver = { .owner = THIS_MODULE, .driver_name = "msm_geni_console", .dev_name = "ttyMSM", .nr = GENI_UART_NR_PORTS, .nr = GENI_UART_CONS_PORTS, .cons = &cons_ops, }; #else Loading @@ -2221,14 +2400,13 @@ static void console_unregister(struct uart_driver *drv) static void msm_geni_serial_debug_init(struct uart_port *uport, bool console) { struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); char name[30]; msm_port->dbg = debugfs_create_dir(dev_name(uport->dev), NULL); if (IS_ERR_OR_NULL(msm_port->dbg)) dev_err(uport->dev, "Failed to create dbg dir\n"); if (!console) { char name[30]; memset(name, 0, sizeof(name)); if (!msm_port->ipc_log_rx) { scnprintf(name, sizeof(name), "%s%s", Loading Loading @@ -2265,6 +2443,16 @@ static void msm_geni_serial_debug_init(struct uart_port *uport, bool console) if (!msm_port->ipc_log_misc) dev_info(uport->dev, "Err in Misc IPC Log\n"); } } else { memset(name, 0, sizeof(name)); if (!msm_port->console_log) { scnprintf(name, sizeof(name), "%s%s", dev_name(uport->dev), "_console"); msm_port->console_log = ipc_log_context_create( IPC_LOG_MISC_PAGES, name, 0); if (!msm_port->console_log) dev_info(uport->dev, "Err in Misc IPC Log\n"); } } } Loading Loading @@ -2329,6 +2517,43 @@ static const struct of_device_id msm_geni_device_tbl[] = { {}, }; static int msm_geni_serial_get_ver_info(struct uart_port *uport) { int hw_ver, ret = 0; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); se_geni_clks_on(&msm_port->serial_rsc); /* Basic HW and FW info */ if (unlikely(get_se_proto(uport->membase) != UART)) { dev_err(uport->dev, "%s: Invalid FW %d loaded.\n", __func__, get_se_proto(uport->membase)); ret = -ENXIO; goto exit_ver_info; } msm_port->ver_info.m_fw_ver = get_se_m_fw(uport->membase); msm_port->ver_info.s_fw_ver = get_se_s_fw(uport->membase); IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: FW Ver:0x%x%x\n", __func__, msm_port->ver_info.m_fw_ver, msm_port->ver_info.s_fw_ver); hw_ver = geni_se_qupv3_hw_version(msm_port->wrapper_dev, &msm_port->ver_info.hw_major_ver, &msm_port->ver_info.hw_minor_ver, &msm_port->ver_info.hw_step_ver); if (hw_ver) dev_err(uport->dev, "%s:Err getting HW version %d\n", __func__, hw_ver); else IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: HW Ver:%x.%x.%x\n", __func__, msm_port->ver_info.hw_major_ver, msm_port->ver_info.hw_minor_ver, msm_port->ver_info.hw_step_ver); exit_ver_info: se_geni_clks_off(&msm_port->serial_rsc); return ret; } static int msm_geni_serial_probe(struct platform_device *pdev) { int ret = 0; Loading @@ -2354,19 +2579,21 @@ static int msm_geni_serial_probe(struct platform_device *pdev) } if (pdev->dev.of_node) { if (drv->cons) if (drv->cons) { line = of_alias_get_id(pdev->dev.of_node, "serial"); else if (line < 0) line = 0; } else { line = of_alias_get_id(pdev->dev.of_node, "hsuart"); if (line < 0) line = uart_line_id++; else uart_line_id++; } } else { line = pdev->id; } if (line < 0) line = atomic_inc_return(&uart_line_id) - 1; if ((line < 0) || (line >= GENI_UART_NR_PORTS)) return -ENXIO; is_console = (drv->cons ? true : false); dev_port = get_port_from_line(line, is_console); if (IS_ERR_OR_NULL(dev_port)) { Loading Loading @@ -2473,6 +2700,15 @@ static int msm_geni_serial_probe(struct platform_device *pdev) ret = PTR_ERR(dev_port->serial_rsc.geni_pinctrl); goto exit_geni_serial_probe; } dev_port->serial_rsc.geni_gpio_active = pinctrl_lookup_state(dev_port->serial_rsc.geni_pinctrl, PINCTRL_ACTIVE); if (IS_ERR_OR_NULL(dev_port->serial_rsc.geni_gpio_active)) { /* * Backward compatible : In case few chips doesn't have ACTIVE * state defined. */ dev_port->serial_rsc.geni_gpio_active = pinctrl_lookup_state(dev_port->serial_rsc.geni_pinctrl, PINCTRL_DEFAULT); Loading @@ -2481,7 +2717,7 @@ static int msm_geni_serial_probe(struct platform_device *pdev) ret = PTR_ERR(dev_port->serial_rsc.geni_gpio_active); goto exit_geni_serial_probe; } } /* * For clients who setup an Inband wakeup, leave the GPIO pins * always connected to the core, else move the pins to their Loading Loading @@ -2542,8 +2778,12 @@ static int msm_geni_serial_probe(struct platform_device *pdev) line, uport->fifosize, is_console); device_create_file(uport->dev, &dev_attr_loopback); device_create_file(uport->dev, &dev_attr_xfer_mode); device_create_file(uport->dev, &dev_attr_ver_info); msm_geni_serial_debug_init(uport, is_console); dev_port->port_setup = false; ret = msm_geni_serial_get_ver_info(uport); if (ret) goto exit_geni_serial_probe; return uart_add_one_port(drv, uport); exit_geni_serial_probe: Loading