|
@@ -140,6 +140,8 @@
|
|
|
#define UARTBAUD_SBNS 0x00002000
|
|
|
#define UARTBAUD_SBR 0x00000000
|
|
|
#define UARTBAUD_SBR_MASK 0x1fff
|
|
|
+#define UARTBAUD_OSR_MASK 0x1f
|
|
|
+#define UARTBAUD_OSR_SHIFT 24
|
|
|
|
|
|
#define UARTSTAT_LBKDIF 0x80000000
|
|
|
#define UARTSTAT_RXEDGIF 0x40000000
|
|
@@ -231,12 +233,14 @@
|
|
|
#define DEV_NAME "ttyLP"
|
|
|
#define UART_NR 6
|
|
|
|
|
|
+/* IMX lpuart has four extra unused regs located at the beginning */
|
|
|
+#define IMX_REG_OFF 0x10
|
|
|
+
|
|
|
struct lpuart_port {
|
|
|
struct uart_port port;
|
|
|
struct clk *clk;
|
|
|
unsigned int txfifo_size;
|
|
|
unsigned int rxfifo_size;
|
|
|
- bool lpuart32;
|
|
|
|
|
|
bool lpuart_dma_tx_use;
|
|
|
bool lpuart_dma_rx_use;
|
|
@@ -258,13 +262,28 @@ struct lpuart_port {
|
|
|
wait_queue_head_t dma_wait;
|
|
|
};
|
|
|
|
|
|
+struct lpuart_soc_data {
|
|
|
+ char iotype;
|
|
|
+ u8 reg_off;
|
|
|
+};
|
|
|
+
|
|
|
+static const struct lpuart_soc_data vf_data = {
|
|
|
+ .iotype = UPIO_MEM,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct lpuart_soc_data ls_data = {
|
|
|
+ .iotype = UPIO_MEM32BE,
|
|
|
+};
|
|
|
+
|
|
|
+static struct lpuart_soc_data imx_data = {
|
|
|
+ .iotype = UPIO_MEM32,
|
|
|
+ .reg_off = IMX_REG_OFF,
|
|
|
+};
|
|
|
+
|
|
|
static const struct of_device_id lpuart_dt_ids[] = {
|
|
|
- {
|
|
|
- .compatible = "fsl,vf610-lpuart",
|
|
|
- },
|
|
|
- {
|
|
|
- .compatible = "fsl,ls1021a-lpuart",
|
|
|
- },
|
|
|
+ { .compatible = "fsl,vf610-lpuart", .data = &vf_data, },
|
|
|
+ { .compatible = "fsl,ls1021a-lpuart", .data = &ls_data, },
|
|
|
+ { .compatible = "fsl,imx7ulp-lpuart", .data = &imx_data, },
|
|
|
{ /* sentinel */ }
|
|
|
};
|
|
|
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
|
@@ -272,14 +291,29 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
|
|
/* Forward declare this for the dma callbacks*/
|
|
|
static void lpuart_dma_tx_complete(void *arg);
|
|
|
|
|
|
-static u32 lpuart32_read(void __iomem *addr)
|
|
|
+static inline u32 lpuart32_read(struct uart_port *port, u32 off)
|
|
|
{
|
|
|
- return ioread32be(addr);
|
|
|
+ switch (port->iotype) {
|
|
|
+ case UPIO_MEM32:
|
|
|
+ return readl(port->membase + off);
|
|
|
+ case UPIO_MEM32BE:
|
|
|
+ return ioread32be(port->membase + off);
|
|
|
+ default:
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-static void lpuart32_write(u32 val, void __iomem *addr)
|
|
|
+static inline void lpuart32_write(struct uart_port *port, u32 val,
|
|
|
+ u32 off)
|
|
|
{
|
|
|
- iowrite32be(val, addr);
|
|
|
+ switch (port->iotype) {
|
|
|
+ case UPIO_MEM32:
|
|
|
+ writel(val, port->membase + off);
|
|
|
+ break;
|
|
|
+ case UPIO_MEM32BE:
|
|
|
+ iowrite32be(val, port->membase + off);
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void lpuart_stop_tx(struct uart_port *port)
|
|
@@ -295,9 +329,9 @@ static void lpuart32_stop_tx(struct uart_port *port)
|
|
|
{
|
|
|
unsigned long temp;
|
|
|
|
|
|
- temp = lpuart32_read(port->membase + UARTCTRL);
|
|
|
+ temp = lpuart32_read(port, UARTCTRL);
|
|
|
temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
|
|
|
- lpuart32_write(temp, port->membase + UARTCTRL);
|
|
|
+ lpuart32_write(port, temp, UARTCTRL);
|
|
|
}
|
|
|
|
|
|
static void lpuart_stop_rx(struct uart_port *port)
|
|
@@ -312,8 +346,8 @@ static void lpuart32_stop_rx(struct uart_port *port)
|
|
|
{
|
|
|
unsigned long temp;
|
|
|
|
|
|
- temp = lpuart32_read(port->membase + UARTCTRL);
|
|
|
- lpuart32_write(temp & ~UARTCTRL_RE, port->membase + UARTCTRL);
|
|
|
+ temp = lpuart32_read(port, UARTCTRL);
|
|
|
+ lpuart32_write(port, temp & ~UARTCTRL_RE, UARTCTRL);
|
|
|
}
|
|
|
|
|
|
static void lpuart_dma_tx(struct lpuart_port *sport)
|
|
@@ -512,14 +546,14 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
|
|
|
struct circ_buf *xmit = &sport->port.state->xmit;
|
|
|
unsigned long txcnt;
|
|
|
|
|
|
- txcnt = lpuart32_read(sport->port.membase + UARTWATER);
|
|
|
+ txcnt = lpuart32_read(&sport->port, UARTWATER);
|
|
|
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
|
|
txcnt &= UARTWATER_COUNT_MASK;
|
|
|
while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) {
|
|
|
- lpuart32_write(xmit->buf[xmit->tail], sport->port.membase + UARTDATA);
|
|
|
+ lpuart32_write(&sport->port, xmit->buf[xmit->tail], UARTDATA);
|
|
|
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
|
|
sport->port.icount.tx++;
|
|
|
- txcnt = lpuart32_read(sport->port.membase + UARTWATER);
|
|
|
+ txcnt = lpuart32_read(&sport->port, UARTWATER);
|
|
|
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
|
|
txcnt &= UARTWATER_COUNT_MASK;
|
|
|
}
|
|
@@ -555,10 +589,10 @@ static void lpuart32_start_tx(struct uart_port *port)
|
|
|
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
|
|
unsigned long temp;
|
|
|
|
|
|
- temp = lpuart32_read(port->membase + UARTCTRL);
|
|
|
- lpuart32_write(temp | UARTCTRL_TIE, port->membase + UARTCTRL);
|
|
|
+ temp = lpuart32_read(port, UARTCTRL);
|
|
|
+ lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL);
|
|
|
|
|
|
- if (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE)
|
|
|
+ if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)
|
|
|
lpuart32_transmit_buffer(sport);
|
|
|
}
|
|
|
|
|
@@ -581,7 +615,7 @@ static unsigned int lpuart_tx_empty(struct uart_port *port)
|
|
|
|
|
|
static unsigned int lpuart32_tx_empty(struct uart_port *port)
|
|
|
{
|
|
|
- return (lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TC) ?
|
|
|
+ return (lpuart32_read(port, UARTSTAT) & UARTSTAT_TC) ?
|
|
|
TIOCSER_TEMT : 0;
|
|
|
}
|
|
|
|
|
@@ -593,22 +627,22 @@ static irqreturn_t lpuart_txint(int irq, void *dev_id)
|
|
|
|
|
|
spin_lock_irqsave(&sport->port.lock, flags);
|
|
|
if (sport->port.x_char) {
|
|
|
- if (sport->lpuart32)
|
|
|
- lpuart32_write(sport->port.x_char, sport->port.membase + UARTDATA);
|
|
|
+ if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
|
|
+ lpuart32_write(&sport->port, sport->port.x_char, UARTDATA);
|
|
|
else
|
|
|
writeb(sport->port.x_char, sport->port.membase + UARTDR);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
|
|
|
- if (sport->lpuart32)
|
|
|
+ if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
|
|
lpuart32_stop_tx(&sport->port);
|
|
|
else
|
|
|
lpuart_stop_tx(&sport->port);
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (sport->lpuart32)
|
|
|
+ if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
|
|
lpuart32_transmit_buffer(sport);
|
|
|
else
|
|
|
lpuart_transmit_buffer(sport);
|
|
@@ -694,15 +728,15 @@ static irqreturn_t lpuart32_rxint(int irq, void *dev_id)
|
|
|
|
|
|
spin_lock_irqsave(&sport->port.lock, flags);
|
|
|
|
|
|
- while (!(lpuart32_read(sport->port.membase + UARTFIFO) & UARTFIFO_RXEMPT)) {
|
|
|
+ while (!(lpuart32_read(&sport->port, UARTFIFO) & UARTFIFO_RXEMPT)) {
|
|
|
flg = TTY_NORMAL;
|
|
|
sport->port.icount.rx++;
|
|
|
/*
|
|
|
* to clear the FE, OR, NF, FE, PE flags,
|
|
|
* read STAT then read DATA reg
|
|
|
*/
|
|
|
- sr = lpuart32_read(sport->port.membase + UARTSTAT);
|
|
|
- rx = lpuart32_read(sport->port.membase + UARTDATA);
|
|
|
+ sr = lpuart32_read(&sport->port, UARTSTAT);
|
|
|
+ rx = lpuart32_read(&sport->port, UARTDATA);
|
|
|
rx &= 0x3ff;
|
|
|
|
|
|
if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
|
|
@@ -769,18 +803,18 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
|
|
|
struct lpuart_port *sport = dev_id;
|
|
|
unsigned long sts, rxcount;
|
|
|
|
|
|
- sts = lpuart32_read(sport->port.membase + UARTSTAT);
|
|
|
- rxcount = lpuart32_read(sport->port.membase + UARTWATER);
|
|
|
+ sts = lpuart32_read(&sport->port, UARTSTAT);
|
|
|
+ rxcount = lpuart32_read(&sport->port, UARTWATER);
|
|
|
rxcount = rxcount >> UARTWATER_RXCNT_OFF;
|
|
|
|
|
|
if (sts & UARTSTAT_RDRF || rxcount > 0)
|
|
|
lpuart32_rxint(irq, dev_id);
|
|
|
|
|
|
if ((sts & UARTSTAT_TDRE) &&
|
|
|
- !(lpuart32_read(sport->port.membase + UARTBAUD) & UARTBAUD_TDMAE))
|
|
|
+ !(lpuart32_read(&sport->port, UARTBAUD) & UARTBAUD_TDMAE))
|
|
|
lpuart_txint(irq, dev_id);
|
|
|
|
|
|
- lpuart32_write(sts, sport->port.membase + UARTSTAT);
|
|
|
+ lpuart32_write(&sport->port, sts, UARTSTAT);
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
@@ -1041,7 +1075,7 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port)
|
|
|
unsigned int temp = 0;
|
|
|
unsigned long reg;
|
|
|
|
|
|
- reg = lpuart32_read(port->membase + UARTMODIR);
|
|
|
+ reg = lpuart32_read(port, UARTMODIR);
|
|
|
if (reg & UARTMODIR_TXCTSE)
|
|
|
temp |= TIOCM_CTS;
|
|
|
|
|
@@ -1076,7 +1110,7 @@ static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|
|
{
|
|
|
unsigned long temp;
|
|
|
|
|
|
- temp = lpuart32_read(port->membase + UARTMODIR) &
|
|
|
+ temp = lpuart32_read(port, UARTMODIR) &
|
|
|
~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE);
|
|
|
|
|
|
if (mctrl & TIOCM_RTS)
|
|
@@ -1085,7 +1119,7 @@ static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|
|
if (mctrl & TIOCM_CTS)
|
|
|
temp |= UARTMODIR_TXCTSE;
|
|
|
|
|
|
- lpuart32_write(temp, port->membase + UARTMODIR);
|
|
|
+ lpuart32_write(port, temp, UARTMODIR);
|
|
|
}
|
|
|
|
|
|
static void lpuart_break_ctl(struct uart_port *port, int break_state)
|
|
@@ -1104,12 +1138,12 @@ static void lpuart32_break_ctl(struct uart_port *port, int break_state)
|
|
|
{
|
|
|
unsigned long temp;
|
|
|
|
|
|
- temp = lpuart32_read(port->membase + UARTCTRL) & ~UARTCTRL_SBK;
|
|
|
+ temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK;
|
|
|
|
|
|
if (break_state != 0)
|
|
|
temp |= UARTCTRL_SBK;
|
|
|
|
|
|
- lpuart32_write(temp, port->membase + UARTCTRL);
|
|
|
+ lpuart32_write(port, temp, UARTCTRL);
|
|
|
}
|
|
|
|
|
|
static void lpuart_setup_watermark(struct lpuart_port *sport)
|
|
@@ -1149,24 +1183,24 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
|
|
|
unsigned long val, ctrl;
|
|
|
unsigned long ctrl_saved;
|
|
|
|
|
|
- ctrl = lpuart32_read(sport->port.membase + UARTCTRL);
|
|
|
+ ctrl = lpuart32_read(&sport->port, UARTCTRL);
|
|
|
ctrl_saved = ctrl;
|
|
|
ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE |
|
|
|
UARTCTRL_RIE | UARTCTRL_RE);
|
|
|
- lpuart32_write(ctrl, sport->port.membase + UARTCTRL);
|
|
|
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
|
|
|
|
|
|
/* enable FIFO mode */
|
|
|
- val = lpuart32_read(sport->port.membase + UARTFIFO);
|
|
|
+ val = lpuart32_read(&sport->port, UARTFIFO);
|
|
|
val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
|
|
|
val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
|
|
|
- lpuart32_write(val, sport->port.membase + UARTFIFO);
|
|
|
+ lpuart32_write(&sport->port, val, UARTFIFO);
|
|
|
|
|
|
/* set the watermark */
|
|
|
val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
|
|
|
- lpuart32_write(val, sport->port.membase + UARTWATER);
|
|
|
+ lpuart32_write(&sport->port, val, UARTWATER);
|
|
|
|
|
|
/* Restore cr2 */
|
|
|
- lpuart32_write(ctrl_saved, sport->port.membase + UARTCTRL);
|
|
|
+ lpuart32_write(&sport->port, ctrl_saved, UARTCTRL);
|
|
|
}
|
|
|
|
|
|
static void rx_dma_timer_init(struct lpuart_port *sport)
|
|
@@ -1242,7 +1276,7 @@ static int lpuart32_startup(struct uart_port *port)
|
|
|
unsigned long temp;
|
|
|
|
|
|
/* determine FIFO size */
|
|
|
- temp = lpuart32_read(sport->port.membase + UARTFIFO);
|
|
|
+ temp = lpuart32_read(&sport->port, UARTFIFO);
|
|
|
|
|
|
sport->txfifo_size = 0x1 << (((temp >> UARTFIFO_TXSIZE_OFF) &
|
|
|
UARTFIFO_FIFOSIZE_MASK) - 1);
|
|
@@ -1259,10 +1293,10 @@ static int lpuart32_startup(struct uart_port *port)
|
|
|
|
|
|
lpuart32_setup_watermark(sport);
|
|
|
|
|
|
- temp = lpuart32_read(sport->port.membase + UARTCTRL);
|
|
|
+ temp = lpuart32_read(&sport->port, UARTCTRL);
|
|
|
temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | UARTCTRL_TE);
|
|
|
temp |= UARTCTRL_ILIE;
|
|
|
- lpuart32_write(temp, sport->port.membase + UARTCTRL);
|
|
|
+ lpuart32_write(&sport->port, temp, UARTCTRL);
|
|
|
|
|
|
spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
|
return 0;
|
|
@@ -1311,10 +1345,10 @@ static void lpuart32_shutdown(struct uart_port *port)
|
|
|
spin_lock_irqsave(&port->lock, flags);
|
|
|
|
|
|
/* disable Rx/Tx and interrupts */
|
|
|
- temp = lpuart32_read(port->membase + UARTCTRL);
|
|
|
+ temp = lpuart32_read(port, UARTCTRL);
|
|
|
temp &= ~(UARTCTRL_TE | UARTCTRL_RE |
|
|
|
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
|
|
|
- lpuart32_write(temp, port->membase + UARTCTRL);
|
|
|
+ lpuart32_write(port, temp, UARTCTRL);
|
|
|
|
|
|
spin_unlock_irqrestore(&port->lock, flags);
|
|
|
|
|
@@ -1478,6 +1512,75 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate)
|
|
|
+{
|
|
|
+ u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
|
|
|
+ u32 clk = sport->port.uartclk;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The idea is to use the best OSR (over-sampling rate) possible.
|
|
|
+ * Note, OSR is typically hard-set to 16 in other LPUART instantiations.
|
|
|
+ * Loop to find the best OSR value possible, one that generates minimum
|
|
|
+ * baud_diff iterate through the rest of the supported values of OSR.
|
|
|
+ *
|
|
|
+ * Calculation Formula:
|
|
|
+ * Baud Rate = baud clock / ((OSR+1) × SBR)
|
|
|
+ */
|
|
|
+ baud_diff = baudrate;
|
|
|
+ osr = 0;
|
|
|
+ sbr = 0;
|
|
|
+
|
|
|
+ for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
|
|
|
+ /* calculate the temporary sbr value */
|
|
|
+ tmp_sbr = (clk / (baudrate * tmp_osr));
|
|
|
+ if (tmp_sbr == 0)
|
|
|
+ tmp_sbr = 1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * calculate the baud rate difference based on the temporary
|
|
|
+ * osr and sbr values
|
|
|
+ */
|
|
|
+ tmp_diff = clk / (tmp_osr * tmp_sbr) - baudrate;
|
|
|
+
|
|
|
+ /* select best values between sbr and sbr+1 */
|
|
|
+ tmp = clk / (tmp_osr * (tmp_sbr + 1));
|
|
|
+ if (tmp_diff > (baudrate - tmp)) {
|
|
|
+ tmp_diff = baudrate - tmp;
|
|
|
+ tmp_sbr++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (tmp_diff <= baud_diff) {
|
|
|
+ baud_diff = tmp_diff;
|
|
|
+ osr = tmp_osr;
|
|
|
+ sbr = tmp_sbr;
|
|
|
+
|
|
|
+ if (!baud_diff)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* handle buadrate outside acceptable rate */
|
|
|
+ if (baud_diff > ((baudrate / 100) * 3))
|
|
|
+ dev_warn(sport->port.dev,
|
|
|
+ "unacceptable baud rate difference of more than 3%%\n");
|
|
|
+
|
|
|
+ tmp = lpuart32_read(&sport->port, UARTBAUD);
|
|
|
+
|
|
|
+ if ((osr > 3) && (osr < 8))
|
|
|
+ tmp |= UARTBAUD_BOTHEDGE;
|
|
|
+
|
|
|
+ tmp &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT);
|
|
|
+ tmp |= (((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT);
|
|
|
+
|
|
|
+ tmp &= ~UARTBAUD_SBR_MASK;
|
|
|
+ tmp |= sbr & UARTBAUD_SBR_MASK;
|
|
|
+
|
|
|
+ tmp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
|
|
|
+
|
|
|
+ lpuart32_write(&sport->port, tmp, UARTBAUD);
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
struct ktermios *old)
|
|
@@ -1487,11 +1590,10 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
unsigned long ctrl, old_ctrl, bd, modem;
|
|
|
unsigned int baud;
|
|
|
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
|
|
|
- unsigned int sbr;
|
|
|
|
|
|
- ctrl = old_ctrl = lpuart32_read(sport->port.membase + UARTCTRL);
|
|
|
- bd = lpuart32_read(sport->port.membase + UARTBAUD);
|
|
|
- modem = lpuart32_read(sport->port.membase + UARTMODIR);
|
|
|
+ ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL);
|
|
|
+ bd = lpuart32_read(&sport->port, UARTBAUD);
|
|
|
+ modem = lpuart32_read(&sport->port, UARTMODIR);
|
|
|
/*
|
|
|
* only support CS8 and CS7, and for CS7 must enable PE.
|
|
|
* supported mode:
|
|
@@ -1577,21 +1679,16 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|
|
uart_update_timeout(port, termios->c_cflag, baud);
|
|
|
|
|
|
/* wait transmit engin complete */
|
|
|
- while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC))
|
|
|
+ while (!(lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_TC))
|
|
|
barrier();
|
|
|
|
|
|
/* disable transmit and receive */
|
|
|
- lpuart32_write(old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
|
|
|
- sport->port.membase + UARTCTRL);
|
|
|
+ lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
|
|
|
+ UARTCTRL);
|
|
|
|
|
|
- sbr = sport->port.uartclk / (16 * baud);
|
|
|
- bd &= ~UARTBAUD_SBR_MASK;
|
|
|
- bd |= sbr & UARTBAUD_SBR_MASK;
|
|
|
- bd |= UARTBAUD_BOTHEDGE;
|
|
|
- bd &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE);
|
|
|
- lpuart32_write(bd, sport->port.membase + UARTBAUD);
|
|
|
- lpuart32_write(modem, sport->port.membase + UARTMODIR);
|
|
|
- lpuart32_write(ctrl, sport->port.membase + UARTCTRL);
|
|
|
+ lpuart32_serial_setbrg(sport, baud);
|
|
|
+ lpuart32_write(&sport->port, modem, UARTMODIR);
|
|
|
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
|
|
|
/* restore control register */
|
|
|
|
|
|
spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
@@ -1694,10 +1791,10 @@ static void lpuart_console_putchar(struct uart_port *port, int ch)
|
|
|
|
|
|
static void lpuart32_console_putchar(struct uart_port *port, int ch)
|
|
|
{
|
|
|
- while (!(lpuart32_read(port->membase + UARTSTAT) & UARTSTAT_TDRE))
|
|
|
+ while (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE))
|
|
|
barrier();
|
|
|
|
|
|
- lpuart32_write(ch, port->membase + UARTDATA);
|
|
|
+ lpuart32_write(port, ch, UARTDATA);
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -1745,18 +1842,18 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count)
|
|
|
spin_lock_irqsave(&sport->port.lock, flags);
|
|
|
|
|
|
/* first save CR2 and then disable interrupts */
|
|
|
- cr = old_cr = lpuart32_read(sport->port.membase + UARTCTRL);
|
|
|
+ cr = old_cr = lpuart32_read(&sport->port, UARTCTRL);
|
|
|
cr |= (UARTCTRL_TE | UARTCTRL_RE);
|
|
|
cr &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE);
|
|
|
- lpuart32_write(cr, sport->port.membase + UARTCTRL);
|
|
|
+ lpuart32_write(&sport->port, cr, UARTCTRL);
|
|
|
|
|
|
uart_console_write(&sport->port, s, count, lpuart32_console_putchar);
|
|
|
|
|
|
/* wait for transmitter finish complete and restore CR2 */
|
|
|
- while (!(lpuart32_read(sport->port.membase + UARTSTAT) & UARTSTAT_TC))
|
|
|
+ while (!(lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_TC))
|
|
|
barrier();
|
|
|
|
|
|
- lpuart32_write(old_cr, sport->port.membase + UARTCTRL);
|
|
|
+ lpuart32_write(&sport->port, old_cr, UARTCTRL);
|
|
|
|
|
|
if (locked)
|
|
|
spin_unlock_irqrestore(&sport->port.lock, flags);
|
|
@@ -1822,14 +1919,14 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
|
|
|
unsigned long cr, bd;
|
|
|
unsigned int sbr, uartclk, baud_raw;
|
|
|
|
|
|
- cr = lpuart32_read(sport->port.membase + UARTCTRL);
|
|
|
+ cr = lpuart32_read(&sport->port, UARTCTRL);
|
|
|
cr &= UARTCTRL_TE | UARTCTRL_RE;
|
|
|
if (!cr)
|
|
|
return;
|
|
|
|
|
|
/* ok, the port was enabled */
|
|
|
|
|
|
- cr = lpuart32_read(sport->port.membase + UARTCTRL);
|
|
|
+ cr = lpuart32_read(&sport->port, UARTCTRL);
|
|
|
|
|
|
*parity = 'n';
|
|
|
if (cr & UARTCTRL_PE) {
|
|
@@ -1844,7 +1941,7 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
|
|
|
else
|
|
|
*bits = 8;
|
|
|
|
|
|
- bd = lpuart32_read(sport->port.membase + UARTBAUD);
|
|
|
+ bd = lpuart32_read(&sport->port, UARTBAUD);
|
|
|
bd &= UARTBAUD_SBR_MASK;
|
|
|
sbr = bd;
|
|
|
uartclk = clk_get_rate(sport->clk);
|
|
@@ -1881,12 +1978,12 @@ static int __init lpuart_console_setup(struct console *co, char *options)
|
|
|
if (options)
|
|
|
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
|
|
else
|
|
|
- if (sport->lpuart32)
|
|
|
+ if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
|
|
lpuart32_console_get_options(sport, &baud, &parity, &bits);
|
|
|
else
|
|
|
lpuart_console_get_options(sport, &baud, &parity, &bits);
|
|
|
|
|
|
- if (sport->lpuart32)
|
|
|
+ if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
|
|
lpuart32_setup_watermark(sport);
|
|
|
else
|
|
|
lpuart_setup_watermark(sport);
|
|
@@ -1945,12 +2042,26 @@ static int __init lpuart32_early_console_setup(struct earlycon_device *device,
|
|
|
if (!device->port.membase)
|
|
|
return -ENODEV;
|
|
|
|
|
|
+ device->port.iotype = UPIO_MEM32BE;
|
|
|
device->con->write = lpuart32_early_write;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int __init lpuart32_imx_early_console_setup(struct earlycon_device *device,
|
|
|
+ const char *opt)
|
|
|
+{
|
|
|
+ if (!device->port.membase)
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
+ device->port.iotype = UPIO_MEM32;
|
|
|
+ device->port.membase += IMX_REG_OFF;
|
|
|
+ device->con->write = lpuart32_early_write;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
|
|
|
OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
|
|
|
+OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup);
|
|
|
EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
|
|
|
EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
|
|
|
|
|
@@ -1971,6 +2082,9 @@ static struct uart_driver lpuart_reg = {
|
|
|
|
|
|
static int lpuart_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
+ const struct of_device_id *of_id = of_match_device(lpuart_dt_ids,
|
|
|
+ &pdev->dev);
|
|
|
+ const struct lpuart_soc_data *sdata = of_id->data;
|
|
|
struct device_node *np = pdev->dev.of_node;
|
|
|
struct lpuart_port *sport;
|
|
|
struct resource *res;
|
|
@@ -1988,25 +2102,23 @@ static int lpuart_probe(struct platform_device *pdev)
|
|
|
return ret;
|
|
|
}
|
|
|
sport->port.line = ret;
|
|
|
- sport->lpuart32 = of_device_is_compatible(np, "fsl,ls1021a-lpuart");
|
|
|
-
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
sport->port.membase = devm_ioremap_resource(&pdev->dev, res);
|
|
|
if (IS_ERR(sport->port.membase))
|
|
|
return PTR_ERR(sport->port.membase);
|
|
|
|
|
|
+ sport->port.membase += sdata->reg_off;
|
|
|
sport->port.mapbase = res->start;
|
|
|
sport->port.dev = &pdev->dev;
|
|
|
sport->port.type = PORT_LPUART;
|
|
|
- sport->port.iotype = UPIO_MEM;
|
|
|
ret = platform_get_irq(pdev, 0);
|
|
|
if (ret < 0) {
|
|
|
dev_err(&pdev->dev, "cannot obtain irq\n");
|
|
|
return ret;
|
|
|
}
|
|
|
sport->port.irq = ret;
|
|
|
-
|
|
|
- if (sport->lpuart32)
|
|
|
+ sport->port.iotype = sdata->iotype;
|
|
|
+ if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
|
|
sport->port.ops = &lpuart32_pops;
|
|
|
else
|
|
|
sport->port.ops = &lpuart_pops;
|
|
@@ -2033,7 +2145,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
|
|
|
|
|
platform_set_drvdata(pdev, &sport->port);
|
|
|
|
|
|
- if (sport->lpuart32)
|
|
|
+ if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE))
|
|
|
lpuart_reg.cons = LPUART32_CONSOLE;
|
|
|
else
|
|
|
lpuart_reg.cons = LPUART_CONSOLE;
|
|
@@ -2086,11 +2198,11 @@ static int lpuart_suspend(struct device *dev)
|
|
|
struct lpuart_port *sport = dev_get_drvdata(dev);
|
|
|
unsigned long temp;
|
|
|
|
|
|
- if (sport->lpuart32) {
|
|
|
+ if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) {
|
|
|
/* disable Rx/Tx and interrupts */
|
|
|
- temp = lpuart32_read(sport->port.membase + UARTCTRL);
|
|
|
+ temp = lpuart32_read(&sport->port, UARTCTRL);
|
|
|
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
|
|
|
- lpuart32_write(temp, sport->port.membase + UARTCTRL);
|
|
|
+ lpuart32_write(&sport->port, temp, UARTCTRL);
|
|
|
} else {
|
|
|
/* disable Rx/Tx and interrupts */
|
|
|
temp = readb(sport->port.membase + UARTCR2);
|
|
@@ -2137,12 +2249,12 @@ static int lpuart_resume(struct device *dev)
|
|
|
if (sport->port.suspended && !sport->port.irq_wake)
|
|
|
clk_prepare_enable(sport->clk);
|
|
|
|
|
|
- if (sport->lpuart32) {
|
|
|
+ if (sport->port.iotype & (UPIO_MEM32 | UPIO_MEM32BE)) {
|
|
|
lpuart32_setup_watermark(sport);
|
|
|
- temp = lpuart32_read(sport->port.membase + UARTCTRL);
|
|
|
+ temp = lpuart32_read(&sport->port, UARTCTRL);
|
|
|
temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE |
|
|
|
UARTCTRL_TE | UARTCTRL_ILIE);
|
|
|
- lpuart32_write(temp, sport->port.membase + UARTCTRL);
|
|
|
+ lpuart32_write(&sport->port, temp, UARTCTRL);
|
|
|
} else {
|
|
|
lpuart_setup_watermark(sport);
|
|
|
temp = readb(sport->port.membase + UARTCR2);
|