Thread (28 messages) 28 messages, 7 authors, 2018-03-22

Re: [PATCH v4 4/6] tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP

From: Stephen Boyd <hidden>
Date: 2018-03-21 17:20:00
Also in: linux-devicetree

Quoting Karthik Ramasubramanian (2018-03-20 15:53:25)

On 3/20/2018 9:37 AM, Stephen Boyd wrote:
quoted
Quoting Karthikeyan Ramasubramanian (2018-03-14 16:58:49)
quoted
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
new file mode 100644
index 0000000..1442777
--- /dev/null
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -0,0 +1,1158 @@
+
+#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
+static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch)
+{
+       writel_relaxed(ch, uport->membase + SE_GENI_TX_FIFOn);
Does this expect the whole word to have data to write? Or does the FIFO
output a character followed by three NUL bytes each time it gets
written? The way that uart_console_write() works is to take each
character a byte at a time, put it into an int (so extend that byte with
zero) and then pass it to the putchar function. I would expect that at
this point the hardware sees the single character and then 3 NULs enter
the FIFO each time.

For previous MSM uarts I had to handle this oddity by packing the words
into the fifo four at a time. You may need to do the same here.
The packing configuration 1 * 8 (done using geni_se_config_packing)
ensures that only one byte per FIFO word needs to be transmitted. From
that perspective, we need not have such oddity.
Ok! That's good to hear.
quoted
Can you also support the OF_EARLYCON_DECLARE method of console writing
so we can get an early printk style debug console?
Do you prefer that as part of this patch itself or is it ok if I upload
the earlycon support once this gets merged.
I think this already got merged? So just split it out into another patch
would be fine. I see the config is already selecting the earlycon
support so it must be planned.
quoted
quoted
+
+       spin_lock_irqsave(&uport->lock, flags);
+       m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS);
+       s_irq_status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS);
+       m_irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN);
+       writel_relaxed(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR);
+       writel_relaxed(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR);
+
+       if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN))
+               goto out_unlock;
+
+       if (s_irq_status & S_RX_FIFO_WR_ERR_EN) {
+               uport->icount.overrun++;
+               tty_insert_flip_char(tport, 0, TTY_OVERRUN);
+       }
+
+       if (m_irq_status & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN) &&
+           m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN))
+               qcom_geni_serial_handle_tx(uport);
+
+       if (s_irq_status & S_GP_IRQ_0_EN || s_irq_status & S_GP_IRQ_1_EN) {
+               if (s_irq_status & S_GP_IRQ_0_EN)
+                       uport->icount.parity++;
+               drop_rx = true;
+       } else if (s_irq_status & S_GP_IRQ_2_EN ||
+                                       s_irq_status & S_GP_IRQ_3_EN) {
+               uport->icount.brk++;
Maybe move this stat accounting to the place where brk is handled?
Since other error accounting like overrun, parity are happening here, it
feels logical to keep that accounting here.
Alright.
quoted
quoted
+       return uart_add_one_port(&qcom_geni_console_driver, uport);
+}
+
+static int qcom_geni_serial_remove(struct platform_device *pdev)
+{
+       struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
+       struct uart_driver *drv = port->uport.private_data;
+
+       uart_remove_one_port(drv, &port->uport);
+       return 0;
+}
+
+static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
+       struct uart_port *uport = &port->uport;
+
+       uart_suspend_port(uport->private_data, uport);
+       return 0;
+}
+
+static int __maybe_unused qcom_geni_serial_sys_resume_noirq(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
+       struct uart_port *uport = &port->uport;
+
+       if (console_suspend_enabled && uport->suspended) {
+               uart_resume_port(uport->private_data, uport);
+               disable_irq(uport->irq);
I missed the enable_irq() part. Is this still necessary?
Suspending the uart console port invokes the uart port shutdown
operation. The shutdown operation disables and frees the concerned IRQ.
Resuming the uart console port invokes the uart port startup operation
which requests for the IRQ. The request_irq operation auto-enables the
IRQ. In addition, resume_noirq implicitly enables the IRQ. This leads to
an unbalanced IRQ enable warning.

This disable_irq() helps with suppressing that warning.
That's not obvious so we need a big comment here.

I thought we would move this to the normal suspend/resume callbacks and
skip the noirq variants. That would make this disable_irq() unnecessary
then?

BTW, free_irq() should disable the irq itself, so it looks odd to have a
disable_irq() followed directly by a free_irq().

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help