aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeng Fan <peng.fan@nxp.com>2017-02-22 16:21:52 +0800
committerStefano Babic <sbabic@denx.de>2017-03-17 09:27:08 +0100
commit7edf5c45f0d7f78ba370013cf513e3e8356c5202 (patch)
treeddda2916c295e2bb02b54c368762a9132e6c44ab
parentc40d612b1a6e1c63f27089d1d8fa3016164cacdb (diff)
downloadu-boot-7edf5c45f0d7f78ba370013cf513e3e8356c5202.zip
u-boot-7edf5c45f0d7f78ba370013cf513e3e8356c5202.tar.gz
u-boot-7edf5c45f0d7f78ba370013cf513e3e8356c5202.tar.bz2
serial: lpuart: add i.MX7ULP support
Add i.MX7ULP support. The buadrate calculation on i.MX7ULP is different,so add a new setbrg function for i.MX7ULP. Add a enum lpuart_devtype for runtime check for different platforms. Signed-off-by: Peng Fan <peng.fan@nxp.com> Cc: Stefano Babic <sbabic@denx.de> Cc: Bhuvanchandra DV <bhuvanchandra.dv@toradex.com> Cc: York Sun <york.sun@nxp.com> Cc: Shaohui Xie <Shaohui.Xie@nxp.com> Cc: Alison Wang <b18965@freescale.com>
-rw-r--r--drivers/serial/serial_lpuart.c113
-rw-r--r--include/fsl_lpuart.h72
2 files changed, 176 insertions, 9 deletions
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index 3f030a6..95e002e 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -52,8 +52,15 @@ DECLARE_GLOBAL_DATA_PTR;
#define LPUART_FLAG_REGMAP_32BIT_REG BIT(0)
#define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1)
+enum lpuart_devtype {
+ DEV_VF610 = 1,
+ DEV_LS1021A,
+ DEV_MX7ULP
+};
+
struct lpuart_serial_platdata {
void *reg;
+ enum lpuart_devtype devtype;
ulong flags;
};
@@ -172,6 +179,65 @@ static int _lpuart_serial_init(struct lpuart_serial_platdata *plat)
return 0;
}
+static void _lpuart32_serial_setbrg_7ulp(struct lpuart_serial_platdata *plat,
+ int baudrate)
+{
+ struct lpuart_fsl_reg32 *base = plat->reg;
+ u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
+ u32 clk = get_lpuart_clk();
+
+ 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 void _lpuart32_serial_setbrg(struct lpuart_serial_platdata *plat,
int baudrate)
{
@@ -188,7 +254,7 @@ static void _lpuart32_serial_setbrg(struct lpuart_serial_platdata *plat,
static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat)
{
struct lpuart_fsl_reg32 *base = plat->reg;
- u32 stat;
+ u32 stat, val;
lpuart_read32(plat->flags, &base->stat, &stat);
while ((stat & STAT_RDRF) == 0) {
@@ -197,10 +263,15 @@ static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat)
lpuart_read32(plat->flags, &base->stat, &stat);
}
- /* Reuse stat */
- lpuart_read32(plat->flags, &base->data, &stat);
+ lpuart_read32(plat->flags, &base->data, &val);
- return stat & 0x3ff;
+ if (plat->devtype & DEV_MX7ULP) {
+ lpuart_read32(plat->flags, &base->stat, &stat);
+ if (stat & STAT_OR)
+ lpuart_write32(plat->flags, &base->stat, STAT_OR);
+ }
+
+ return val & 0x3ff;
}
static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat,
@@ -209,6 +280,11 @@ static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat,
struct lpuart_fsl_reg32 *base = plat->reg;
u32 stat;
+ if (plat->devtype & DEV_MX7ULP) {
+ if (c == '\n')
+ serial_putc('\r');
+ }
+
while (true) {
lpuart_read32(plat->flags, &base->stat, &stat);
@@ -254,8 +330,12 @@ static int _lpuart32_serial_init(struct lpuart_serial_platdata *plat)
lpuart_write32(plat->flags, &base->match, 0);
- /* provide data bits, parity, stop bit, etc */
- _lpuart32_serial_setbrg(plat, gd->baudrate);
+ if (plat->devtype & DEV_MX7ULP) {
+ _lpuart32_serial_setbrg_7ulp(plat, gd->baudrate);
+ } else {
+ /* provide data bits, parity, stop bit, etc */
+ _lpuart32_serial_setbrg(plat, gd->baudrate);
+ }
lpuart_write32(plat->flags, &base->ctrl, CTRL_RE | CTRL_TE);
@@ -266,10 +346,14 @@ static int lpuart_serial_setbrg(struct udevice *dev, int baudrate)
{
struct lpuart_serial_platdata *plat = dev->platdata;
- if (is_lpuart32(dev))
- _lpuart32_serial_setbrg(plat, baudrate);
- else
+ if (is_lpuart32(dev)) {
+ if (plat->devtype & DEV_MX7ULP)
+ _lpuart32_serial_setbrg_7ulp(plat, baudrate);
+ else
+ _lpuart32_serial_setbrg(plat, baudrate);
+ } else {
_lpuart_serial_setbrg(plat, baudrate);
+ }
return 0;
}
@@ -331,6 +415,8 @@ static int lpuart_serial_probe(struct udevice *dev)
static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
{
struct lpuart_serial_platdata *plat = dev->platdata;
+ const void *blob = gd->fdt_blob;
+ int node = dev->of_offset;
fdt_addr_t addr;
addr = dev_get_addr(dev);
@@ -340,6 +426,13 @@ static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
plat->reg = (void *)addr;
plat->flags = dev_get_driver_data(dev);
+ if (!fdt_node_check_compatible(blob, node, "fsl,ls1021a-lpuart"))
+ plat->devtype = DEV_LS1021A;
+ else if (!fdt_node_check_compatible(blob, node, "fsl,imx7ulp-lpuart"))
+ plat->devtype = DEV_MX7ULP;
+ else if (!fdt_node_check_compatible(blob, node, "fsl,vf610-lpuart"))
+ plat->devtype = DEV_VF610;
+
return 0;
}
@@ -353,6 +446,8 @@ static const struct dm_serial_ops lpuart_serial_ops = {
static const struct udevice_id lpuart_serial_ids[] = {
{ .compatible = "fsl,ls1021a-lpuart", .data =
LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG },
+ { .compatible = "fsl,imx7ulp-lpuart",
+ .data = LPUART_FLAG_REGMAP_32BIT_REG },
{ .compatible = "fsl,vf610-lpuart"},
{ }
};
diff --git a/include/fsl_lpuart.h b/include/fsl_lpuart.h
new file mode 100644
index 0000000..4643ee7
--- /dev/null
+++ b/include/fsl_lpuart.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ */
+
+#ifdef CONFIG_ARCH_MX7ULP
+struct lpuart_fsl_reg32 {
+ u32 verid;
+ u32 param;
+ u32 global;
+ u32 pincfg;
+ u32 baud;
+ u32 stat;
+ u32 ctrl;
+ u32 data;
+ u32 match;
+ u32 modir;
+ u32 fifo;
+ u32 water;
+};
+#else
+struct lpuart_fsl_reg32 {
+ u32 baud;
+ u32 stat;
+ u32 ctrl;
+ u32 data;
+ u32 match;
+ u32 modir;
+ u32 fifo;
+ u32 water;
+};
+#endif
+
+struct lpuart_fsl {
+ u8 ubdh;
+ u8 ubdl;
+ u8 uc1;
+ u8 uc2;
+ u8 us1;
+ u8 us2;
+ u8 uc3;
+ u8 ud;
+ u8 uma1;
+ u8 uma2;
+ u8 uc4;
+ u8 uc5;
+ u8 ued;
+ u8 umodem;
+ u8 uir;
+ u8 reserved;
+ u8 upfifo;
+ u8 ucfifo;
+ u8 usfifo;
+ u8 utwfifo;
+ u8 utcfifo;
+ u8 urwfifo;
+ u8 urcfifo;
+ u8 rsvd[28];
+};
+
+/* Used on i.MX7ULP */
+#define LPUART_BAUD_BOTHEDGE_MASK (0x20000)
+#define LPUART_BAUD_OSR_MASK (0x1F000000)
+#define LPUART_BAUD_OSR_SHIFT (24)
+#define LPUART_BAUD_OSR(x) ((((uint32_t)(x)) << 24) & 0x1F000000)
+#define LPUART_BAUD_SBR_MASK (0x1FFF)
+#define LPUART_BAUD_SBR_SHIFT (0U)
+#define LPUART_BAUD_SBR(x) (((uint32_t)(x)) & 0x1FFF)
+#define LPUART_BAUD_M10_MASK (0x20000000U)
+#define LPUART_BAUD_SBNS_MASK (0x2000U)