On Mon 09 Apr 12:38 PDT 2018, Karthikeyan Ramasubramanian wrote: > Add early console support in Qualcomm Technologies Inc., GENI based > UART controller. > Hi Karthikeyan, I pulled this into my SDM845 tree and added "earlycon" to my command line, the result is a working console up until the serial driver is probed at which point the console stops. I'm expecting that this should hand over to the normal console as it is probed, unless I specify keep_bootcon in which case I expect all log entries to be printed both through the earlycon and the normal console (i.e. show up twice on the uart). > Signed-off-by: Karthikeyan Ramasubramanian <kramasub@xxxxxxxxxxxxxx> > Signed-off-by: Girish Mahadevan <girishm@xxxxxxxxxxxxxx> This is a log of how the patch got to the list (and later to mainline), as such your name should be the last entry in this line and you should add an extra Co-Developed-by to indicate that you worked on this together with Girish. Regards, Bjorn > --- > drivers/tty/serial/qcom_geni_serial.c | 85 ++++++++++++++++++++++++++++++++++- > 1 file changed, 83 insertions(+), 2 deletions(-) > > diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c > index e40d4a4..2ce83a57 100644 > --- a/drivers/tty/serial/qcom_geni_serial.c > +++ b/drivers/tty/serial/qcom_geni_serial.c > @@ -196,8 +196,18 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, > timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500; > } > > - return !readl_poll_timeout_atomic(uport->membase + offset, reg, > - (bool)(reg & field) == set, 10, timeout_us); > + /* > + * Use custom implementation instead of readl_poll_atomic since ktimer > + * is not ready at the time of early console. > + */ > + while (timeout_us) { > + reg = readl_relaxed(uport->membase + offset); > + if ((bool)(reg & field) == set) > + return true; > + udelay(10); > + timeout_us -= 10; > + } > + return false; > } > > static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size) > @@ -944,6 +954,77 @@ static int __init qcom_geni_console_setup(struct console *co, char *options) > return uart_set_options(uport, co, baud, parity, bits, flow); > } > > +static void qcom_geni_serial_earlycon_write(struct console *con, > + const char *s, unsigned int n) > +{ > + struct earlycon_device *dev = con->data; > + > + __qcom_geni_serial_console_write(&dev->port, s, n); > +} > + > +static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev, > + const char *opt) > +{ > + struct uart_port *uport = &dev->port; > + u32 tx_trans_cfg; > + u32 tx_parity_cfg = 0; /* Disable Tx Parity */ > + u32 rx_trans_cfg = 0; > + u32 rx_parity_cfg = 0; /* Disable Rx Parity */ > + u32 stop_bit_len = 0; /* Default stop bit length - 1 bit */ > + u32 bits_per_char; > + u32 ser_clk_cfg; > + u32 baud = 115200; > + unsigned int clk_div; > + unsigned long clk_rate; > + struct geni_se se; > + > + if (!uport->membase) > + return -EINVAL; > + > + memset(&se, 0, sizeof(se)); > + se.base = uport->membase; > + if (geni_se_read_proto(&se) != GENI_SE_UART) > + return -ENXIO; > + > + /* > + * Ignore Flow control. > + * n = 8. > + */ > + tx_trans_cfg = UART_CTS_MASK; > + bits_per_char = BITS_PER_BYTE; > + > + clk_rate = get_clk_div_rate(baud, &clk_div); > + if (!clk_rate) > + return -EINVAL; > + > + ser_clk_cfg = SER_CLK_EN | (clk_div << CLK_DIV_SHFT); > + /* > + * Make an unconditional cancel on the main sequencer to reset > + * it else we could end up in data loss scenarios. > + */ > + qcom_geni_serial_poll_tx_done(uport); > + qcom_geni_serial_abort_rx(uport); > + geni_se_config_packing(&se, BITS_PER_BYTE, 1, false, true, false); > + geni_se_init(&se, DEF_FIFO_DEPTH_WORDS / 2, DEF_FIFO_DEPTH_WORDS - 2); > + geni_se_select_mode(&se, GENI_SE_FIFO); > + > + writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); > + writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); > + writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); > + writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); > + writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); > + writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); > + writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); > + writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); > + writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); > + > + dev->con->write = qcom_geni_serial_earlycon_write; > + dev->con->setup = NULL; > + return 0; > +} > +OF_EARLYCON_DECLARE(qcom_serial, "qcom,geni-debug-uart", > + qcom_geni_serial_earlycon_setup); > + > static int __init console_register(struct uart_driver *drv) > { > return uart_register_driver(drv); > -- > Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, > a Linux Foundation Collaborative Project > > -- > To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html