|
|
|
|
@@ -147,6 +147,7 @@ static struct uart_driver qcom_geni_uart_driver;
|
|
|
|
|
|
|
|
|
|
static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
|
|
|
|
|
static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
|
|
|
|
|
static int qcom_geni_serial_port_setup(struct uart_port *uport);
|
|
|
|
|
|
|
|
|
|
static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport)
|
|
|
|
|
{
|
|
|
|
|
@@ -395,6 +396,23 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
|
|
|
|
|
writel(c, uport->membase + SE_GENI_TX_FIFOn);
|
|
|
|
|
qcom_geni_serial_poll_tx_done(uport);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int qcom_geni_serial_poll_init(struct uart_port *uport)
|
|
|
|
|
{
|
|
|
|
|
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (!port->setup) {
|
|
|
|
|
ret = qcom_geni_serial_port_setup(uport);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!qcom_geni_serial_secondary_active(uport))
|
|
|
|
|
geni_se_setup_s_cmd(&port->se, UART_START_READ, 0);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
|
|
|
|
|
@@ -562,7 +580,7 @@ static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
|
|
|
|
|
}
|
|
|
|
|
#endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */
|
|
|
|
|
|
|
|
|
|
static void handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
|
|
|
|
|
static void handle_rx_uart(struct uart_port *uport, u32 bytes)
|
|
|
|
|
{
|
|
|
|
|
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
|
|
|
|
struct tty_port *tport = &uport->state->port;
|
|
|
|
|
@@ -570,9 +588,8 @@ static void handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
|
|
|
|
|
|
|
|
|
|
ret = tty_insert_flip_string(tport, port->rx_buf, bytes);
|
|
|
|
|
if (ret != bytes) {
|
|
|
|
|
dev_err(uport->dev, "%s:Unable to push data ret %d_bytes %d\n",
|
|
|
|
|
__func__, ret, bytes);
|
|
|
|
|
WARN_ON_ONCE(1);
|
|
|
|
|
dev_err_ratelimited(uport->dev, "failed to push data (%d < %u)\n",
|
|
|
|
|
ret, bytes);
|
|
|
|
|
}
|
|
|
|
|
uport->icount.rx += ret;
|
|
|
|
|
tty_flip_buffer_push(tport);
|
|
|
|
|
@@ -787,17 +804,27 @@ static void qcom_geni_serial_start_rx_fifo(struct uart_port *uport)
|
|
|
|
|
static void qcom_geni_serial_stop_rx_dma(struct uart_port *uport)
|
|
|
|
|
{
|
|
|
|
|
struct qcom_geni_serial_port *port = to_dev_port(uport);
|
|
|
|
|
bool done;
|
|
|
|
|
|
|
|
|
|
if (!qcom_geni_serial_secondary_active(uport))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
geni_se_cancel_s_cmd(&port->se);
|
|
|
|
|
qcom_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS,
|
|
|
|
|
S_CMD_CANCEL_EN, true);
|
|
|
|
|
|
|
|
|
|
if (qcom_geni_serial_secondary_active(uport))
|
|
|
|
|
done = qcom_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT,
|
|
|
|
|
RX_EOT, true);
|
|
|
|
|
if (done) {
|
|
|
|
|
writel(RX_EOT | RX_DMA_DONE,
|
|
|
|
|
uport->membase + SE_DMA_RX_IRQ_CLR);
|
|
|
|
|
} else {
|
|
|
|
|
qcom_geni_serial_abort_rx(uport);
|
|
|
|
|
|
|
|
|
|
writel(1, uport->membase + SE_DMA_RX_FSM_RST);
|
|
|
|
|
qcom_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT,
|
|
|
|
|
RX_RESET_DONE, true);
|
|
|
|
|
writel(RX_RESET_DONE | RX_DMA_DONE,
|
|
|
|
|
uport->membase + SE_DMA_RX_IRQ_CLR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (port->rx_dma_addr) {
|
|
|
|
|
geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr,
|
|
|
|
|
DMA_RX_BUF_SIZE);
|
|
|
|
|
@@ -846,7 +873,7 @@ static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!drop)
|
|
|
|
|
handle_rx_uart(uport, rx_in, drop);
|
|
|
|
|
handle_rx_uart(uport, rx_in);
|
|
|
|
|
|
|
|
|
|
ret = geni_se_rx_dma_prep(&port->se, port->rx_buf,
|
|
|
|
|
DMA_RX_BUF_SIZE,
|
|
|
|
|
@@ -1096,10 +1123,12 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport)
|
|
|
|
|
{
|
|
|
|
|
disable_irq(uport->irq);
|
|
|
|
|
|
|
|
|
|
uart_port_lock_irq(uport);
|
|
|
|
|
qcom_geni_serial_stop_tx(uport);
|
|
|
|
|
qcom_geni_serial_stop_rx(uport);
|
|
|
|
|
|
|
|
|
|
qcom_geni_serial_cancel_tx_cmd(uport);
|
|
|
|
|
uart_port_unlock_irq(uport);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void qcom_geni_serial_flush_buffer(struct uart_port *uport)
|
|
|
|
|
@@ -1152,7 +1181,6 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
|
|
|
|
|
false, true, true);
|
|
|
|
|
geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
|
|
|
|
|
geni_se_select_mode(&port->se, port->dev_data->mode);
|
|
|
|
|
qcom_geni_serial_start_rx(uport);
|
|
|
|
|
port->setup = true;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -1168,6 +1196,11 @@ static int qcom_geni_serial_startup(struct uart_port *uport)
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uart_port_lock_irq(uport);
|
|
|
|
|
qcom_geni_serial_start_rx(uport);
|
|
|
|
|
uart_port_unlock_irq(uport);
|
|
|
|
|
|
|
|
|
|
enable_irq(uport->irq);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -1253,7 +1286,6 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
|
|
|
|
|
unsigned int avg_bw_core;
|
|
|
|
|
unsigned long timeout;
|
|
|
|
|
|
|
|
|
|
qcom_geni_serial_stop_rx(uport);
|
|
|
|
|
/* baud rate */
|
|
|
|
|
baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
|
|
|
|
|
|
|
|
|
|
@@ -1269,7 +1301,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
|
|
|
|
|
dev_err(port->se.dev,
|
|
|
|
|
"Couldn't find suitable clock rate for %u\n",
|
|
|
|
|
baud * sampling_rate);
|
|
|
|
|
goto out_restart_rx;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n",
|
|
|
|
|
@@ -1360,8 +1392,6 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
|
|
|
|
|
writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
|
|
|
|
|
writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
|
|
|
|
|
writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
|
|
|
|
|
out_restart_rx:
|
|
|
|
|
qcom_geni_serial_start_rx(uport);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
|
|
|
|
|
@@ -1582,7 +1612,7 @@ static const struct uart_ops qcom_geni_console_pops = {
|
|
|
|
|
#ifdef CONFIG_CONSOLE_POLL
|
|
|
|
|
.poll_get_char = qcom_geni_serial_get_char,
|
|
|
|
|
.poll_put_char = qcom_geni_serial_poll_put_char,
|
|
|
|
|
.poll_init = qcom_geni_serial_port_setup,
|
|
|
|
|
.poll_init = qcom_geni_serial_poll_init,
|
|
|
|
|
#endif
|
|
|
|
|
.pm = qcom_geni_serial_pm,
|
|
|
|
|
};
|
|
|
|
|
@@ -1749,7 +1779,7 @@ static void qcom_geni_serial_remove(struct platform_device *pdev)
|
|
|
|
|
uart_remove_one_port(drv, &port->uport);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int qcom_geni_serial_sys_suspend(struct device *dev)
|
|
|
|
|
static int qcom_geni_serial_suspend(struct device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
|
|
|
|
struct uart_port *uport = &port->uport;
|
|
|
|
|
@@ -1766,7 +1796,7 @@ static int qcom_geni_serial_sys_suspend(struct device *dev)
|
|
|
|
|
return uart_suspend_port(private_data->drv, uport);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int qcom_geni_serial_sys_resume(struct device *dev)
|
|
|
|
|
static int qcom_geni_serial_resume(struct device *dev)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
|
|
|
|
@@ -1781,38 +1811,6 @@ static int qcom_geni_serial_sys_resume(struct device *dev)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int qcom_geni_serial_sys_hib_resume(struct device *dev)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
struct uart_port *uport;
|
|
|
|
|
struct qcom_geni_private_data *private_data;
|
|
|
|
|
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
|
|
|
|
|
|
|
|
|
uport = &port->uport;
|
|
|
|
|
private_data = uport->private_data;
|
|
|
|
|
|
|
|
|
|
if (uart_console(uport)) {
|
|
|
|
|
geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS);
|
|
|
|
|
geni_icc_set_bw(&port->se);
|
|
|
|
|
ret = uart_resume_port(private_data->drv, uport);
|
|
|
|
|
/*
|
|
|
|
|
* For hibernation usecase clients for
|
|
|
|
|
* console UART won't call port setup during restore,
|
|
|
|
|
* hence call port setup for console uart.
|
|
|
|
|
*/
|
|
|
|
|
qcom_geni_serial_port_setup(uport);
|
|
|
|
|
} else {
|
|
|
|
|
/*
|
|
|
|
|
* Peripheral register settings are lost during hibernation.
|
|
|
|
|
* Update setup flag such that port setup happens again
|
|
|
|
|
* during next session. Clients of HS-UART will close and
|
|
|
|
|
* open the port during hibernation.
|
|
|
|
|
*/
|
|
|
|
|
port->setup = false;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct qcom_geni_device_data qcom_geni_console_data = {
|
|
|
|
|
.console = true,
|
|
|
|
|
.mode = GENI_SE_FIFO,
|
|
|
|
|
@@ -1824,12 +1822,7 @@ static const struct qcom_geni_device_data qcom_geni_uart_data = {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
|
|
|
|
|
.suspend = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
|
|
|
|
|
.resume = pm_sleep_ptr(qcom_geni_serial_sys_resume),
|
|
|
|
|
.freeze = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
|
|
|
|
|
.poweroff = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
|
|
|
|
|
.restore = pm_sleep_ptr(qcom_geni_serial_sys_hib_resume),
|
|
|
|
|
.thaw = pm_sleep_ptr(qcom_geni_serial_sys_hib_resume),
|
|
|
|
|
SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct of_device_id qcom_geni_serial_match_table[] = {
|
|
|
|
|
|