diff options
author | Peng Fan <peng.fan@nxp.com> | 2017-02-22 16:21:52 +0800 |
---|---|---|
committer | Stefano Babic <sbabic@denx.de> | 2017-03-17 09:27:08 +0100 |
commit | 7edf5c45f0d7f78ba370013cf513e3e8356c5202 (patch) | |
tree | ddda2916c295e2bb02b54c368762a9132e6c44ab /drivers/serial/serial_lpuart.c | |
parent | c40d612b1a6e1c63f27089d1d8fa3016164cacdb (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.c | 113 |
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"}, { } }; |