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>
This commit is contained in:
Peng Fan 2017-02-22 16:21:52 +08:00 committed by Stefano Babic
parent c40d612b1a
commit 7edf5c45f0
2 changed files with 176 additions and 9 deletions

View file

@ -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"},
{ }
};

72
include/fsl_lpuart.h Normal file
View file

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