mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 15:14:43 +00:00
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
2 changed files with 176 additions and 9 deletions
|
@ -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
72
include/fsl_lpuart.h
Normal 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)
|
Loading…
Reference in a new issue