summaryrefslogtreecommitdiff
path: root/drivers/serial/serial_lpuart.c
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 /drivers/serial/serial_lpuart.c
parentc40d612b1a6e1c63f27089d1d8fa3016164cacdb (diff)
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>
Diffstat (limited to 'drivers/serial/serial_lpuart.c')
-rw-r--r--drivers/serial/serial_lpuart.c113
1 files changed, 104 insertions, 9 deletions
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index 3f030a622f..95e002ea4b 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"},
{ }
};