diff --git a/drivers/platform/msm/msm-geni-se.c b/drivers/platform/msm/msm-geni-se.c index 72dc328b3e2b..d0df2021e9a1 100644 --- a/drivers/platform/msm/msm-geni-se.c +++ b/drivers/platform/msm/msm-geni-se.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #include @@ -1244,6 +1244,35 @@ int geni_se_tx_dma_prep(struct device *wrapper_dev, void __iomem *base, } EXPORT_SYMBOL(geni_se_tx_dma_prep); +/** + * geni_se_rx_dma_start() - Prepare the Serial Engine registers for RX DMA + transfers. + * @base: Base address of the SE register block. + * @rx_len: Length of the RX buffer. + * @rx_dma: Pointer to store the mapped DMA address. + * + * This function is used to prepare the Serial Engine registers for DMA RX. + * + * Return: None. + */ +void geni_se_rx_dma_start(void __iomem *base, int rx_len, dma_addr_t *rx_dma) +{ + + if (!*rx_dma || !base || !rx_len) + return; + + geni_write_reg(7, base, SE_DMA_RX_IRQ_EN_SET); + geni_write_reg(GENI_SE_DMA_PTR_L(*rx_dma), base, SE_DMA_RX_PTR_L); + geni_write_reg(GENI_SE_DMA_PTR_H(*rx_dma), base, SE_DMA_RX_PTR_H); + /* RX does not have EOT bit */ + geni_write_reg(0, base, SE_DMA_RX_ATTR); + + /* Ensure that above register writes went through */ + mb(); + geni_write_reg(rx_len, base, SE_DMA_RX_LEN); +} +EXPORT_SYMBOL(geni_se_rx_dma_start); + /** * geni_se_rx_dma_prep() - Prepare the Serial Engine for RX DMA transfer * @wrapper_dev: QUPv3 Wrapper Device to which the RX buffer is mapped. @@ -1269,12 +1298,8 @@ int geni_se_rx_dma_prep(struct device *wrapper_dev, void __iomem *base, if (ret) return ret; - geni_write_reg(7, base, SE_DMA_RX_IRQ_EN_SET); - geni_write_reg(GENI_SE_DMA_PTR_L(*rx_dma), base, SE_DMA_RX_PTR_L); - geni_write_reg(GENI_SE_DMA_PTR_H(*rx_dma), base, SE_DMA_RX_PTR_H); - /* RX does not have EOT bit */ - geni_write_reg(0, base, SE_DMA_RX_ATTR); - geni_write_reg(rx_len, base, SE_DMA_RX_LEN); + geni_se_rx_dma_start(base, rx_len, rx_dma); + return 0; } EXPORT_SYMBOL(geni_se_rx_dma_prep); diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 84764d5e0c28..be3fd24d7c82 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -23,6 +23,7 @@ #include #include #include +#include /* UART specific GENI registers */ #define SE_UART_LOOPBACK_CFG (0x22C) @@ -1076,7 +1077,6 @@ static void start_rx_sequencer(struct uart_port *uport) unsigned int geni_m_irq_en; unsigned int geni_status; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); - int ret; u32 geni_se_param = UART_PARAM_RFR_OPEN; if (port->startup_in_progress) @@ -1084,17 +1084,11 @@ static void start_rx_sequencer(struct uart_port *uport) geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); if (geni_status & S_GENI_CMD_ACTIVE) { - if (port->xfer_mode == SE_DMA && !port->rx_dma) { + if (port->xfer_mode == SE_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; - } + geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, + &port->rx_dma); } msm_geni_serial_stop_rx(uport); } @@ -1116,21 +1110,14 @@ static void start_rx_sequencer(struct uart_port *uport) geni_write_reg_nolog(geni_m_irq_en, uport->membase, SE_GENI_M_IRQ_EN); } else if (port->xfer_mode == SE_DMA) { - ret = geni_se_rx_dma_prep(port->wrapper_dev, uport->membase, - port->rx_buf, DMA_RX_BUF_SIZE, &port->rx_dma); - if (ret) { - dev_err(uport->dev, "%s: RX Prep dma failed %d\n", - __func__, ret); - msm_geni_serial_stop_rx(uport); - goto exit_start_rx_sequencer; - } + geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, + &port->rx_dma); } /* * Ensure the writes to the secondary sequencer and interrupt enables * go through. */ mb(); -exit_start_rx_sequencer: 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)); @@ -1257,12 +1244,9 @@ static void stop_rx_sequencer(struct uart_port *uport) msm_geni_serial_abort_rx(uport); } exit_rx_seq: - if (port->xfer_mode == SE_DMA && port->rx_dma) { + if (port->xfer_mode == SE_DMA && port->rx_dma) msm_geni_serial_rx_fsm_rst(uport); - geni_se_rx_dma_unprep(port->wrapper_dev, port->rx_dma, - 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); } @@ -1443,7 +1427,7 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx) struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned int rx_bytes = 0; struct tty_port *tport; - int ret; + int ret = 0; unsigned int geni_status; geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); @@ -1451,16 +1435,13 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx) if (!(geni_status & S_GENI_CMD_ACTIVE)) return 0; - geni_se_rx_dma_unprep(msm_port->wrapper_dev, msm_port->rx_dma, - DMA_RX_BUF_SIZE); - msm_port->rx_dma = (dma_addr_t)NULL; - - rx_bytes = geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN); if (unlikely(!msm_port->rx_buf)) { IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: NULL Rx_buf\n", __func__); return 0; } + + rx_bytes = geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN); if (unlikely(!rx_bytes)) { IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: Size %d\n", __func__, rx_bytes); @@ -1482,10 +1463,9 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx) dump_ipc(msm_port->ipc_log_rx, "DMA Rx", (char *)msm_port->rx_buf, 0, rx_bytes); exit_handle_dma_rx: - ret = geni_se_rx_dma_prep(msm_port->wrapper_dev, uport->membase, - msm_port->rx_buf, DMA_RX_BUF_SIZE, &msm_port->rx_dma); - if (ret) - IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: %d\n", __func__, ret); + geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, + &msm_port->rx_dma); + return ret; } @@ -1771,6 +1751,7 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) int ret = 0; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); unsigned long cfg0, cfg1; + dma_addr_t dma_address; unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; set_rfr_wm(msm_port); @@ -1796,14 +1777,15 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) goto exit_portsetup; } - msm_port->rx_buf = devm_kzalloc(uport->dev, DMA_RX_BUF_SIZE, - GFP_KERNEL); + msm_port->rx_buf = dma_alloc_coherent(msm_port->wrapper_dev, + DMA_RX_BUF_SIZE, &dma_address, GFP_KERNEL); if (!msm_port->rx_buf) { devm_kfree(uport->dev, msm_port->rx_fifo); msm_port->rx_fifo = NULL; ret = -ENOMEM; goto exit_portsetup; } + msm_port->rx_dma = dma_address; } else { /* * Make an unconditional cancel on the main sequencer to reset @@ -1825,12 +1807,12 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) ret = geni_se_init(uport->membase, msm_port->rx_wm, msm_port->rx_rfr); if (ret) { dev_err(uport->dev, "%s: Fail\n", __func__); - goto exit_portsetup; + goto free_dma; } ret = geni_se_select_mode(uport->membase, msm_port->xfer_mode); if (ret) - goto exit_portsetup; + goto free_dma; msm_port->port_setup = true; /* @@ -1838,6 +1820,14 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) * framework. */ mb(); + + return 0; +free_dma: + if (msm_port->rx_dma) { + dma_free_coherent(msm_port->wrapper_dev, DMA_RX_BUF_SIZE, + msm_port->rx_buf, msm_port->rx_dma); + msm_port->rx_dma = (dma_addr_t)NULL; + } exit_portsetup: return ret; } @@ -2806,6 +2796,11 @@ static int msm_geni_serial_remove(struct platform_device *pdev) if (!uart_console(&port->uport)) wakeup_source_unregister(port->geni_wake); uart_remove_one_port(drv, &port->uport); + if (port->rx_dma) { + dma_free_coherent(port->wrapper_dev, DMA_RX_BUF_SIZE, + port->rx_buf, port->rx_dma); + port->rx_dma = (dma_addr_t)NULL; + } return 0; } diff --git a/include/linux/msm-geni-se.h b/include/linux/msm-geni-se.h index b5b2db67f972..40f4d672449a 100644 --- a/include/linux/msm-geni-se.h +++ b/include/linux/msm-geni-se.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef _LINUX_MSM_GENI_SE @@ -665,6 +665,19 @@ int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq, int geni_se_tx_dma_prep(struct device *wrapper_dev, void __iomem *base, void *tx_buf, int tx_len, dma_addr_t *tx_dma); +/** + * geni_se_rx_dma_start() - Prepare the Serial Engine registers for RX DMA + transfers. + * @base: Base address of the SE register block. + * @rx_len: Length of the RX buffer. + * @rx_dma: Pointer to store the mapped DMA address. + * + * This function is used to prepare the Serial Engine registers for DMA RX. + * + * Return: None. + */ +void geni_se_rx_dma_start(void __iomem *base, int rx_len, dma_addr_t *rx_dma); + /** * geni_se_rx_dma_prep() - Prepare the Serial Engine for RX DMA transfer * @wrapper_dev: QUPv3 Wrapper Device to which the TX buffer is mapped. @@ -979,5 +992,10 @@ static void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base, { } +static void geni_se_rx_dma_start(void __iomem *base, int rx_len, + dma_addr_t *rx_dma) +{ +} + #endif #endif