summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Kconfig7
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/imx_rgpio2p.c224
-rw-r--r--drivers/i2c/Kconfig6
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/imx_lpi2c.c462
-rw-r--r--drivers/misc/mxc_ocotp.c52
-rw-r--r--drivers/mmc/fsl_esdhc.c8
-rw-r--r--drivers/pinctrl/nxp/Kconfig14
-rw-r--r--drivers/pinctrl/nxp/Makefile1
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx.c10
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx.h3
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx7ulp.c41
-rw-r--r--drivers/serial/serial_lpuart.c336
-rw-r--r--drivers/serial/serial_mxc.c1
-rw-r--r--drivers/watchdog/Kconfig8
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/ulp_wdog.c98
18 files changed, 1157 insertions, 117 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 8d9ab52..dc4108f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -48,6 +48,13 @@ config INTEL_BROADWELL_GPIO
driver from the common Intel ICH6 driver. It supports a total of
95 GPIOs which can be configured from the device tree.
+config IMX_RGPIO2P
+ bool "i.MX7ULP RGPIO2P driver"
+ depends on DM
+ default n
+ help
+ This driver supports i.MX7ULP Rapid GPIO2P controller.
+
config LPC32XX_GPIO
bool "LPC32XX GPIO driver"
depends on DM
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 8939226..27f8068 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o
obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o
obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o
obj-$(CONFIG_HIKEY_GPIO) += hi6220_gpio.o
+obj-$(CONFIG_IMX_RGPIO2P) += imx_rgpio2p.o
obj-$(CONFIG_PIC32_GPIO) += pic32_gpio.o
obj-$(CONFIG_MVEBU_GPIO) += mvebu_gpio.o
obj-$(CONFIG_MSM_GPIO) += msm_gpio.o
diff --git a/drivers/gpio/imx_rgpio2p.c b/drivers/gpio/imx_rgpio2p.c
new file mode 100644
index 0000000..886b161
--- /dev/null
+++ b/drivers/gpio/imx_rgpio2p.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * RGPIO2P driver for the Freescale i.MX7ULP.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum imx_rgpio2p_direction {
+ IMX_RGPIO2P_DIRECTION_IN,
+ IMX_RGPIO2P_DIRECTION_OUT,
+};
+
+#define GPIO_PER_BANK 32
+
+struct imx_rgpio2p_data {
+ struct gpio_regs *regs;
+};
+
+struct imx_rgpio2p_plat {
+ int bank_index;
+ struct gpio_regs *regs;
+};
+
+static int imx_rgpio2p_is_output(struct gpio_regs *regs, int offset)
+{
+ u32 val;
+
+ val = readl(&regs->gpio_pddr);
+
+ return val & (1 << offset) ? 1 : 0;
+}
+
+static void imx_rgpio2p_bank_direction(struct gpio_regs *regs, int offset,
+ enum imx_rgpio2p_direction direction)
+{
+ u32 l;
+
+ l = readl(&regs->gpio_pddr);
+
+ switch (direction) {
+ case IMX_RGPIO2P_DIRECTION_OUT:
+ l |= 1 << offset;
+ break;
+ case IMX_RGPIO2P_DIRECTION_IN:
+ l &= ~(1 << offset);
+ }
+ writel(l, &regs->gpio_pddr);
+}
+
+static void imx_rgpio2p_bank_set_value(struct gpio_regs *regs, int offset,
+ int value)
+{
+ if (value)
+ writel((1 << offset), &regs->gpio_psor);
+ else
+ writel((1 << offset), &regs->gpio_pcor);
+}
+
+static int imx_rgpio2p_bank_get_value(struct gpio_regs *regs, int offset)
+{
+ return (readl(&regs->gpio_pdir) >> offset) & 0x01;
+}
+
+static int imx_rgpio2p_direction_input(struct udevice *dev, unsigned offset)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+
+ /* Configure GPIO direction as input. */
+ imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_IN);
+
+ return 0;
+}
+
+static int imx_rgpio2p_direction_output(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+
+ /* Configure GPIO output value. */
+ imx_rgpio2p_bank_set_value(bank->regs, offset, value);
+
+ /* Configure GPIO direction as output. */
+ imx_rgpio2p_bank_direction(bank->regs, offset, IMX_RGPIO2P_DIRECTION_OUT);
+
+ return 0;
+}
+
+static int imx_rgpio2p_get_value(struct udevice *dev, unsigned offset)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+
+ return imx_rgpio2p_bank_get_value(bank->regs, offset);
+}
+
+static int imx_rgpio2p_set_value(struct udevice *dev, unsigned offset,
+ int value)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+
+ imx_rgpio2p_bank_set_value(bank->regs, offset, value);
+
+ return 0;
+}
+
+static int imx_rgpio2p_get_function(struct udevice *dev, unsigned offset)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+
+ /* GPIOF_FUNC is not implemented yet */
+ if (imx_rgpio2p_is_output(bank->regs, offset))
+ return GPIOF_OUTPUT;
+ else
+ return GPIOF_INPUT;
+}
+
+static const struct dm_gpio_ops imx_rgpio2p_ops = {
+ .direction_input = imx_rgpio2p_direction_input,
+ .direction_output = imx_rgpio2p_direction_output,
+ .get_value = imx_rgpio2p_get_value,
+ .set_value = imx_rgpio2p_set_value,
+ .get_function = imx_rgpio2p_get_function,
+};
+
+static int imx_rgpio2p_probe(struct udevice *dev)
+{
+ struct imx_rgpio2p_data *bank = dev_get_priv(dev);
+ struct imx_rgpio2p_plat *plat = dev_get_platdata(dev);
+ struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+ int banknum;
+ char name[18], *str;
+
+ banknum = plat->bank_index;
+ sprintf(name, "GPIO%d_", banknum + 1);
+ str = strdup(name);
+ if (!str)
+ return -ENOMEM;
+ uc_priv->bank_name = str;
+ uc_priv->gpio_count = GPIO_PER_BANK;
+ bank->regs = plat->regs;
+
+ return 0;
+}
+
+static int imx_rgpio2p_bind(struct udevice *dev)
+{
+ struct imx_rgpio2p_plat *plat = dev->platdata;
+ fdt_addr_t addr;
+
+ /*
+ * If platdata already exsits, directly return.
+ * Actually only when DT is not supported, platdata
+ * is statically initialized in U_BOOT_DEVICES.Here
+ * will return.
+ */
+ if (plat)
+ return 0;
+
+ addr = dev_get_addr_index(dev, 1);
+ if (addr == FDT_ADDR_T_NONE)
+ return -ENODEV;
+
+ /*
+ * TODO:
+ * When every board is converted to driver model and DT is supported,
+ * this can be done by auto-alloc feature, but not using calloc
+ * to alloc memory for platdata.
+ */
+ plat = calloc(1, sizeof(*plat));
+ if (!plat)
+ return -ENOMEM;
+
+ plat->regs = (struct gpio_regs *)addr;
+ plat->bank_index = dev->req_seq;
+ dev->platdata = plat;
+
+ return 0;
+}
+
+
+static const struct udevice_id imx_rgpio2p_ids[] = {
+ { .compatible = "fsl,imx7ulp-gpio" },
+ { }
+};
+
+U_BOOT_DRIVER(imx_rgpio2p) = {
+ .name = "imx_rgpio2p",
+ .id = UCLASS_GPIO,
+ .ops = &imx_rgpio2p_ops,
+ .probe = imx_rgpio2p_probe,
+ .priv_auto_alloc_size = sizeof(struct imx_rgpio2p_plat),
+ .of_match = imx_rgpio2p_ids,
+ .bind = imx_rgpio2p_bind,
+};
+
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
+static const struct imx_rgpio2p_plat imx_plat[] = {
+ { 0, (struct gpio_regs *)RGPIO2P_GPIO1_BASE_ADDR },
+ { 1, (struct gpio_regs *)RGPIO2P_GPIO2_BASE_ADDR },
+ { 2, (struct gpio_regs *)RGPIO2P_GPIO3_BASE_ADDR },
+ { 3, (struct gpio_regs *)RGPIO2P_GPIO4_BASE_ADDR },
+ { 4, (struct gpio_regs *)RGPIO2P_GPIO5_BASE_ADDR },
+ { 5, (struct gpio_regs *)RGPIO2P_GPIO6_BASE_ADDR },
+};
+
+U_BOOT_DEVICES(imx_rgpio2ps) = {
+ { "imx_rgpio2p", &imx_plat[0] },
+ { "imx_rgpio2p", &imx_plat[1] },
+ { "imx_rgpio2p", &imx_plat[2] },
+ { "imx_rgpio2p", &imx_plat[3] },
+ { "imx_rgpio2p", &imx_plat[4] },
+ { "imx_rgpio2p", &imx_plat[5] },
+};
+#endif
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 39f62da..8ac7aaf 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -109,6 +109,12 @@ config SYS_I2C_INTEL
the I2C API meaning that any I2C operations will immediately fail
for now.
+config SYS_I2C_IMX_LPI2C
+ bool "NXP i.MX LPI2C driver"
+ depends on ARCH_MX7ULP
+ help
+ Add support for the NXP i.MX LPI2C driver.
+
config SYS_I2C_MXC
bool "NXP i.MX I2C driver"
depends on MX6
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 7c86198..446af22 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_SYS_I2C_FSL) += fsl_i2c.o
obj-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o
obj-$(CONFIG_SYS_I2C_IHS) += ihs_i2c.o
obj-$(CONFIG_SYS_I2C_INTEL) += intel_i2c.o
+obj-$(CONFIG_SYS_I2C_IMX_LPI2C) += imx_lpi2c.o
obj-$(CONFIG_SYS_I2C_KONA) += kona_i2c.o
obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
diff --git a/drivers/i2c/imx_lpi2c.c b/drivers/i2c/imx_lpi2c.c
new file mode 100644
index 0000000..f792d44
--- /dev/null
+++ b/drivers/i2c/imx_lpi2c.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2016 Freescale Semiconductors, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/imx_lpi2c.h>
+#include <asm/arch/sys_proto.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+#define LPI2C_FIFO_SIZE 4
+#define LPI2C_TIMEOUT_MS 100
+
+/* Weak linked function for overridden by some SoC power function */
+int __weak init_i2c_power(unsigned i2c_num)
+{
+ return 0;
+}
+
+static int imx_lpci2c_check_busy_bus(struct udevice *bus)
+{
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)dev_get_addr(bus);
+ lpi2c_status_t result = LPI2C_SUCESS;
+ u32 status;
+
+ status = readl(&regs->msr);
+
+ if ((status & LPI2C_MSR_BBF_MASK) && !(status & LPI2C_MSR_MBF_MASK))
+ result = LPI2C_BUSY;
+
+ return result;
+}
+
+static int imx_lpci2c_check_clear_error(struct udevice *bus)
+{
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)dev_get_addr(bus);
+ lpi2c_status_t result = LPI2C_SUCESS;
+ u32 val, status;
+
+ status = readl(&regs->msr);
+ /* errors to check for */
+ status &= LPI2C_MSR_NDF_MASK | LPI2C_MSR_ALF_MASK |
+ LPI2C_MSR_FEF_MASK | LPI2C_MSR_PLTF_MASK;
+
+ if (status) {
+ if (status & LPI2C_MSR_PLTF_MASK)
+ result = LPI2C_PIN_LOW_TIMEOUT_ERR;
+ else if (status & LPI2C_MSR_ALF_MASK)
+ result = LPI2C_ARB_LOST_ERR;
+ else if (status & LPI2C_MSR_NDF_MASK)
+ result = LPI2C_NAK_ERR;
+ else if (status & LPI2C_MSR_FEF_MASK)
+ result = LPI2C_FIFO_ERR;
+
+ /* clear status flags */
+ writel(0x7f00, &regs->msr);
+ /* reset fifos */
+ val = readl(&regs->mcr);
+ val |= LPI2C_MCR_RRF_MASK | LPI2C_MCR_RTF_MASK;
+ writel(val, &regs->mcr);
+ }
+
+ return result;
+}
+
+static int bus_i2c_wait_for_tx_ready(struct udevice *bus)
+{
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)dev_get_addr(bus);
+ lpi2c_status_t result = LPI2C_SUCESS;
+ u32 txcount = 0;
+ ulong start_time = get_timer(0);
+
+ do {
+ txcount = LPI2C_MFSR_TXCOUNT(readl(&regs->mfsr));
+ txcount = LPI2C_FIFO_SIZE - txcount;
+ result = imx_lpci2c_check_clear_error(bus);
+ if (result) {
+ debug("i2c: wait for tx ready: result 0x%x\n", result);
+ return result;
+ }
+ if (get_timer(start_time) > LPI2C_TIMEOUT_MS) {
+ debug("i2c: wait for tx ready: timeout\n");
+ return -1;
+ }
+ } while (!txcount);
+
+ return result;
+}
+
+static int bus_i2c_send(struct udevice *bus, u8 *txbuf, int len)
+{
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)dev_get_addr(bus);
+ lpi2c_status_t result = LPI2C_SUCESS;
+
+ /* empty tx */
+ if (!len)
+ return result;
+
+ while (len--) {
+ result = bus_i2c_wait_for_tx_ready(bus);
+ if (result) {
+ debug("i2c: send wait fot tx ready: %d\n", result);
+ return result;
+ }
+ writel(*txbuf++, &regs->mtdr);
+ }
+
+ return result;
+}
+
+static int bus_i2c_receive(struct udevice *bus, u8 *rxbuf, int len)
+{
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)dev_get_addr(bus);
+ lpi2c_status_t result = LPI2C_SUCESS;
+ u32 val;
+ ulong start_time = get_timer(0);
+
+ /* empty read */
+ if (!len)
+ return result;
+
+ result = bus_i2c_wait_for_tx_ready(bus);
+ if (result) {
+ debug("i2c: receive wait fot tx ready: %d\n", result);
+ return result;
+ }
+
+ /* clear all status flags */
+ writel(0x7f00, &regs->msr);
+ /* send receive command */
+ val = LPI2C_MTDR_CMD(0x1) | LPI2C_MTDR_DATA(len - 1);
+ writel(val, &regs->mtdr);
+
+ while (len--) {
+ do {
+ result = imx_lpci2c_check_clear_error(bus);
+ if (result) {
+ debug("i2c: receive check clear error: %d\n", result);
+ return result;
+ }
+ if (get_timer(start_time) > LPI2C_TIMEOUT_MS) {
+ debug("i2c: receive mrdr: timeout\n");
+ return -1;
+ }
+ val = readl(&regs->mrdr);
+ } while (val & LPI2C_MRDR_RXEMPTY_MASK);
+ *rxbuf++ = LPI2C_MRDR_DATA(val);
+ }
+
+ return result;
+}
+
+static int bus_i2c_start(struct udevice *bus, u8 addr, u8 dir)
+{
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)dev_get_addr(bus);
+ lpi2c_status_t result = LPI2C_SUCESS;
+ u32 val;
+
+ result = imx_lpci2c_check_busy_bus(bus);
+ if (result) {
+ debug("i2c: start check busy bus: 0x%x\n", result);
+ return result;
+ }
+ /* clear all status flags */
+ writel(0x7f00, &regs->msr);
+ /* turn off auto-stop condition */
+ val = readl(&regs->mcfgr1) & ~LPI2C_MCFGR1_AUTOSTOP_MASK;
+ writel(val, &regs->mcfgr1);
+ /* wait tx fifo ready */
+ result = bus_i2c_wait_for_tx_ready(bus);
+ if (result) {
+ debug("i2c: start wait for tx ready: 0x%x\n", result);
+ return result;
+ }
+ /* issue start command */
+ val = LPI2C_MTDR_CMD(0x4) | (addr << 0x1) | dir;
+ writel(val, &regs->mtdr);
+
+ return result;
+}
+static int bus_i2c_stop(struct udevice *bus)
+{
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)dev_get_addr(bus);
+ lpi2c_status_t result = LPI2C_SUCESS;
+ u32 status;
+
+ result = bus_i2c_wait_for_tx_ready(bus);
+ if (result) {
+ debug("i2c: stop wait for tx ready: 0x%x\n", result);
+ return result;
+ }
+
+ /* send stop command */
+ writel(LPI2C_MTDR_CMD(0x2), &regs->mtdr);
+
+ while (result == LPI2C_SUCESS) {
+ status = readl(&regs->msr);
+ result = imx_lpci2c_check_clear_error(bus);
+ /* stop detect flag */
+ if (status & LPI2C_MSR_SDF_MASK) {
+ /* clear stop flag */
+ status &= LPI2C_MSR_SDF_MASK;
+ writel(status, &regs->msr);
+ break;
+ }
+ }
+
+ return result;
+}
+
+static int bus_i2c_read(struct udevice *bus, u32 chip, u8 *buf, int len)
+{
+ lpi2c_status_t result = LPI2C_SUCESS;
+
+ result = bus_i2c_start(bus, chip, 1);
+ if (result)
+ return result;
+ result = bus_i2c_receive(bus, buf, len);
+ if (result)
+ return result;
+ result = bus_i2c_stop(bus);
+ if (result)
+ return result;
+
+ return result;
+}
+
+static int bus_i2c_write(struct udevice *bus, u32 chip, u8 *buf, int len)
+{
+ lpi2c_status_t result = LPI2C_SUCESS;
+
+ result = bus_i2c_start(bus, chip, 0);
+ if (result)
+ return result;
+ result = bus_i2c_send(bus, buf, len);
+ if (result)
+ return result;
+ result = bus_i2c_stop(bus);
+ if (result)
+ return result;
+
+ return result;
+}
+
+
+static int bus_i2c_set_bus_speed(struct udevice *bus, int speed)
+{
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)dev_get_addr(bus);
+ u32 val;
+ u32 preescale = 0, best_pre = 0, clkhi = 0;
+ u32 best_clkhi = 0, abs_error = 0, rate;
+ u32 error = 0xffffffff;
+ u32 clock_rate;
+ bool mode;
+ int i;
+
+ clock_rate = imx_get_i2cclk(bus->seq + 4);
+ if (!clock_rate)
+ return -EPERM;
+
+ mode = (readl(&regs->mcr) & LPI2C_MCR_MEN_MASK) >> LPI2C_MCR_MEN_SHIFT;
+ /* disable master mode */
+ val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
+ writel(val | LPI2C_MCR_MEN(0), &regs->mcr);
+
+ for (preescale = 1; (preescale <= 128) &&
+ (error != 0); preescale = 2 * preescale) {
+ for (clkhi = 1; clkhi < 32; clkhi++) {
+ if (clkhi == 1)
+ rate = (clock_rate / preescale) / (1 + 3 + 2 + 2 / preescale);
+ else
+ rate = (clock_rate / preescale / (3 * clkhi + 2 + 2 / preescale));
+
+ abs_error = speed > rate ? speed - rate : rate - speed;
+
+ if (abs_error < error) {
+ best_pre = preescale;
+ best_clkhi = clkhi;
+ error = abs_error;
+ if (abs_error == 0)
+ break;
+ }
+ }
+ }
+
+ /* Standard, fast, fast mode plus and ultra-fast transfers. */
+ val = LPI2C_MCCR0_CLKHI(best_clkhi);
+ if (best_clkhi < 2)
+ val |= LPI2C_MCCR0_CLKLO(3) | LPI2C_MCCR0_SETHOLD(2) | LPI2C_MCCR0_DATAVD(1);
+ else
+ val |= LPI2C_MCCR0_CLKLO(2 * best_clkhi) | LPI2C_MCCR0_SETHOLD(best_clkhi) |
+ LPI2C_MCCR0_DATAVD(best_clkhi / 2);
+ writel(val, &regs->mccr0);
+
+ for (i = 0; i < 8; i++) {
+ if (best_pre == (1 << i)) {
+ best_pre = i;
+ break;
+ }
+ }
+
+ val = readl(&regs->mcfgr1) & ~LPI2C_MCFGR1_PRESCALE_MASK;
+ writel(val | LPI2C_MCFGR1_PRESCALE(best_pre), &regs->mcfgr1);
+
+ if (mode) {
+ val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
+ writel(val | LPI2C_MCR_MEN(1), &regs->mcr);
+ }
+
+ return 0;
+}
+
+static int bus_i2c_init(struct udevice *bus, int speed)
+{
+ struct imx_lpi2c_reg *regs = (struct imx_lpi2c_reg *)dev_get_addr(bus);
+ u32 val;
+ int ret;
+
+ /* reset peripheral */
+ writel(LPI2C_MCR_RST_MASK, &regs->mcr);
+ writel(0x0, &regs->mcr);
+ /* Disable Dozen mode */
+ writel(LPI2C_MCR_DBGEN(0) | LPI2C_MCR_DOZEN(1), &regs->mcr);
+ /* host request disable, active high, external pin */
+ val = readl(&regs->mcfgr0);
+ val &= (~(LPI2C_MCFGR0_HREN_MASK | LPI2C_MCFGR0_HRPOL_MASK |
+ LPI2C_MCFGR0_HRSEL_MASK));
+ val |= LPI2C_MCFGR0_HRPOL(0x1);
+ writel(val, &regs->mcfgr0);
+ /* pincfg and ignore ack */
+ val = readl(&regs->mcfgr1);
+ val &= ~(LPI2C_MCFGR1_PINCFG_MASK | LPI2C_MCFGR1_IGNACK_MASK);
+ val |= LPI2C_MCFGR1_PINCFG(0x0); /* 2 pin open drain */
+ val |= LPI2C_MCFGR1_IGNACK(0x0); /* ignore nack */
+ writel(val, &regs->mcfgr1);
+
+ ret = bus_i2c_set_bus_speed(bus, speed);
+
+ /* enable lpi2c in master mode */
+ val = readl(&regs->mcr) & ~LPI2C_MCR_MEN_MASK;
+ writel(val | LPI2C_MCR_MEN(1), &regs->mcr);
+
+ debug("i2c : controller bus %d, speed %d:\n", bus->seq, speed);
+
+ return ret;
+}
+
+static int imx_lpi2c_probe_chip(struct udevice *bus, u32 chip,
+ u32 chip_flags)
+{
+ lpi2c_status_t result = LPI2C_SUCESS;
+
+ result = bus_i2c_start(bus, chip, 0);
+ if (result) {
+ bus_i2c_stop(bus);
+ bus_i2c_init(bus, 100000);
+ return result;
+ }
+
+ result = bus_i2c_stop(bus);
+ if (result) {
+ bus_i2c_init(bus, 100000);
+ return -result;
+ }
+
+ return result;
+}
+
+static int imx_lpi2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+ int ret = 0;
+
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ debug("i2c_xfer: chip=0x%x, len=0x%x\n", msg->addr, msg->len);
+ if (msg->flags & I2C_M_RD)
+ ret = bus_i2c_read(bus, msg->addr, msg->buf,
+ msg->len);
+ else {
+ ret = bus_i2c_write(bus, msg->addr, msg->buf,
+ msg->len);
+ if (ret)
+ break;
+ }
+ }
+
+ if (ret)
+ debug("i2c_write: error sending\n");
+
+ return ret;
+}
+
+static int imx_lpi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+ return bus_i2c_set_bus_speed(bus, speed);
+}
+
+static int imx_lpi2c_probe(struct udevice *bus)
+{
+ struct imx_lpi2c_bus *i2c_bus = dev_get_priv(bus);
+ fdt_addr_t addr;
+ int ret;
+
+ i2c_bus->driver_data = dev_get_driver_data(bus);
+
+ addr = dev_get_addr(bus);
+ if (addr == FDT_ADDR_T_NONE)
+ return -ENODEV;
+
+ i2c_bus->base = addr;
+ i2c_bus->index = bus->seq;
+ i2c_bus->bus = bus;
+
+ /* power up i2c resource */
+ ret = init_i2c_power(bus->seq + 4);
+ if (ret) {
+ debug("init_i2c_power err = %d\n", ret);
+ return ret;
+ }
+
+ /* Enable clk, only i2c4-7 can be handled by A7 core */
+ ret = enable_i2c_clk(1, bus->seq + 4);
+ if (ret < 0)
+ return ret;
+
+ ret = bus_i2c_init(bus, 100000);
+ if (ret < 0)
+ return ret;
+
+ debug("i2c : controller bus %d at %lu , speed %d: ",
+ bus->seq, i2c_bus->base,
+ i2c_bus->speed);
+
+ return 0;
+}
+
+static const struct dm_i2c_ops imx_lpi2c_ops = {
+ .xfer = imx_lpi2c_xfer,
+ .probe_chip = imx_lpi2c_probe_chip,
+ .set_bus_speed = imx_lpi2c_set_bus_speed,
+};
+
+static const struct udevice_id imx_lpi2c_ids[] = {
+ { .compatible = "fsl,imx7ulp-lpi2c", },
+ {}
+};
+
+U_BOOT_DRIVER(imx_lpi2c) = {
+ .name = "imx_lpi2c",
+ .id = UCLASS_I2C,
+ .of_match = imx_lpi2c_ids,
+ .probe = imx_lpi2c_probe,
+ .priv_auto_alloc_size = sizeof(struct imx_lpi2c_bus),
+ .ops = &imx_lpi2c_ops,
+};
diff --git a/drivers/misc/mxc_ocotp.c b/drivers/misc/mxc_ocotp.c
index 0b1c050..88610d6 100644
--- a/drivers/misc/mxc_ocotp.c
+++ b/drivers/misc/mxc_ocotp.c
@@ -29,6 +29,12 @@
#ifdef CONFIG_MX7
#define BM_CTRL_ADDR 0x0000000f
#define BM_CTRL_RELOAD 0x00000400
+#elif defined(CONFIG_MX7ULP)
+#define BM_CTRL_ADDR 0x000000FF
+#define BM_CTRL_RELOAD 0x00000400
+#define BM_OUT_STATUS_DED 0x00000400
+#define BM_OUT_STATUS_LOCKED 0x00000800
+#define BM_OUT_STATUS_PROGFAIL 0x00001000
#else
#define BM_CTRL_ADDR 0x0000007f
#endif
@@ -70,6 +76,9 @@
#elif defined CONFIG_MX7
#define FUSE_BANK_SIZE 0x40
#define FUSE_BANKS 16
+#elif defined(CONFIG_MX7ULP)
+#define FUSE_BANK_SIZE 0x80
+#define FUSE_BANKS 31
#else
#error "Unsupported architecture\n"
#endif
@@ -98,7 +107,7 @@ u32 fuse_bank_physical(int index)
{
u32 phy_index;
- if (is_mx6sl()) {
+ if (is_mx6sl() || is_mx7ulp()) {
phy_index = index;
} else if (is_mx6ul() || is_mx6ull() || is_mx6sll()) {
if ((is_mx6ull() || is_mx6sll()) && index == 8)
@@ -187,6 +196,10 @@ static int finish_access(struct ocotp_regs *regs, const char *caller)
err = !!(readl(&regs->ctrl) & BM_CTRL_ERROR);
clear_error(regs);
+#ifdef CONFIG_MX7ULP
+ /* Need to power down the OTP memory */
+ writel(1, &regs->pdn);
+#endif
if (err) {
printf("mxc_ocotp %s(): Access protect error\n", caller);
return -EIO;
@@ -217,6 +230,13 @@ int fuse_read(u32 bank, u32 word, u32 *val)
*val = readl(&regs->bank[phy_bank].fuse_regs[phy_word << 2]);
+#ifdef CONFIG_MX7ULP
+ if (readl(&regs->out_status) & BM_OUT_STATUS_DED) {
+ writel(BM_OUT_STATUS_DED, &regs->out_status_clr);
+ printf("mxc_ocotp %s(): fuse read wrong\n", __func__);
+ return -EIO;
+ }
+#endif
return finish_access(regs, __func__);
}
@@ -238,6 +258,12 @@ static void set_timing(struct ocotp_regs *regs)
clrsetbits_le32(&regs->timing, BM_TIMING_FSOURCE | BM_TIMING_PROG,
timing);
}
+#elif defined(CONFIG_MX7ULP)
+static void set_timing(struct ocotp_regs *regs)
+{
+ /* No timing set for MX7ULP */
+}
+
#else
static void set_timing(struct ocotp_regs *regs)
{
@@ -302,6 +328,14 @@ int fuse_sense(u32 bank, u32 word, u32 *val)
*val = readl(&regs->read_fuse_data);
#endif
+#ifdef CONFIG_MX7ULP
+ if (readl(&regs->out_status) & BM_OUT_STATUS_DED) {
+ writel(BM_OUT_STATUS_DED, &regs->out_status_clr);
+ printf("mxc_ocotp %s(): fuse read wrong\n", __func__);
+ return -EIO;
+ }
+#endif
+
return finish_access(regs, __func__);
}
@@ -355,6 +389,14 @@ int fuse_prog(u32 bank, u32 word, u32 val)
#endif
udelay(WRITE_POSTAMBLE_US);
+#ifdef CONFIG_MX7ULP
+ if (readl(&regs->out_status) & (BM_OUT_STATUS_PROGFAIL | BM_OUT_STATUS_LOCKED)) {
+ writel((BM_OUT_STATUS_PROGFAIL | BM_OUT_STATUS_LOCKED), &regs->out_status_clr);
+ printf("mxc_ocotp %s(): fuse write is failed\n", __func__);
+ return -EIO;
+ }
+#endif
+
return finish_access(regs, __func__);
}
@@ -374,5 +416,13 @@ int fuse_override(u32 bank, u32 word, u32 val)
writel(val, &regs->bank[phy_bank].fuse_regs[phy_word << 2]);
+#ifdef CONFIG_MX7ULP
+ if (readl(&regs->out_status) & (BM_OUT_STATUS_PROGFAIL | BM_OUT_STATUS_LOCKED)) {
+ writel((BM_OUT_STATUS_PROGFAIL | BM_OUT_STATUS_LOCKED), &regs->out_status_clr);
+ printf("mxc_ocotp %s(): fuse write is failed\n", __func__);
+ return -EIO;
+ }
+#endif
+
return finish_access(regs, __func__);
}
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index adeb5df..f3c6358 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -949,6 +949,10 @@ void fdt_fixup_esdhc(void *blob, bd_t *bd)
#ifdef CONFIG_DM_MMC
#include <asm/arch/clock.h>
+__weak void init_clk_usdhc(u32 index)
+{
+}
+
static int fsl_esdhc_probe(struct udevice *dev)
{
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
@@ -1011,6 +1015,9 @@ static int fsl_esdhc_probe(struct udevice *dev)
* correctly get the seq as 2 and 3, then let mxc_get_clock
* work as expected.
*/
+
+ init_clk_usdhc(dev->seq);
+
priv->sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK + dev->seq);
if (priv->sdhc_clk <= 0) {
dev_err(dev, "Unable to get clk for %s\n", dev->name);
@@ -1035,6 +1042,7 @@ static const struct udevice_id fsl_esdhc_ids[] = {
{ .compatible = "fsl,imx6sl-usdhc", },
{ .compatible = "fsl,imx6q-usdhc", },
{ .compatible = "fsl,imx7d-usdhc", },
+ { .compatible = "fsl,imx7ulp-usdhc", },
{ .compatible = "fsl,esdhc", },
{ /* sentinel */ }
};
diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig
index 238f77d..b668359 100644
--- a/drivers/pinctrl/nxp/Kconfig
+++ b/drivers/pinctrl/nxp/Kconfig
@@ -42,3 +42,17 @@ config PINCTRL_IMX7
configuration. This driver is different from the linux one,
this is a simple implementation, only parses the 'fsl,pins'
property and configure related registers.
+
+config PINCTRL_IMX7ULP
+ bool "IMX7ULP pinctrl driver"
+ depends on ARCH_MX7ULP && PINCTRL_FULL
+ select DEVRES
+ select PINCTRL_IMX
+ help
+ Say Y here to enable the imx7ulp pinctrl driver
+
+ This provides a simple pinctrl driver for i.MX7ULP SoC familiy.
+ This feature depends on device tree configuration. This driver
+ is different from the linux one, this is a simple implementation,
+ only parses the 'fsl,pins' property and configure related
+ registers.
diff --git a/drivers/pinctrl/nxp/Makefile b/drivers/pinctrl/nxp/Makefile
index e0f7325..c763948 100644
--- a/drivers/pinctrl/nxp/Makefile
+++ b/drivers/pinctrl/nxp/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
obj-$(CONFIG_PINCTRL_IMX5) += pinctrl-imx5.o
obj-$(CONFIG_PINCTRL_IMX6) += pinctrl-imx6.o
obj-$(CONFIG_PINCTRL_IMX7) += pinctrl-imx7.o
+obj-$(CONFIG_PINCTRL_IMX7ULP) += pinctrl-imx7ulp.o
diff --git a/drivers/pinctrl/nxp/pinctrl-imx.c b/drivers/pinctrl/nxp/pinctrl-imx.c
index e130faf..f0321c4 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx.c
@@ -24,6 +24,7 @@ static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config)
u32 *pin_data;
int npins, size, pin_size;
int mux_reg, conf_reg, input_reg, input_val, mux_mode, config_val;
+ u32 mux_shift = info->mux_mask ? ffs(info->mux_mask) - 1 : 0;
int i, j = 0;
dev_dbg(dev, "%s: %s\n", __func__, config->name);
@@ -97,8 +98,8 @@ static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config)
/* Set Mux */
if (info->flags & SHARE_MUX_CONF_REG) {
- clrsetbits_le32(info->base + mux_reg, 0x7 << 20,
- mux_mode << 20);
+ clrsetbits_le32(info->base + mux_reg, info->mux_mask,
+ mux_mode << mux_shift);
} else {
writel(mux_mode, info->base + mux_reg);
}
@@ -154,8 +155,8 @@ static int imx_pinctrl_set_state(struct udevice *dev, struct udevice *config)
/* Set config */
if (!(config_val & IMX_NO_PAD_CTL)) {
if (info->flags & SHARE_MUX_CONF_REG) {
- clrsetbits_le32(info->base + conf_reg, 0xffff,
- config_val);
+ clrsetbits_le32(info->base + conf_reg,
+ info->mux_mask, config_val);
} else {
writel(config_val, info->base + conf_reg);
}
@@ -200,6 +201,7 @@ int imx_pinctrl_probe(struct udevice *dev,
return -ENOMEM;
priv->info = info;
+ info->mux_mask = fdtdec_get_int(gd->fdt_blob, node, "fsl,mux_mask", 0);
/*
* Refer to linux documentation for details:
* Documentation/devicetree/bindings/pinctrl/fsl,imx7d-pinctrl.txt
diff --git a/drivers/pinctrl/nxp/pinctrl-imx.h b/drivers/pinctrl/nxp/pinctrl-imx.h
index 037c491..a26ba85 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx.h
+++ b/drivers/pinctrl/nxp/pinctrl-imx.h
@@ -11,11 +11,13 @@
* @base: the address to the controller in virtual memory
* @input_sel_base: the address of the select input in virtual memory.
* @flags: flags specific for each soc
+ * @mux_mask: Used when SHARE_MUX_CONF_REG flag is added
*/
struct imx_pinctrl_soc_info {
void __iomem *base;
void __iomem *input_sel_base;
unsigned int flags;
+ unsigned int mux_mask;
};
/**
@@ -41,6 +43,7 @@ extern const struct pinctrl_ops imx_pinctrl_ops;
#define SHARE_MUX_CONF_REG 0x1
#define ZERO_OFFSET_VALID 0x2
+#define CONFIG_IBE_OBE 0x4
#define IOMUXC_CONFIG_SION (0x1 << 4)
diff --git a/drivers/pinctrl/nxp/pinctrl-imx7ulp.c b/drivers/pinctrl/nxp/pinctrl-imx7ulp.c
new file mode 100644
index 0000000..5f01175
--- /dev/null
+++ b/drivers/pinctrl/nxp/pinctrl-imx7ulp.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * Peng Fan <peng.fan@nxp.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <dm/device.h>
+#include <dm/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+static struct imx_pinctrl_soc_info imx7ulp_pinctrl_soc_info = {
+ .flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG | CONFIG_IBE_OBE,
+};
+
+static int imx7ulp_pinctrl_probe(struct udevice *dev)
+{
+ struct imx_pinctrl_soc_info *info =
+ (struct imx_pinctrl_soc_info *)dev_get_driver_data(dev);
+
+ return imx_pinctrl_probe(dev, info);
+}
+
+static const struct udevice_id imx7ulp_pinctrl_match[] = {
+ { .compatible = "fsl,imx7ulp-iomuxc-0", .data = (ulong)&imx7ulp_pinctrl_soc_info },
+ { .compatible = "fsl,imx7ulp-iomuxc-1", .data = (ulong)&imx7ulp_pinctrl_soc_info },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(imx7ulp_pinctrl) = {
+ .name = "imx7ulp-pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = of_match_ptr(imx7ulp_pinctrl_match),
+ .probe = imx7ulp_pinctrl_probe,
+ .remove = imx_pinctrl_remove,
+ .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
+ .ops = &imx_pinctrl_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index beb4243..95e002e 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <dm.h>
+#include <fsl_lpuart.h>
#include <watchdog.h>
#include <asm/io.h>
#include <serial.h>
@@ -48,14 +49,63 @@
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 {
- struct lpuart_fsl *reg;
+ void *reg;
+ enum lpuart_devtype devtype;
+ ulong flags;
};
-#ifndef CONFIG_LPUART_32B_REG
-static void _lpuart_serial_setbrg(struct lpuart_fsl *base, int baudrate)
+static void lpuart_read32(u32 flags, u32 *addr, u32 *val)
+{
+ if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
+ if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
+ *(u32 *)val = in_be32(addr);
+ else
+ *(u32 *)val = in_le32(addr);
+ }
+}
+
+static void lpuart_write32(u32 flags, u32 *addr, u32 val)
+{
+ if (flags & LPUART_FLAG_REGMAP_32BIT_REG) {
+ if (flags & LPUART_FLAG_REGMAP_ENDIAN_BIG)
+ out_be32(addr, val);
+ else
+ out_le32(addr, val);
+ }
+}
+
+
+#ifndef CONFIG_SYS_CLK_FREQ
+#define CONFIG_SYS_CLK_FREQ 0
+#endif
+
+u32 __weak get_lpuart_clk(void)
{
- u32 clk = mxc_get_clock(MXC_UART_CLK);
+ return CONFIG_SYS_CLK_FREQ;
+}
+
+static bool is_lpuart32(struct udevice *dev)
+{
+ struct lpuart_serial_platdata *plat = dev->platdata;
+
+ return plat->flags & LPUART_FLAG_REGMAP_32BIT_REG;
+}
+
+static void _lpuart_serial_setbrg(struct lpuart_serial_platdata *plat,
+ int baudrate)
+{
+ struct lpuart_fsl *base = plat->reg;
+ u32 clk = get_lpuart_clk();
u16 sbr;
sbr = (u16)(clk / (16 * baudrate));
@@ -65,8 +115,9 @@ static void _lpuart_serial_setbrg(struct lpuart_fsl *base, int baudrate)
__raw_writeb(sbr & 0xff, &base->ubdl);
}
-static int _lpuart_serial_getc(struct lpuart_fsl *base)
+static int _lpuart_serial_getc(struct lpuart_serial_platdata *plat)
{
+ struct lpuart_fsl *base = plat->reg;
while (!(__raw_readb(&base->us1) & (US1_RDRF | US1_OR)))
WATCHDOG_RESET();
@@ -75,8 +126,11 @@ static int _lpuart_serial_getc(struct lpuart_fsl *base)
return __raw_readb(&base->ud);
}
-static void _lpuart_serial_putc(struct lpuart_fsl *base, const char c)
+static void _lpuart_serial_putc(struct lpuart_serial_platdata *plat,
+ const char c)
{
+ struct lpuart_fsl *base = plat->reg;
+
while (!(__raw_readb(&base->us1) & US1_TDRE))
WATCHDOG_RESET();
@@ -84,8 +138,10 @@ static void _lpuart_serial_putc(struct lpuart_fsl *base, const char c)
}
/* Test whether a character is in the RX buffer */
-static int _lpuart_serial_tstc(struct lpuart_fsl *base)
+static int _lpuart_serial_tstc(struct lpuart_serial_platdata *plat)
{
+ struct lpuart_fsl *base = plat->reg;
+
if (__raw_readb(&base->urcfifo) == 0)
return 0;
@@ -96,8 +152,9 @@ static int _lpuart_serial_tstc(struct lpuart_fsl *base)
* Initialise the serial port with the given baudrate. The settings
* are always 8 data bits, no parity, 1 stop bit, no start bits.
*/
-static int _lpuart_serial_init(struct lpuart_fsl *base)
+static int _lpuart_serial_init(struct lpuart_serial_platdata *plat)
{
+ struct lpuart_fsl *base = (struct lpuart_fsl *)plat->reg;
u8 ctrl;
ctrl = __raw_readb(&base->uc2);
@@ -115,101 +172,140 @@ static int _lpuart_serial_init(struct lpuart_fsl *base)
__raw_writeb(CFIFO_TXFLUSH | CFIFO_RXFLUSH, &base->ucfifo);
/* provide data bits, parity, stop bit, etc */
- _lpuart_serial_setbrg(base, gd->baudrate);
+ _lpuart_serial_setbrg(plat, gd->baudrate);
__raw_writeb(UC2_RE | UC2_TE, &base->uc2);
return 0;
}
-static int lpuart_serial_setbrg(struct udevice *dev, int baudrate)
+static void _lpuart32_serial_setbrg_7ulp(struct lpuart_serial_platdata *plat,
+ int baudrate)
{
- struct lpuart_serial_platdata *plat = dev->platdata;
- struct lpuart_fsl *reg = plat->reg;
+ struct lpuart_fsl_reg32 *base = plat->reg;
+ u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
+ u32 clk = get_lpuart_clk();
- _lpuart_serial_setbrg(reg, baudrate);
+ baud_diff = baudrate;
+ osr = 0;
+ sbr = 0;
- return 0;
-}
+ for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) {
+ tmp_sbr = (clk / (baudrate * tmp_osr));
-static int lpuart_serial_getc(struct udevice *dev)
-{
- struct lpuart_serial_platdata *plat = dev->platdata;
- struct lpuart_fsl *reg = plat->reg;
+ if (tmp_sbr == 0)
+ tmp_sbr = 1;
- return _lpuart_serial_getc(reg);
-}
+ /*calculate difference in actual buad w/ current values */
+ tmp_diff = (clk / (tmp_osr * tmp_sbr));
+ tmp_diff = tmp_diff - baudrate;
-static int lpuart_serial_putc(struct udevice *dev, const char c)
-{
- struct lpuart_serial_platdata *plat = dev->platdata;
- struct lpuart_fsl *reg = plat->reg;
+ /* 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++;
+ }
- _lpuart_serial_putc(reg, c);
+ if (tmp_diff <= baud_diff) {
+ baud_diff = tmp_diff;
+ osr = tmp_osr;
+ sbr = tmp_sbr;
+ }
+ }
- return 0;
-}
+ /*
+ * 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);
-static int lpuart_serial_pending(struct udevice *dev, bool input)
-{
- struct lpuart_serial_platdata *plat = dev->platdata;
- struct lpuart_fsl *reg = plat->reg;
+ if ((osr > 3) && (osr < 8))
+ tmp |= LPUART_BAUD_BOTHEDGE_MASK;
- if (input)
- return _lpuart_serial_tstc(reg);
- else
- return __raw_readb(&reg->us1) & US1_TDRE ? 0 : 1;
-}
+ tmp &= ~LPUART_BAUD_OSR_MASK;
+ tmp |= LPUART_BAUD_OSR(osr-1);
-static int lpuart_serial_probe(struct udevice *dev)
-{
- struct lpuart_serial_platdata *plat = dev->platdata;
- struct lpuart_fsl *reg = plat->reg;
+ tmp &= ~LPUART_BAUD_SBR_MASK;
+ tmp |= LPUART_BAUD_SBR(sbr);
- return _lpuart_serial_init(reg);
-}
-#else
+ /* explicitly disable 10 bit mode & set 1 stop bit */
+ tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK);
-u32 __weak get_lpuart_clk(void)
-{
- return CONFIG_SYS_CLK_FREQ;
+ out_le32(&base->baud, tmp);
}
-static void _lpuart32_serial_setbrg(struct lpuart_fsl *base, int baudrate)
+static void _lpuart32_serial_setbrg(struct lpuart_serial_platdata *plat,
+ int baudrate)
{
+ struct lpuart_fsl_reg32 *base = plat->reg;
u32 clk = get_lpuart_clk();
u32 sbr;
sbr = (clk / (16 * baudrate));
/* place adjustment later - n/32 BRFA */
- out_be32(&base->baud, sbr);
+ lpuart_write32(plat->flags, &base->baud, sbr);
}
-static int _lpuart32_serial_getc(struct lpuart_fsl *base)
+static int _lpuart32_serial_getc(struct lpuart_serial_platdata *plat)
{
- u32 stat;
+ struct lpuart_fsl_reg32 *base = plat->reg;
+ u32 stat, val;
- while (((stat = in_be32(&base->stat)) & STAT_RDRF) == 0) {
- out_be32(&base->stat, STAT_FLAGS);
+ lpuart_read32(plat->flags, &base->stat, &stat);
+ while ((stat & STAT_RDRF) == 0) {
+ lpuart_write32(plat->flags, &base->stat, STAT_FLAGS);
WATCHDOG_RESET();
+ lpuart_read32(plat->flags, &base->stat, &stat);
+ }
+
+ lpuart_read32(plat->flags, &base->data, &val);
+
+ 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 in_be32(&base->data) & 0x3ff;
+ return val & 0x3ff;
}
-static void _lpuart32_serial_putc(struct lpuart_fsl *base, const char c)
+static void _lpuart32_serial_putc(struct lpuart_serial_platdata *plat,
+ const char c)
{
- while (!(in_be32(&base->stat) & STAT_TDRE))
+ 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);
+
+ if ((stat & STAT_TDRE))
+ break;
+
WATCHDOG_RESET();
+ }
- out_be32(&base->data, c);
+ lpuart_write32(plat->flags, &base->data, c);
}
/* Test whether a character is in the RX buffer */
-static int _lpuart32_serial_tstc(struct lpuart_fsl *base)
+static int _lpuart32_serial_tstc(struct lpuart_serial_platdata *plat)
{
- if ((in_be32(&base->water) >> 24) == 0)
+ struct lpuart_fsl_reg32 *base = plat->reg;
+ u32 water;
+
+ lpuart_read32(plat->flags, &base->water, &water);
+
+ if ((water >> 24) == 0)
return 0;
return 1;
@@ -219,91 +315,127 @@ static int _lpuart32_serial_tstc(struct lpuart_fsl *base)
* Initialise the serial port with the given baudrate. The settings
* are always 8 data bits, no parity, 1 stop bit, no start bits.
*/
-static int _lpuart32_serial_init(struct lpuart_fsl *base)
+static int _lpuart32_serial_init(struct lpuart_serial_platdata *plat)
{
- u8 ctrl;
+ struct lpuart_fsl_reg32 *base = (struct lpuart_fsl_reg32 *)plat->reg;
+ u32 ctrl;
- ctrl = in_be32(&base->ctrl);
+ lpuart_read32(plat->flags, &base->ctrl, &ctrl);
ctrl &= ~CTRL_RE;
ctrl &= ~CTRL_TE;
- out_be32(&base->ctrl, ctrl);
+ lpuart_write32(plat->flags, &base->ctrl, ctrl);
- out_be32(&base->modir, 0);
- out_be32(&base->fifo, ~(FIFO_TXFE | FIFO_RXFE));
+ lpuart_write32(plat->flags, &base->modir, 0);
+ lpuart_write32(plat->flags, &base->fifo, ~(FIFO_TXFE | FIFO_RXFE));
- out_be32(&base->match, 0);
+ lpuart_write32(plat->flags, &base->match, 0);
- /* provide data bits, parity, stop bit, etc */
- _lpuart32_serial_setbrg(base, 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);
+ }
- out_be32(&base->ctrl, CTRL_RE | CTRL_TE);
+ lpuart_write32(plat->flags, &base->ctrl, CTRL_RE | CTRL_TE);
return 0;
}
-static int lpuart32_serial_setbrg(struct udevice *dev, int baudrate)
+static int lpuart_serial_setbrg(struct udevice *dev, int baudrate)
{
struct lpuart_serial_platdata *plat = dev->platdata;
- struct lpuart_fsl *reg = plat->reg;
- _lpuart32_serial_setbrg(reg, baudrate);
+ 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;
}
-static int lpuart32_serial_getc(struct udevice *dev)
+static int lpuart_serial_getc(struct udevice *dev)
{
struct lpuart_serial_platdata *plat = dev->platdata;
- struct lpuart_fsl *reg = plat->reg;
- return _lpuart32_serial_getc(reg);
+ if (is_lpuart32(dev))
+ return _lpuart32_serial_getc(plat);
+
+ return _lpuart_serial_getc(plat);
}
-static int lpuart32_serial_putc(struct udevice *dev, const char c)
+static int lpuart_serial_putc(struct udevice *dev, const char c)
{
struct lpuart_serial_platdata *plat = dev->platdata;
- struct lpuart_fsl *reg = plat->reg;
- _lpuart32_serial_putc(reg, c);
+ if (is_lpuart32(dev))
+ _lpuart32_serial_putc(plat, c);
+ else
+ _lpuart_serial_putc(plat, c);
return 0;
}
-static int lpuart32_serial_pending(struct udevice *dev, bool input)
+static int lpuart_serial_pending(struct udevice *dev, bool input)
{
struct lpuart_serial_platdata *plat = dev->platdata;
struct lpuart_fsl *reg = plat->reg;
+ struct lpuart_fsl_reg32 *reg32 = plat->reg;
+ u32 stat;
+
+ if (is_lpuart32(dev)) {
+ if (input) {
+ return _lpuart32_serial_tstc(plat);
+ } else {
+ lpuart_read32(plat->flags, &reg32->stat, &stat);
+ return stat & STAT_TDRE ? 0 : 1;
+ }
+ }
if (input)
- return _lpuart32_serial_tstc(reg);
+ return _lpuart_serial_tstc(plat);
else
- return in_be32(&reg->stat) & STAT_TDRE ? 0 : 1;
+ return __raw_readb(&reg->us1) & US1_TDRE ? 0 : 1;
}
-static int lpuart32_serial_probe(struct udevice *dev)
+static int lpuart_serial_probe(struct udevice *dev)
{
struct lpuart_serial_platdata *plat = dev->platdata;
- struct lpuart_fsl *reg = plat->reg;
- return _lpuart32_serial_init(reg);
+ if (is_lpuart32(dev))
+ return _lpuart32_serial_init(plat);
+ else
+ return _lpuart_serial_init(plat);
}
-#endif /* CONFIG_LPUART_32B_REG */
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);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- plat->reg = (struct lpuart_fsl *)addr;
+ 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;
}
-#ifndef CONFIG_LPUART_32B_REG
static const struct dm_serial_ops lpuart_serial_ops = {
.putc = lpuart_serial_putc,
.pending = lpuart_serial_pending,
@@ -312,7 +444,11 @@ static const struct dm_serial_ops lpuart_serial_ops = {
};
static const struct udevice_id lpuart_serial_ids[] = {
- { .compatible = "fsl,vf610-lpuart" },
+ { .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"},
{ }
};
@@ -326,27 +462,3 @@ U_BOOT_DRIVER(serial_lpuart) = {
.ops = &lpuart_serial_ops,
.flags = DM_FLAG_PRE_RELOC,
};
-#else /* CONFIG_LPUART_32B_REG */
-static const struct dm_serial_ops lpuart32_serial_ops = {
- .putc = lpuart32_serial_putc,
- .pending = lpuart32_serial_pending,
- .getc = lpuart32_serial_getc,
- .setbrg = lpuart32_serial_setbrg,
-};
-
-static const struct udevice_id lpuart32_serial_ids[] = {
- { .compatible = "fsl,ls1021a-lpuart" },
- { }
-};
-
-U_BOOT_DRIVER(serial_lpuart32) = {
- .name = "serial_lpuart32",
- .id = UCLASS_SERIAL,
- .of_match = lpuart32_serial_ids,
- .ofdata_to_platdata = lpuart_serial_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata),
- .probe = lpuart32_serial_probe,
- .ops = &lpuart32_serial_ops,
- .flags = DM_FLAG_PRE_RELOC,
-};
-#endif /* CONFIG_LPUART_32B_REG */
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c
index 1cfcbf2..64126e2 100644
--- a/drivers/serial/serial_mxc.c
+++ b/drivers/serial/serial_mxc.c
@@ -365,6 +365,7 @@ static int mxc_serial_ofdata_to_platdata(struct udevice *dev)
}
static const struct udevice_id mxc_serial_ids[] = {
+ { .compatible = "fsl,imx6ul-uart" },
{ .compatible = "fsl,imx7d-uart" },
{ }
};
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index e69de29..dbdaafc 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -0,0 +1,8 @@
+menu "WATCHDOG support"
+
+config ULP_WATCHDOG
+ bool "i.MX7ULP watchdog"
+ help
+ Say Y here to enable i.MX7ULP watchdog driver.
+
+endmenu
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index a007ae8..dea1836 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o
obj-$(CONFIG_BFIN_WATCHDOG) += bfin_wdt.o
obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o
+obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o
diff --git a/drivers/watchdog/ulp_wdog.c b/drivers/watchdog/ulp_wdog.c
new file mode 100644
index 0000000..72ec694
--- /dev/null
+++ b/drivers/watchdog/ulp_wdog.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+
+/*
+ * MX7ULP WDOG Register Map
+ */
+struct wdog_regs {
+ u8 cs1;
+ u8 cs2;
+ u16 reserve0;
+ u32 cnt;
+ u32 toval;
+ u32 win;
+};
+
+#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
+#define CONFIG_WATCHDOG_TIMEOUT_MSECS 0x1500
+#endif
+
+#define REFRESH_WORD0 0xA602 /* 1st refresh word */
+#define REFRESH_WORD1 0xB480 /* 2nd refresh word */
+
+#define UNLOCK_WORD0 0xC520 /* 1st unlock word */
+#define UNLOCK_WORD1 0xD928 /* 2nd unlock word */
+
+#define WDGCS1_WDGE (1<<7)
+#define WDGCS1_WDGUPDATE (1<<5)
+
+#define WDGCS2_FLG (1<<6)
+
+#define WDG_BUS_CLK (0x0)
+#define WDG_LPO_CLK (0x1)
+#define WDG_32KHZ_CLK (0x2)
+#define WDG_EXT_CLK (0x3)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void hw_watchdog_set_timeout(u16 val)
+{
+ /* setting timeout value */
+ struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
+
+ writel(val, &wdog->toval);
+}
+
+void hw_watchdog_reset(void)
+{
+ struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
+
+ writel(REFRESH_WORD0, &wdog->cnt);
+ writel(REFRESH_WORD1, &wdog->cnt);
+}
+
+void hw_watchdog_init(void)
+{
+ u8 val;
+ struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
+
+ writel(UNLOCK_WORD0, &wdog->cnt);
+ writel(UNLOCK_WORD1, &wdog->cnt);
+
+ val = readb(&wdog->cs2);
+ val |= WDGCS2_FLG;
+ writeb(val, &wdog->cs2);
+
+ hw_watchdog_set_timeout(CONFIG_WATCHDOG_TIMEOUT_MSECS);
+ writel(0, &wdog->win);
+
+ writeb(WDG_LPO_CLK, &wdog->cs2);/* setting 1-kHz clock source */
+ writeb((WDGCS1_WDGE | WDGCS1_WDGUPDATE), &wdog->cs1);/* enable counter running */
+
+ hw_watchdog_reset();
+}
+
+void reset_cpu(ulong addr)
+{
+ struct wdog_regs *wdog = (struct wdog_regs *)WDOG_BASE_ADDR;
+
+ writel(UNLOCK_WORD0, &wdog->cnt);
+ writel(UNLOCK_WORD1, &wdog->cnt);
+
+ hw_watchdog_set_timeout(5); /* 5ms timeout */
+ writel(0, &wdog->win);
+
+ writeb(WDG_LPO_CLK, &wdog->cs2);/* setting 1-kHz clock source */
+ writeb(WDGCS1_WDGE, &wdog->cs1);/* enable counter running */
+
+ hw_watchdog_reset();
+
+ while (1);
+}