summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/arch-mx7ulp/imx-regs.h42
-rw-r--r--drivers/serial/serial_lpuart.c180
2 files changed, 219 insertions, 3 deletions
diff --git a/arch/arm/include/asm/arch-mx7ulp/imx-regs.h b/arch/arm/include/asm/arch-mx7ulp/imx-regs.h
index 9fbef8c..ee38e01 100644
--- a/arch/arm/include/asm/arch-mx7ulp/imx-regs.h
+++ b/arch/arm/include/asm/arch-mx7ulp/imx-regs.h
@@ -1142,6 +1142,48 @@ struct usbphy_regs {
u32 usb1_pfda_ctrl1_tog; /* 0x14c */
};
+struct lpuart_fsl {
+ u32 verid;
+ u32 param;
+ u32 global;
+ u32 pincfg;
+ u32 baud;
+ u32 stat;
+ u32 ctrl;
+ u32 data;
+ u32 match;
+ u32 modir;
+ u32 fifo;
+ u32 water;
+};
+
+#define LPUART_BAUD_SBR_MASK (0x1FFFU)
+#define LPUART_BAUD_SBR_SHIFT (0U)
+#define LPUART_BAUD_SBR(x) (((uint32_t)(((uint32_t)(x)) << LPUART_BAUD_SBR_SHIFT)) & LPUART_BAUD_SBR_MASK)
+#define LPUART_BAUD_SBNS_MASK (0x2000U)
+#define LPUART_BAUD_SBNS_SHIFT (13U)
+#define LPUART_BAUD_SBNS(x) (((uint32_t)(((uint32_t)(x)) << LPUART_BAUD_SBNS_SHIFT)) & LPUART_BAUD_SBNS_MASK)
+#define LPUART_BAUD_BOTHEDGE_MASK (0x20000U)
+#define LPUART_BAUD_BOTHEDGE_SHIFT (17U)
+#define LPUART_BAUD_BOTHEDGE(x) (((uint32_t)(((uint32_t)(x)) << LPUART_BAUD_BOTHEDGE_SHIFT)) & LPUART_BAUD_BOTHEDGE_MASK)
+#define LPUART_BAUD_OSR_MASK (0x1F000000U)
+#define LPUART_BAUD_OSR_SHIFT (24U)
+#define LPUART_BAUD_OSR(x) (((uint32_t)(((uint32_t)(x)) << LPUART_BAUD_OSR_SHIFT)) & LPUART_BAUD_OSR_MASK)
+#define LPUART_BAUD_M10_MASK (0x20000000U)
+#define LPUART_BAUD_M10_SHIFT (29U)
+#define LPUART_BAUD_M10(x) (((uint32_t)(((uint32_t)(x)) << LPUART_BAUD_M10_SHIFT)) & LPUART_BAUD_M10_MASK)
+
+/*! @name CTRL - LPUART Control Register */
+#define LPUART_CTRL_PT_MASK (0x1U)
+#define LPUART_CTRL_PT_SHIFT (0U)
+#define LPUART_CTRL_PT(x) (((uint32_t)(((uint32_t)(x)) << LPUART_CTRL_PT_SHIFT)) & LPUART_CTRL_PT_MASK)
+#define LPUART_CTRL_PE_MASK (0x2U)
+#define LPUART_CTRL_PE_SHIFT (1U)
+#define LPUART_CTRL_PE(x) (((uint32_t)(((uint32_t)(x)) << LPUART_CTRL_PE_SHIFT)) & LPUART_CTRL_PE_MASK)
+#define LPUART_CTRL_M_MASK (0x10U)
+#define LPUART_CTRL_M_SHIFT (4U)
+#define LPUART_CTRL_M(x) (((uint32_t)(((uint32_t)(x)) << LPUART_CTRL_M_SHIFT)) & LPUART_CTRL_M_MASK)
+
#define is_boot_from_usb(void) (!(readl(USB_PHY0_BASE_ADDR) & (1<<20)))
#define disconnect_from_pc(void) writel(0x0, USBOTG0_RBASE + 0x140)
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index fc3321f..607187c 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -52,7 +52,179 @@ struct lpuart_serial_platdata {
struct lpuart_fsl *reg;
};
-#ifndef CONFIG_LPUART_32B_REG
+#ifdef CONFIG_LPUART_32LE_REG
+static void _lpuart32_serial_setbrg(struct lpuart_fsl *base, int baudrate)
+{
+ u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
+ u32 clk = imx_get_uartclk();
+
+ baud_diff = baudrate;
+ osr = 0;
+ sbr = 0;
+
+ for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
+ tmp_sbr = (clk / (baudrate * tmp_osr));
+
+ if (tmp_sbr == 0)
+ tmp_sbr = 1;
+
+ /*calculate difference in actual buad w/ current values */
+ tmp_diff = (clk / (tmp_osr * tmp_sbr));
+ tmp_diff = tmp_diff - baudrate;
+
+ /* select best values between sbr and sbr+1 */
+ if (tmp_diff > (baudrate - (clk / (tmp_osr * (tmp_sbr + 1))))) {
+ tmp_diff = baudrate - (clk / (tmp_osr * (tmp_sbr + 1)));
+ tmp_sbr++;
+ }
+
+ if (tmp_diff <= baud_diff) {
+ baud_diff = tmp_diff;
+ osr = tmp_osr;
+ sbr = tmp_sbr;
+ }
+ }
+
+ /*TODO handle buadrate outside acceptable rate
+ * if (baudDiff > ((config->baudRate_Bps / 100) * 3))
+ * {
+ * Unacceptable baud rate difference of more than 3%
+ * return kStatus_LPUART_BaudrateNotSupport;
+ * }
+ *
+ */
+ tmp = in_le32(&base->baud);
+
+ if ((osr > 3) && (osr < 8))
+ tmp |= LPUART_BAUD_BOTHEDGE_MASK;
+
+ tmp &= ~LPUART_BAUD_OSR_MASK;
+ tmp |= LPUART_BAUD_OSR(osr-1);
+
+ tmp &= ~LPUART_BAUD_SBR_MASK;
+ tmp |= LPUART_BAUD_SBR(sbr);
+
+ /* explicitly disable 10 bit mode & set 1 stop bit */
+ tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK);
+
+ out_le32(&base->baud, tmp);
+}
+
+static int _lpuart32_serial_getc(struct lpuart_fsl *base)
+{
+ int ch;
+
+ while (!(in_le32(&base->stat) & STAT_RDRF))
+ WATCHDOG_RESET();
+
+ ch = in_le32(&base->data) & 0x3ff;
+ if (in_le32(&base->stat) & STAT_OR)
+ out_le32(&base->stat, STAT_OR);
+
+ return ch;
+}
+
+static void _lpuart32_serial_putc(struct lpuart_fsl *base, const char c)
+{
+ if (c == '\n')
+ serial_putc('\r');
+
+ while (!(in_le32(&base->stat) & STAT_TDRE))
+ WATCHDOG_RESET();
+
+ out_le32(&base->data, c);
+}
+
+/*
+ * Test whether a character is in the RX buffer
+ */
+static int _lpuart32_serial_tstc(struct lpuart_fsl *base)
+{
+ if ((in_le32(&base->water) >> 24) == 0)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Initialise the serial port with the given baudrate. The settings
+ * are always 8 data bits, no parity, 1 stop bit, no start bits.
+ */
+static int _lpuart32_serial_init(struct lpuart_fsl *base)
+{
+ u32 tmp;
+
+ /*disable TX & RX before enabling clocks */
+ tmp = in_le32(&base->ctrl);
+ tmp &= ~(CTRL_TE | CTRL_RE);
+ out_le32(&base->ctrl, tmp);
+
+ out_le32(&base->modir, 0);
+ out_le32(&base->fifo, ~(FIFO_TXFE | FIFO_RXFE));
+
+ out_le32(&base->match, 0);
+
+ /* provide data bits, parity, stop bit, etc */
+ _lpuart32_serial_setbrg(base, gd->baudrate);
+
+ /* eight data bits no parity bit */
+ tmp = in_le32(&base->ctrl);
+ tmp &= ~(LPUART_CTRL_PE_MASK | LPUART_CTRL_PT_MASK | LPUART_CTRL_M_MASK);
+ out_le32(&base->ctrl, tmp);
+
+ out_le32(&base->ctrl, CTRL_RE | CTRL_TE);
+
+ return 0;
+}
+
+static int lpuart32_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ _lpuart32_serial_setbrg(reg, baudrate);
+
+ return 0;
+}
+
+static int lpuart32_serial_getc(struct udevice *dev)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ return _lpuart32_serial_getc(reg);
+}
+
+static int lpuart32_serial_putc(struct udevice *dev, const char c)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ _lpuart32_serial_putc(reg, c);
+
+ return 0;
+}
+
+static int lpuart32_serial_pending(struct udevice *dev, bool input)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ if (input)
+ return _lpuart32_serial_tstc(reg);
+ else
+ return in_le32(&reg->stat) & STAT_TDRE ? 0 : 1;
+}
+
+static int lpuart32_serial_probe(struct udevice *dev)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+ struct lpuart_fsl *reg = plat->reg;
+
+ return _lpuart32_serial_init(reg);
+}
+
+#elif !defined(CONFIG_LPUART_32B_REG)
static void _lpuart_serial_setbrg(struct lpuart_fsl *base, int baudrate)
{
u32 clk = mxc_get_clock(MXC_UART_CLK);
@@ -171,6 +343,7 @@ static int lpuart_serial_probe(struct udevice *dev)
return _lpuart_serial_init(reg);
}
+
#else
static void _lpuart32_serial_setbrg(struct lpuart_fsl *base, int baudrate)
@@ -304,7 +477,7 @@ static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
return 0;
}
-#ifndef CONFIG_LPUART_32B_REG
+#if !defined(CONFIG_LPUART_32B_REG) && !defined(CONFIG_LPUART_32LE_REG)
static const struct dm_serial_ops lpuart_serial_ops = {
.putc = lpuart_serial_putc,
.pending = lpuart_serial_pending,
@@ -327,7 +500,7 @@ U_BOOT_DRIVER(serial_lpuart) = {
.ops = &lpuart_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};
-#else /* CONFIG_LPUART_32B_REG */
+#else /* CONFIG_LPUART_32B_REG || CONFIG_LPUART_32LE_REG */
static const struct dm_serial_ops lpuart32_serial_ops = {
.putc = lpuart32_serial_putc,
.pending = lpuart32_serial_pending,
@@ -337,6 +510,7 @@ static const struct dm_serial_ops lpuart32_serial_ops = {
static const struct udevice_id lpuart32_serial_ids[] = {
{ .compatible = "fsl,ls1021a-lpuart" },
+ { .compatible = "fsl,imx7ulp-lpuart" },
{ }
};