[U-Boot] [PATCH V3 14/19] serial: lpuart: add i.MX7ULP support

Peng Fan peng.fan at nxp.com
Wed Feb 22 08:21:52 UTC 2017


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 at nxp.com>
Cc: Stefano Babic <sbabic at denx.de>
Cc: Bhuvanchandra DV <bhuvanchandra.dv at toradex.com>
Cc: York Sun <york.sun at nxp.com>
Cc: Shaohui Xie <Shaohui.Xie at nxp.com>
Cc: Alison Wang <b18965 at freescale.com>
---
V3:
 None
V2:
 New

 drivers/serial/serial_lpuart.c | 113 +++++++++++++++++++++++++++++++++++++----
 include/fsl_lpuart.h           |  72 ++++++++++++++++++++++++++
 2 files changed, 176 insertions(+), 9 deletions(-)
 create mode 100644 include/fsl_lpuart.h

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)
-- 
2.6.2



More information about the U-Boot mailing list