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:
parent
c40d612b1a
commit
7edf5c45f0
|
@ -52,8 +52,15 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||||
#define LPUART_FLAG_REGMAP_32BIT_REG BIT(0)
|
#define LPUART_FLAG_REGMAP_32BIT_REG BIT(0)
|
||||||
#define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1)
|
#define LPUART_FLAG_REGMAP_ENDIAN_BIG BIT(1)
|
||||||
|
|
||||||
|
enum lpuart_devtype {
|
||||||
|
DEV_VF610 = 1,
|
||||||
|
DEV_LS1021A,
|
||||||
|
DEV_MX7ULP
|
||||||
|
};
|
||||||
|
|
||||||
struct lpuart_serial_platdata {
|
struct lpuart_serial_platdata {
|
||||||
void *reg;
|
void *reg;
|
||||||
|
enum lpuart_devtype devtype;
|
||||||
ulong flags;
|
ulong flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -172,6 +179,65 @@ static int _lpuart_serial_init(struct lpuart_serial_platdata *plat)
|
||||||
return 0;
|
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,
|
static void _lpuart32_serial_setbrg(struct lpuart_serial_platdata *plat,
|
||||||
int baudrate)
|
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)
|
static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat)
|
||||||
{
|
{
|
||||||
struct lpuart_fsl_reg32 *base = plat->reg;
|
struct lpuart_fsl_reg32 *base = plat->reg;
|
||||||
u32 stat;
|
u32 stat, val;
|
||||||
|
|
||||||
lpuart_read32(plat->flags, &base->stat, &stat);
|
lpuart_read32(plat->flags, &base->stat, &stat);
|
||||||
while ((stat & STAT_RDRF) == 0) {
|
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);
|
lpuart_read32(plat->flags, &base->stat, &stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reuse stat */
|
lpuart_read32(plat->flags, &base->data, &val);
|
||||||
lpuart_read32(plat->flags, &base->data, &stat);
|
|
||||||
|
|
||||||
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,
|
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;
|
struct lpuart_fsl_reg32 *base = plat->reg;
|
||||||
u32 stat;
|
u32 stat;
|
||||||
|
|
||||||
|
if (plat->devtype & DEV_MX7ULP) {
|
||||||
|
if (c == '\n')
|
||||||
|
serial_putc('\r');
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
lpuart_read32(plat->flags, &base->stat, &stat);
|
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);
|
lpuart_write32(plat->flags, &base->match, 0);
|
||||||
|
|
||||||
/* provide data bits, parity, stop bit, etc */
|
if (plat->devtype & DEV_MX7ULP) {
|
||||||
_lpuart32_serial_setbrg(plat, gd->baudrate);
|
_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);
|
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;
|
struct lpuart_serial_platdata *plat = dev->platdata;
|
||||||
|
|
||||||
if (is_lpuart32(dev))
|
if (is_lpuart32(dev)) {
|
||||||
_lpuart32_serial_setbrg(plat, baudrate);
|
if (plat->devtype & DEV_MX7ULP)
|
||||||
else
|
_lpuart32_serial_setbrg_7ulp(plat, baudrate);
|
||||||
|
else
|
||||||
|
_lpuart32_serial_setbrg(plat, baudrate);
|
||||||
|
} else {
|
||||||
_lpuart_serial_setbrg(plat, baudrate);
|
_lpuart_serial_setbrg(plat, baudrate);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -331,6 +415,8 @@ static int lpuart_serial_probe(struct udevice *dev)
|
||||||
static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
|
static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
|
||||||
{
|
{
|
||||||
struct lpuart_serial_platdata *plat = dev->platdata;
|
struct lpuart_serial_platdata *plat = dev->platdata;
|
||||||
|
const void *blob = gd->fdt_blob;
|
||||||
|
int node = dev->of_offset;
|
||||||
fdt_addr_t addr;
|
fdt_addr_t addr;
|
||||||
|
|
||||||
addr = dev_get_addr(dev);
|
addr = dev_get_addr(dev);
|
||||||
|
@ -340,6 +426,13 @@ static int lpuart_serial_ofdata_to_platdata(struct udevice *dev)
|
||||||
plat->reg = (void *)addr;
|
plat->reg = (void *)addr;
|
||||||
plat->flags = dev_get_driver_data(dev);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,6 +446,8 @@ static const struct dm_serial_ops lpuart_serial_ops = {
|
||||||
static const struct udevice_id lpuart_serial_ids[] = {
|
static const struct udevice_id lpuart_serial_ids[] = {
|
||||||
{ .compatible = "fsl,ls1021a-lpuart", .data =
|
{ .compatible = "fsl,ls1021a-lpuart", .data =
|
||||||
LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG },
|
LPUART_FLAG_REGMAP_32BIT_REG | LPUART_FLAG_REGMAP_ENDIAN_BIG },
|
||||||
|
{ .compatible = "fsl,imx7ulp-lpuart",
|
||||||
|
.data = LPUART_FLAG_REGMAP_32BIT_REG },
|
||||||
{ .compatible = "fsl,vf610-lpuart"},
|
{ .compatible = "fsl,vf610-lpuart"},
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue