aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-07-17 08:04:28 -0400
committerTom Rini <trini@konsulko.com>2020-07-17 08:04:28 -0400
commit42e7659db0ac7089d3a2f80ee1c3b8eb64d84706 (patch)
treec2b2dda157f71ce80ca4fb00332519f161896a5c /drivers
parentfee68b98fe3890631a9bdf8f8db328179011ee3f (diff)
parentab8b4e818cbc3846672c13b12f1d75daccfac519 (diff)
downloadu-boot-42e7659db0ac7089d3a2f80ee1c3b8eb64d84706.zip
u-boot-42e7659db0ac7089d3a2f80ee1c3b8eb64d84706.tar.gz
u-boot-42e7659db0ac7089d3a2f80ee1c3b8eb64d84706.tar.bz2
Merge tag 'u-boot-imx-20200716' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
i.MX for 2020.10 ---------------- - i.MX DDR driver fix/update for i.MX8M - i.MX pinctrl driver fix. - Use arm_smccc_smc to remove imx sip function - i.MX8M clk update - support booting aarch32 kernel on aarch64 hardware - fused part support for i.MX8MP - imx6: pcm058 to DM Travis: https://travis-ci.org/github/sbabic/u-boot-imx/builds/708734785
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/imx/clk-imx8mm.c63
-rw-r--r--drivers/clk/imx/clk-imx8mn.c108
-rw-r--r--drivers/clk/imx/clk-imx8mp.c52
-rw-r--r--drivers/ddr/imx/imx8m/Kconfig7
-rw-r--r--drivers/ddr/imx/imx8m/ddr_init.c79
-rw-r--r--drivers/ddr/imx/imx8m/ddrphy_train.c7
-rw-r--r--drivers/ddr/imx/imx8m/ddrphy_utils.c164
-rw-r--r--drivers/gpio/mxc_gpio.c36
-rw-r--r--drivers/misc/imx8/fuse.c19
-rw-r--r--drivers/misc/imx8/scu_api.c25
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx5.c2
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx7.c2
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx8m.c2
-rw-r--r--drivers/power/domain/imx8m-power-domain.c10
-rw-r--r--drivers/power/pmic/pmic_pca9450.c21
-rw-r--r--drivers/spi/Kconfig8
-rw-r--r--drivers/spi/fsl_qspi.c122
-rw-r--r--drivers/watchdog/imx_watchdog.c18
18 files changed, 586 insertions, 159 deletions
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
index 66c9601..d32ff84 100644
--- a/drivers/clk/imx/clk-imx8mm.c
+++ b/drivers/clk/imx/clk-imx8mm.c
@@ -95,6 +95,9 @@ static const char *imx8mm_enet_phy_sels[] = {"clock-osc-24m", "sys_pll2_50m", "s
static const char *imx8mm_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_200m",
"sys_pll1_133m", "sys_pll3_out", "sys_pll2_250m", "audio_pll1_out", };
+static const char *imx8mm_usb_bus_sels[] = {"clock-osc-24m", "sys_pll2_500m", "sys_pll1_800m", "sys_pll2_100m",
+ "sys_pll2_200m", "clk_ext2", "clk_ext4", "audio_pll2_out", };
+
static const char *imx8mm_usdhc1_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
"sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", };
@@ -119,6 +122,15 @@ static const char *imx8mm_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_
static const char *imx8mm_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
"sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", };
+static const char *imx8mm_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m", "sys_pll2_500m",
+ "audio_pll2_out", "sys_pll1_266m", "sys_pll3_out", "sys_pll1_100m", };
+
+static const char *imx8mm_usb_core_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m",
+ "sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+
+static const char *imx8mm_usb_phy_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m", "sys_pll2_100m",
+ "sys_pll2_200m", "clk_ext2", "clk_ext3", "audio_pll2_out", };
+
static ulong imx8mm_clk_get_rate(struct clk *clk)
{
struct clk *c;
@@ -191,7 +203,10 @@ static int imx8mm_clk_set_parent(struct clk *clk, struct clk *parent)
if (ret)
return ret;
- return clk_set_parent(c, cp);
+ ret = clk_set_parent(c, cp);
+ c->dev->parent = cp->dev;
+
+ return ret;
}
static struct clk_ops imx8mm_clk_ops = {
@@ -349,6 +364,8 @@ static int imx8mm_clk_probe(struct udevice *dev)
imx8m_clk_composite_critical("nand_usdhc_bus",
imx8mm_nand_usdhc_sels,
base + 0x8900));
+ clk_dm(IMX8MM_CLK_USB_BUS,
+ imx8m_clk_composite("usb_bus", imx8mm_usb_bus_sels, base + 0x8b80));
/* IP */
clk_dm(IMX8MM_CLK_USDHC1,
@@ -370,6 +387,12 @@ static int imx8mm_clk_probe(struct udevice *dev)
clk_dm(IMX8MM_CLK_USDHC3,
imx8m_clk_composite("usdhc3", imx8mm_usdhc3_sels,
base + 0xbc80));
+ clk_dm(IMX8MM_CLK_QSPI,
+ imx8m_clk_composite("qspi", imx8mm_qspi_sels, base + 0xab80));
+ clk_dm(IMX8MM_CLK_USB_CORE_REF,
+ imx8m_clk_composite("usb_core_ref", imx8mm_usb_core_sels, base + 0xb100));
+ clk_dm(IMX8MM_CLK_USB_PHY_REF,
+ imx8m_clk_composite("usb_phy_ref", imx8mm_usb_phy_sels, base + 0xb180));
clk_dm(IMX8MM_CLK_I2C1_ROOT,
imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0));
@@ -393,6 +416,10 @@ static int imx8mm_clk_probe(struct udevice *dev)
imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0));
clk_dm(IMX8MM_CLK_USDHC3_ROOT,
imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
+ clk_dm(IMX8MM_CLK_QSPI_ROOT,
+ imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0));
+ clk_dm(IMX8MM_CLK_USB1_CTRL_ROOT,
+ imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0));
/* clks not needed in SPL stage */
#ifndef CONFIG_SPL_BUILD
@@ -410,40 +437,6 @@ static int imx8mm_clk_probe(struct udevice *dev)
base + 0x40a0, 0));
#endif
-#ifdef CONFIG_SPL_BUILD
- struct clk *clkp, *clkp1;
-
- clk_get_by_id(IMX8MM_CLK_WDOG1_ROOT, &clkp);
- clk_enable(clkp);
- clk_get_by_id(IMX8MM_CLK_WDOG2_ROOT, &clkp);
- clk_enable(clkp);
- clk_get_by_id(IMX8MM_CLK_WDOG3_ROOT, &clkp);
- clk_enable(clkp);
-
- /* Configure SYS_PLL3 to 750MHz */
- clk_get_by_id(IMX8MM_SYS_PLL3, &clkp);
- clk_set_rate(clkp, 750000000UL);
- clk_enable(clkp);
-
- /* Configure ARM to sys_pll2_500m */
- clk_get_by_id(IMX8MM_CLK_A53_SRC, &clkp);
- clk_get_by_id(IMX8MM_SYS_PLL2_OUT, &clkp1);
- clk_enable(clkp1);
- clk_get_by_id(IMX8MM_SYS_PLL2_500M, &clkp1);
- clk_set_parent(clkp, clkp1);
-
- /* Configure ARM PLL to 1.2GHz */
- clk_get_by_id(IMX8MM_ARM_PLL, &clkp1);
- clk_set_rate(clkp1, 1200000000UL);
- clk_get_by_id(IMX8MM_ARM_PLL_OUT, &clkp1);
- clk_enable(clkp1);
- clk_set_parent(clkp, clkp1);
-
- /* Configure DIV to 1.2GHz */
- clk_get_by_id(IMX8MM_CLK_A53_DIV, &clkp1);
- clk_set_rate(clkp1, 1200000000UL);
-#endif
-
return 0;
}
diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c
index 2d8e373..e29d902 100644
--- a/drivers/clk/imx/clk-imx8mn.c
+++ b/drivers/clk/imx/clk-imx8mn.c
@@ -81,9 +81,24 @@ static const char *imx8mn_ahb_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_p
static const char *imx8mn_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_250m",
"sys_pll2_200m", "audio_pll1_out", "video_pll1_out", "sys_pll3_out", };
+#ifndef CONFIG_SPL_BUILD
+static const char *imx8mn_enet_ref_sels[] = {"clock-osc-24m", "sys_pll2_125m", "sys_pll2_50m", "sys_pll2_100m",
+ "sys_pll1_160m", "audio_pll1_out", "video_pll1_out", "clk_ext4", };
+
+static const char *imx8mn_enet_timer_sels[] = {"clock-osc-24m", "sys_pll2_100m", "audio_pll1_out", "clk_ext1", "clk_ext2",
+ "clk_ext3", "clk_ext4", "video_pll1_out", };
+
+static const char *imx8mn_enet_phy_sels[] = {"clock-osc-24m", "sys_pll2_50m", "sys_pll2_125m", "sys_pll2_200m",
+ "sys_pll2_500m", "video_pll1_out", "audio_pll2_out", };
+#endif
+
static const char *imx8mn_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m", "sys_pll2_200m",
"sys_pll1_133m", "sys_pll3_out", "sys_pll2_250m", "audio_pll1_out", };
+static const char * const imx8mn_usb_bus_sels[] = {"clock-osc-24m", "sys_pll2_500m", "sys_pll1_800m",
+ "sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
+ "clk_ext4", "audio_pll2_out", };
+
static const char *imx8mn_usdhc1_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
"sys_pll3_out", "sys_pll1_266m", "audio_pll2_out", "sys_pll1_100m", };
@@ -108,6 +123,17 @@ static const char *imx8mn_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_
static const char *imx8mn_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m", "sys_pll2_500m",
"sys_pll3_out", "sys_pll1_266m", "audio_pll2_clk", "sys_pll1_100m", };
+static const char *imx8mn_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m", "sys_pll2_500m",
+ "audio_pll2_out", "sys_pll1_266m", "sys_pll3_out", "sys_pll1_100m", };
+
+static const char * const imx8mn_usb_core_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m",
+ "sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
+ "clk_ext3", "audio_pll2_out", };
+
+static const char * const imx8mn_usb_phy_sels[] = {"clock-osc-24m", "sys_pll1_100m", "sys_pll1_40m",
+ "sys_pll2_100m", "sys_pll2_200m", "clk_ext2",
+ "clk_ext3", "audio_pll2_out", };
+
static ulong imx8mn_clk_get_rate(struct clk *clk)
{
struct clk *c;
@@ -165,11 +191,33 @@ static int imx8mn_clk_enable(struct clk *clk)
return __imx8mn_clk_enable(clk, 1);
}
+static int imx8mn_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk *c, *cp;
+ int ret;
+
+ debug("%s(#%lu), parent: %lu\n", __func__, clk->id, parent->id);
+
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
+
+ ret = clk_get_by_id(parent->id, &cp);
+ if (ret)
+ return ret;
+
+ ret = clk_set_parent(c, cp);
+ c->dev->parent = cp->dev;
+
+ return ret;
+}
+
static struct clk_ops imx8mn_clk_ops = {
.set_rate = imx8mn_clk_set_rate,
.get_rate = imx8mn_clk_get_rate,
.enable = imx8mn_clk_enable,
.disable = imx8mn_clk_disable,
+ .set_parent = imx8mn_clk_set_parent,
};
static int imx8mn_clk_probe(struct udevice *dev)
@@ -319,6 +367,8 @@ static int imx8mn_clk_probe(struct udevice *dev)
imx8m_clk_composite_critical("nand_usdhc_bus",
imx8mn_nand_usdhc_sels,
base + 0x8900));
+ clk_dm(IMX8MN_CLK_USB_BUS,
+ imx8m_clk_composite("usb_bus", imx8mn_usb_bus_sels, base + 0x8b80));
/* IP */
clk_dm(IMX8MN_CLK_USDHC1,
@@ -340,6 +390,12 @@ static int imx8mn_clk_probe(struct udevice *dev)
clk_dm(IMX8MN_CLK_USDHC3,
imx8m_clk_composite("usdhc3", imx8mn_usdhc3_sels,
base + 0xbc80));
+ clk_dm(IMX8MN_CLK_QSPI,
+ imx8m_clk_composite("qspi", imx8mn_qspi_sels, base + 0xab80));
+ clk_dm(IMX8MN_CLK_USB_CORE_REF,
+ imx8m_clk_composite("usb_core_ref", imx8mn_usb_core_sels, base + 0xb100));
+ clk_dm(IMX8MN_CLK_USB_PHY_REF,
+ imx8m_clk_composite("usb_phy_ref", imx8mn_usb_phy_sels, base + 0xb180));
clk_dm(IMX8MN_CLK_I2C1_ROOT,
imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0));
@@ -363,39 +419,25 @@ static int imx8mn_clk_probe(struct udevice *dev)
imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0));
clk_dm(IMX8MN_CLK_USDHC3_ROOT,
imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0));
-
-#ifdef CONFIG_SPL_BUILD
- struct clk *clkp, *clkp1;
-
- clk_get_by_id(IMX8MN_CLK_WDOG1_ROOT, &clkp);
- clk_enable(clkp);
- clk_get_by_id(IMX8MN_CLK_WDOG2_ROOT, &clkp);
- clk_enable(clkp);
- clk_get_by_id(IMX8MN_CLK_WDOG3_ROOT, &clkp);
- clk_enable(clkp);
-
- /* Configure SYS_PLL3 to 600MHz */
- clk_get_by_id(IMX8MN_SYS_PLL3, &clkp);
- clk_set_rate(clkp, 600000000UL);
- clk_enable(clkp);
-
- /* Configure ARM to sys_pll2_500m */
- clk_get_by_id(IMX8MN_CLK_A53_SRC, &clkp);
- clk_get_by_id(IMX8MN_SYS_PLL2_OUT, &clkp1);
- clk_enable(clkp1);
- clk_get_by_id(IMX8MN_SYS_PLL2_500M, &clkp1);
- clk_set_parent(clkp, clkp1);
-
- /* Configure ARM PLL to 1.2GHz */
- clk_get_by_id(IMX8MN_ARM_PLL, &clkp1);
- clk_set_rate(clkp1, 1200000000UL);
- clk_get_by_id(IMX8MN_ARM_PLL_OUT, &clkp1);
- clk_enable(clkp1);
- clk_set_parent(clkp, clkp1);
-
- /* Configure DIV to 1.2GHz */
- clk_get_by_id(IMX8MN_CLK_A53_DIV, &clkp1);
- clk_set_rate(clkp1, 1200000000UL);
+ clk_dm(IMX8MN_CLK_QSPI_ROOT,
+ imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0));
+ clk_dm(IMX8MN_CLK_USB1_CTRL_ROOT,
+ imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0));
+
+ /* clks not needed in SPL stage */
+#ifndef CONFIG_SPL_BUILD
+ clk_dm(IMX8MN_CLK_ENET_REF,
+ imx8m_clk_composite("enet_ref", imx8mn_enet_ref_sels,
+ base + 0xa980));
+ clk_dm(IMX8MN_CLK_ENET_TIMER,
+ imx8m_clk_composite("enet_timer", imx8mn_enet_timer_sels,
+ base + 0xaa00));
+ clk_dm(IMX8MN_CLK_ENET_PHY_REF,
+ imx8m_clk_composite("enet_phy", imx8mn_enet_phy_sels,
+ base + 0xaa80));
+ clk_dm(IMX8MN_CLK_ENET1_ROOT,
+ imx_clk_gate4("enet1_root_clk", "enet_axi",
+ base + 0x40a0, 0));
#endif
return 0;
diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c
index 124138c..c77500b 100644
--- a/drivers/clk/imx/clk-imx8mp.c
+++ b/drivers/clk/imx/clk-imx8mp.c
@@ -80,6 +80,10 @@ static const char *imx8mp_main_axi_sels[] = {"clock-osc-24m", "sys_pll2_333m", "
"sys_pll2_250m", "sys_pll2_1000m", "audio_pll1_out",
"video_pll1_out", "sys_pll1_100m",};
+static const char *imx8mp_enet_axi_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m",
+ "sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out",
+ "video_pll1_out", "sys_pll3_out", };
+
static const char *imx8mp_nand_usdhc_sels[] = {"clock-osc-24m", "sys_pll1_266m", "sys_pll1_800m",
"sys_pll2_200m", "sys_pll1_133m", "sys_pll3_out",
"sys_pll2_250m", "audio_pll1_out", };
@@ -160,10 +164,26 @@ static const char *imx8mp_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_
"vpu_pll_out", "sys_pll2_125m", "sys_pll3_out",
"sys_pll1_80m", "sys_pll2_166m" };
+static const char *imx8mp_qspi_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll2_333m",
+ "sys_pll2_500m", "audio_pll2_out", "sys_pll1_266m",
+ "sys_pll3_out", "sys_pll1_100m", };
+
static const char *imx8mp_usdhc3_sels[] = {"clock-osc-24m", "sys_pll1_400m", "sys_pll1_800m",
"sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m",
"audio_pll2_out", "sys_pll1_100m", };
+static const char *imx8mp_enet_ref_sels[] = {"clock-osc-24m", "sys_pll2_125m", "sys_pll2_50m",
+ "sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out",
+ "video_pll1_out", "clk_ext4", };
+
+static const char *imx8mp_enet_timer_sels[] = {"clock-osc-24m", "sys_pll2_100m", "audio_pll1_out",
+ "clk_ext1", "clk_ext2", "clk_ext3",
+ "clk_ext4", "video_pll1_out", };
+
+static const char *imx8mp_enet_phy_ref_sels[] = {"clock-osc-24m", "sys_pll2_50m", "sys_pll2_125m",
+ "sys_pll2_200m", "sys_pll2_500m", "audio_pll1_out",
+ "video_pll1_out", "audio_pll2_out", };
+
static const char *imx8mp_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", };
@@ -224,11 +244,34 @@ static int imx8mp_clk_enable(struct clk *clk)
return __imx8mp_clk_enable(clk, 1);
}
+static int imx8mp_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk *c, *cp;
+ int ret;
+
+ debug("%s(#%lu), parent: %lu\n", __func__, clk->id, parent->id);
+
+ ret = clk_get_by_id(clk->id, &c);
+ if (ret)
+ return ret;
+
+ ret = clk_get_by_id(parent->id, &cp);
+ if (ret)
+ return ret;
+
+ ret = clk_set_parent(c, cp);
+
+ c->dev->parent = cp->dev;
+
+ return ret;
+}
+
static struct clk_ops imx8mp_clk_ops = {
.set_rate = imx8mp_clk_set_rate,
.get_rate = imx8mp_clk_get_rate,
.enable = imx8mp_clk_enable,
.disable = imx8mp_clk_disable,
+ .set_parent = imx8mp_clk_set_parent,
};
static int imx8mp_clk_probe(struct udevice *dev)
@@ -290,6 +333,7 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_A53_DIV, imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3));
clk_dm(IMX8MP_CLK_MAIN_AXI, imx8m_clk_composite_critical("main_axi", imx8mp_main_axi_sels, base + 0x8800));
+ clk_dm(IMX8MP_CLK_ENET_AXI, imx8m_clk_composite_critical("enet_axi", imx8mp_enet_axi_sels, base + 0x8880));
clk_dm(IMX8MP_CLK_NAND_USDHC_BUS, imx8m_clk_composite_critical("nand_usdhc_bus", imx8mp_nand_usdhc_sels, base + 0x8900));
clk_dm(IMX8MP_CLK_NOC, imx8m_clk_composite_critical("noc", imx8mp_noc_sels, base + 0x8d00));
clk_dm(IMX8MP_CLK_NOC_IO, imx8m_clk_composite_critical("noc_io", imx8mp_noc_io_sels, base + 0x8d80));
@@ -302,6 +346,10 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_DRAM_APB, imx8m_clk_composite_critical("dram_apb", imx8mp_dram_apb_sels, base + 0xa080));
clk_dm(IMX8MP_CLK_I2C5, imx8m_clk_composite("i2c5", imx8mp_i2c5_sels, base + 0xa480));
clk_dm(IMX8MP_CLK_I2C6, imx8m_clk_composite("i2c6", imx8mp_i2c6_sels, base + 0xa500));
+ clk_dm(IMX8MP_CLK_ENET_REF, imx8m_clk_composite("enet_ref", imx8mp_enet_ref_sels, base + 0xa980));
+ clk_dm(IMX8MP_CLK_ENET_TIMER, imx8m_clk_composite("enet_timer", imx8mp_enet_timer_sels, base + 0xaa00));
+ clk_dm(IMX8MP_CLK_ENET_PHY_REF, imx8m_clk_composite("enet_phy_ref", imx8mp_enet_phy_ref_sels, base + 0xaa80));
+ clk_dm(IMX8MP_CLK_QSPI, imx8m_clk_composite("qspi", imx8mp_qspi_sels, base + 0xab80));
clk_dm(IMX8MP_CLK_USDHC1, imx8m_clk_composite("usdhc1", imx8mp_usdhc1_sels, base + 0xac00));
clk_dm(IMX8MP_CLK_USDHC2, imx8m_clk_composite("usdhc2", imx8mp_usdhc2_sels, base + 0xac80));
clk_dm(IMX8MP_CLK_I2C1, imx8m_clk_composite("i2c1", imx8mp_i2c1_sels, base + 0xad00));
@@ -322,6 +370,8 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_DRAM_CORE, imx_clk_mux2_flags("dram_core_clk", base + 0x9800, 24, 1, imx8mp_dram_core_sels, ARRAY_SIZE(imx8mp_dram_core_sels), CLK_IS_CRITICAL));
clk_dm(IMX8MP_CLK_DRAM1_ROOT, imx_clk_gate4_flags("dram1_root_clk", "dram_core_clk", base + 0x4050, 0, CLK_IS_CRITICAL));
+
+ clk_dm(IMX8MP_CLK_ENET1_ROOT, imx_clk_gate4("enet1_root_clk", "enet_axi", base + 0x40a0, 0));
clk_dm(IMX8MP_CLK_GPIO1_ROOT, imx_clk_gate4("gpio1_root_clk", "ipg_root", base + 0x40b0, 0));
clk_dm(IMX8MP_CLK_GPIO2_ROOT, imx_clk_gate4("gpio2_root_clk", "ipg_root", base + 0x40c0, 0));
clk_dm(IMX8MP_CLK_GPIO3_ROOT, imx_clk_gate4("gpio3_root_clk", "ipg_root", base + 0x40d0, 0));
@@ -331,8 +381,10 @@ static int imx8mp_clk_probe(struct udevice *dev)
clk_dm(IMX8MP_CLK_I2C2_ROOT, imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0));
clk_dm(IMX8MP_CLK_I2C3_ROOT, imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0));
clk_dm(IMX8MP_CLK_I2C4_ROOT, imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0));
+ clk_dm(IMX8MP_CLK_QSPI_ROOT, imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0));
clk_dm(IMX8MP_CLK_I2C5_ROOT, imx_clk_gate2("i2c5_root_clk", "i2c5", base + 0x4330, 0));
clk_dm(IMX8MP_CLK_I2C6_ROOT, imx_clk_gate2("i2c6_root_clk", "i2c6", base + 0x4340, 0));
+ clk_dm(IMX8MP_CLK_SIM_ENET_ROOT, imx_clk_gate4("sim_enet_root_clk", "enet_axi", base + 0x4400, 0));
clk_dm(IMX8MP_CLK_UART1_ROOT, imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0));
clk_dm(IMX8MP_CLK_UART2_ROOT, imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0));
clk_dm(IMX8MP_CLK_UART3_ROOT, imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0));
diff --git a/drivers/ddr/imx/imx8m/Kconfig b/drivers/ddr/imx/imx8m/Kconfig
index 5bf61eb..a5f5524 100644
--- a/drivers/ddr/imx/imx8m/Kconfig
+++ b/drivers/ddr/imx/imx8m/Kconfig
@@ -29,4 +29,11 @@ config SAVED_DRAM_TIMING_BASE
info into memory for low power use. OCRAM_S is used for this
purpose on i.MX8MM.
default 0x180000
+
+config IMX8M_DRAM_INLINE_ECC
+ bool "imx8mp inline ECC"
+ depends on IMX8MP && IMX8M_LPDDR4
+ help
+ Select this config if you want to use inline ecc feature for
+ imx8mp-evk board.
endmenu
diff --git a/drivers/ddr/imx/imx8m/ddr_init.c b/drivers/ddr/imx/imx8m/ddr_init.c
index bbddee6..99a67ed 100644
--- a/drivers/ddr/imx/imx8m/ddr_init.c
+++ b/drivers/ddr/imx/imx8m/ddr_init.c
@@ -21,6 +21,76 @@ void ddr_cfg_umctl2(struct dram_cfg_param *ddrc_cfg, int num)
}
}
+#ifdef CONFIG_IMX8M_DRAM_INLINE_ECC
+void ddrc_inline_ecc_scrub(unsigned int start_address,
+ unsigned int range_address)
+{
+ unsigned int tmp;
+
+ /* Step1: Enable quasi-dynamic programming */
+ reg32_write(DDRC_SWCTL(0), 0x00000000);
+ /* Step2: Set ECCCFG1.ecc_parity_region_lock to 1 */
+ reg32setbit(DDRC_ECCCFG1(0), 0x4);
+ /* Step3: Block the AXI ports from taking the transaction */
+ reg32_write(DDRC_PCTRL_0(0), 0x0);
+ /* Step4: Set scrub start address */
+ reg32_write(DDRC_SBRSTART0(0), start_address);
+ /* Step5: Set scrub range address */
+ reg32_write(DDRC_SBRRANGE0(0), range_address);
+ /* Step6: Set scrub_mode to write */
+ reg32_write(DDRC_SBRCTL(0), 0x00000014);
+ /* Step7: Set the desired pattern through SBRWDATA0 registers */
+ reg32_write(DDRC_SBRWDATA0(0), 0x55aa55aa);
+ /* Step8: Enable the SBR by programming SBRCTL.scrub_en=1 */
+ reg32setbit(DDRC_SBRCTL(0), 0x0);
+ /* Step9: Poll SBRSTAT.scrub_done=1 */
+ tmp = reg32_read(DDRC_SBRSTAT(0));
+ while (tmp != 0x00000002)
+ tmp = reg32_read(DDRC_SBRSTAT(0)) & 0x2;
+ /* Step10: Poll SBRSTAT.scrub_busy=0 */
+ tmp = reg32_read(DDRC_SBRSTAT(0));
+ while (tmp != 0x0)
+ tmp = reg32_read(DDRC_SBRSTAT(0)) & 0x1;
+ /* Step11: Disable SBR by programming SBRCTL.scrub_en=0 */
+ clrbits_le32(DDRC_SBRCTL(0), 0x1);
+ /* Step12: Prepare for normal scrub operation(Read) and set scrub_interval*/
+ reg32_write(DDRC_SBRCTL(0), 0x100);
+ /* Step13: Enable the SBR by programming SBRCTL.scrub_en=1 */
+ reg32_write(DDRC_SBRCTL(0), 0x101);
+ /* Step14: Enable AXI ports by programming */
+ reg32_write(DDRC_PCTRL_0(0), 0x1);
+ /* Step15: Disable quasi-dynamic programming */
+ reg32_write(DDRC_SWCTL(0), 0x00000001);
+}
+
+void ddrc_inline_ecc_scrub_end(unsigned int start_address,
+ unsigned int range_address)
+{
+ /* Step1: Enable quasi-dynamic programming */
+ reg32_write(DDRC_SWCTL(0), 0x00000000);
+ /* Step2: Block the AXI ports from taking the transaction */
+ reg32_write(DDRC_PCTRL_0(0), 0x0);
+ /* Step3: Set scrub start address */
+ reg32_write(DDRC_SBRSTART0(0), start_address);
+ /* Step4: Set scrub range address */
+ reg32_write(DDRC_SBRRANGE0(0), range_address);
+ /* Step5: Disable SBR by programming SBRCTL.scrub_en=0 */
+ clrbits_le32(DDRC_SBRCTL(0), 0x1);
+ /* Step6: Prepare for normal scrub operation(Read) and set scrub_interval */
+ reg32_write(DDRC_SBRCTL(0), 0x100);
+ /* Step7: Enable the SBR by programming SBRCTL.scrub_en=1 */
+ reg32_write(DDRC_SBRCTL(0), 0x101);
+ /* Step8: Enable AXI ports by programming */
+ reg32_write(DDRC_PCTRL_0(0), 0x1);
+ /* Step9: Disable quasi-dynamic programming */
+ reg32_write(DDRC_SWCTL(0), 0x00000001);
+}
+#endif
+
+void __weak board_dram_ecc_scrub(void)
+{
+}
+
int ddr_init(struct dram_timing_info *dram_timing)
{
unsigned int tmp, initial_drate, target_freq;
@@ -74,7 +144,7 @@ int ddr_init(struct dram_timing_info *dram_timing)
/* if ddr type is LPDDR4, do it */
tmp = reg32_read(DDRC_MSTR(0));
- if (tmp & (0x1 << 5))
+ if (tmp & (0x1 << 5) && !is_imx8mn())
reg32_write(DDRC_DDR_SS_GPR0, 0x01); /* LPDDR4 mode */
/* determine the initial boot frequency */
@@ -120,6 +190,9 @@ int ddr_init(struct dram_timing_info *dram_timing)
/* Step15: Set SWCTL.sw_done to 0 */
reg32_write(DDRC_SWCTL(0), 0x00000000);
+ /* Apply rank-to-rank workaround */
+ update_umctl2_rank_space_setting(dram_timing->fsp_msg_num - 1);
+
/* Step16: Set DFIMISC.dfi_init_start to 1 */
setbits_le32(DDRC_DFIMISC(0), (0x1 << 5));
@@ -163,12 +236,14 @@ int ddr_init(struct dram_timing_info *dram_timing)
/* Step26: Set back register in Step4 to the original values if desired */
reg32_write(DDRC_RFSHCTL3(0), 0x0000000);
/* enable selfref_en by default */
- setbits_le32(DDRC_PWRCTL(0), 0x1 << 3);
+ setbits_le32(DDRC_PWRCTL(0), 0x1);
/* enable port 0 */
reg32_write(DDRC_PCTRL_0(0), 0x00000001);
debug("DDRINFO: ddrmix config done\n");
+ board_dram_ecc_scrub();
+
/* save the dram timing config into memory */
dram_config_save(dram_timing, CONFIG_SAVED_DRAM_TIMING_BASE);
diff --git a/drivers/ddr/imx/imx8m/ddrphy_train.c b/drivers/ddr/imx/imx8m/ddrphy_train.c
index f2a997b..08fed61 100644
--- a/drivers/ddr/imx/imx8m/ddrphy_train.c
+++ b/drivers/ddr/imx/imx8m/ddrphy_train.c
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <asm/arch/ddr.h>
#include <asm/arch/lpddr4_define.h>
+#include <asm/arch/sys_proto.h>
int ddr_cfg_phy(struct dram_timing_info *dram_timing)
{
@@ -71,9 +72,15 @@ int ddr_cfg_phy(struct dram_timing_info *dram_timing)
/* Read the Message Block results */
dwc_ddrphy_apb_wr(0xd0000, 0x0);
+
ddrphy_init_read_msg_block(fsp_msg->fw_type);
+
+ if(fsp_msg->fw_type != FW_2D_IMAGE)
+ get_trained_CDD(i);
+
dwc_ddrphy_apb_wr(0xd0000, 0x1);
+
fsp_msg++;
}
diff --git a/drivers/ddr/imx/imx8m/ddrphy_utils.c b/drivers/ddr/imx/imx8m/ddrphy_utils.c
index d5eef53..20ae47b 100644
--- a/drivers/ddr/imx/imx8m/ddrphy_utils.c
+++ b/drivers/ddr/imx/imx8m/ddrphy_utils.c
@@ -11,6 +11,12 @@
#include <asm/arch/clock.h>
#include <asm/arch/ddr.h>
#include <asm/arch/lpddr4_define.h>
+#include <asm/arch/sys_proto.h>
+
+static unsigned int g_cdd_rr_max[4];
+static unsigned int g_cdd_rw_max[4];
+static unsigned int g_cdd_wr_max[4];
+static unsigned int g_cdd_ww_max[4];
static inline void poll_pmu_message_ready(void)
{
@@ -193,3 +199,161 @@ unsigned int lpddr4_mr_read(unsigned int mr_rank, unsigned int mr_addr)
return tmp;
}
+
+unsigned int look_for_max(unsigned int data[],
+ unsigned int addr_start, unsigned int addr_end)
+{
+ unsigned int i, imax = 0;
+
+ for (i = addr_start; i <= addr_end; i++) {
+ if (((data[i] >> 7) == 0) && (data[i] > imax))
+ imax = data[i];
+ }
+
+ return imax;
+}
+
+void get_trained_CDD(u32 fsp)
+{
+ unsigned int i, ddr_type, tmp;
+ unsigned int cdd_cha[12], cdd_chb[12];
+ unsigned int cdd_cha_rr_max, cdd_cha_rw_max, cdd_cha_wr_max, cdd_cha_ww_max;
+ unsigned int cdd_chb_rr_max, cdd_chb_rw_max, cdd_chb_wr_max, cdd_chb_ww_max;
+
+ ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
+ if (ddr_type == 0x20) {
+ for (i = 0; i < 6; i++) {
+ tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x54013 + i) * 4);
+ cdd_cha[i * 2] = tmp & 0xff;
+ cdd_cha[i * 2 + 1] = (tmp >> 8) & 0xff;
+ }
+
+ for (i = 0; i < 7; i++) {
+ tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x5402c + i) * 4);
+ if (i == 0) {
+ cdd_cha[0] = (tmp >> 8) & 0xff;
+ } else if (i == 6) {
+ cdd_cha[11]=tmp & 0xff;
+ } else {
+ cdd_chb[ i * 2 - 1] = tmp & 0xff;
+ cdd_chb[i * 2] = (tmp >> 8) & 0xff;
+ }
+ }
+
+ cdd_cha_rr_max = look_for_max(cdd_cha, 0, 1);
+ cdd_cha_rw_max = look_for_max(cdd_cha, 2, 5);
+ cdd_cha_wr_max = look_for_max(cdd_cha, 6, 9);
+ cdd_cha_ww_max = look_for_max(cdd_cha, 10, 11);
+ cdd_chb_rr_max = look_for_max(cdd_chb, 0, 1);
+ cdd_chb_rw_max = look_for_max(cdd_chb, 2, 5);
+ cdd_chb_wr_max = look_for_max(cdd_chb, 6, 9);
+ cdd_chb_ww_max = look_for_max(cdd_chb, 10, 11);
+ g_cdd_rr_max[fsp] = cdd_cha_rr_max > cdd_chb_rr_max ? cdd_cha_rr_max : cdd_chb_rr_max;
+ g_cdd_rw_max[fsp] = cdd_cha_rw_max > cdd_chb_rw_max ? cdd_cha_rw_max : cdd_chb_rw_max;
+ g_cdd_wr_max[fsp] = cdd_cha_wr_max > cdd_chb_wr_max ? cdd_cha_wr_max : cdd_chb_wr_max;
+ g_cdd_ww_max[fsp] = cdd_cha_ww_max > cdd_chb_ww_max ? cdd_cha_ww_max : cdd_chb_ww_max;
+ } else {
+ unsigned int ddr4_cdd[64];
+ for( i = 0; i < 29; i++) {
+ tmp = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + (0x54012 + i) * 4);
+ ddr4_cdd[i * 2] = tmp & 0xff;
+ ddr4_cdd[i * 2 + 1] = (tmp >> 8) & 0xff;
+ }
+
+ g_cdd_rr_max[fsp] = look_for_max(ddr4_cdd, 1, 12);
+ g_cdd_ww_max[fsp] = look_for_max(ddr4_cdd, 13, 24);
+ g_cdd_rw_max[fsp] = look_for_max(ddr4_cdd, 25, 40);
+ g_cdd_wr_max[fsp] = look_for_max(ddr4_cdd, 41, 56);
+ }
+}
+
+void update_umctl2_rank_space_setting(unsigned int pstat_num)
+{
+ unsigned int i,ddr_type;
+ unsigned int addr_slot, rdata, tmp, tmp_t;
+ unsigned int ddrc_w2r,ddrc_r2w,ddrc_wr_gap,ddrc_rd_gap;
+
+ ddr_type = reg32_read(DDRC_MSTR(0)) & 0x3f;
+ for (i = 0; i < pstat_num; i++) {
+ addr_slot = i ? (i + 1) * 0x1000 : 0;
+ if (ddr_type == 0x20) {
+ /* update r2w:[13:8], w2r:[5:0] */
+ rdata=reg32_read(DDRC_DRAMTMG2(0) + addr_slot);
+ ddrc_w2r = rdata & 0x3f;
+ if(is_imx8mp())
+ tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1);
+ else
+ tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1;
+ ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp;
+
+ ddrc_r2w = (rdata >> 8) & 0x3f;
+ if (is_imx8mp())
+ tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1);
+ else
+ tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1;
+ ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp;
+
+ tmp_t = (rdata & 0xffffc0c0) | (ddrc_r2w << 8) | ddrc_w2r;
+ reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t);
+ } else {
+ /* update w2r:[5:0] */
+ rdata=reg32_read(DDRC_DRAMTMG9(0) + addr_slot);
+ ddrc_w2r = rdata & 0x3f;
+ if (is_imx8mp())
+ tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1);
+ else
+ tmp = ddrc_w2r + (g_cdd_wr_max[i] >> 1) + 1;
+ ddrc_w2r = (tmp > 0x3f) ? 0x3f : tmp;
+ tmp_t = (rdata & 0xffffffc0) | ddrc_w2r;
+ reg32_write((DDRC_DRAMTMG9(0) + addr_slot), tmp_t);
+
+ /* update r2w:[13:8] */
+ rdata = reg32_read(DDRC_DRAMTMG2(0) + addr_slot);
+ ddrc_r2w = (rdata >> 8) & 0x3f;
+ if(is_imx8mp())
+ tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1);
+ else
+ tmp = ddrc_r2w + (g_cdd_rw_max[i] >> 1) + 1;
+ ddrc_r2w = (tmp > 0x3f) ? 0x3f : tmp;
+
+ tmp_t = (rdata & 0xffffc0ff) | (ddrc_r2w << 8);
+ reg32_write((DDRC_DRAMTMG2(0) + addr_slot), tmp_t);
+ }
+
+ if (!is_imx8mq()) {
+ /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */
+ rdata = reg32_read(DDRC_RANKCTL(0) + addr_slot);
+ ddrc_wr_gap = (rdata >> 8) & 0xf;
+ if(is_imx8mp())
+ tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1);
+ else
+ tmp = ddrc_wr_gap + (g_cdd_ww_max[i] >> 1) + 1;
+ ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp;
+
+ ddrc_rd_gap = (rdata >> 4) & 0xf;
+ if (is_imx8mp())
+ tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1);
+ else
+ tmp = ddrc_rd_gap + (g_cdd_rr_max[i] >> 1) + 1;
+ ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp;
+
+ tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4);
+ reg32_write((DDRC_RANKCTL(0) + addr_slot), tmp_t);
+ }
+ }
+
+ if(is_imx8mq()) {
+ /* update rankctl: wr_gap:11:8; rd:gap:7:4; quasi-dymic, doc wrong(static) */
+ rdata = reg32_read(DDRC_RANKCTL(0));
+ ddrc_wr_gap = (rdata >> 8) & 0xf;
+ tmp = ddrc_wr_gap + (g_cdd_ww_max[0] >> 1) + 1;
+ ddrc_wr_gap = (tmp > 0xf) ? 0xf : tmp;
+
+ ddrc_rd_gap = (rdata >> 4) & 0xf;
+ tmp = ddrc_rd_gap + (g_cdd_rr_max[0] >> 1) + 1;
+ ddrc_rd_gap = (tmp > 0xf) ? 0xf : tmp;
+
+ tmp_t = (rdata & 0xfffff00f) | (ddrc_wr_gap << 8) | (ddrc_rd_gap << 4);
+ reg32_write(DDRC_RANKCTL(0), tmp_t);
+ }
+}
diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c
index 316dcc7..90d36fb 100644
--- a/drivers/gpio/mxc_gpio.c
+++ b/drivers/gpio/mxc_gpio.c
@@ -295,46 +295,26 @@ static int mxc_gpio_probe(struct udevice *dev)
return 0;
}
-static int mxc_gpio_bind(struct udevice *dev)
+static int mxc_gpio_ofdata_to_platdata(struct udevice *dev)
{
- struct mxc_gpio_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;
+ struct mxc_gpio_plat *plat = dev_get_platdata(dev);
addr = devfdt_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- /*
- * 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.
- *
- * For example mxc_plat below uses platform data rather than device
- * tree.
- *
- * NOTE: DO NOT COPY this code if you are using device tree.
- */
- 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 int mxc_gpio_bind(struct udevice *dev)
+{
+ return 0;
+}
+
static const struct udevice_id mxc_gpio_ids[] = {
{ .compatible = "fsl,imx35-gpio" },
{ }
@@ -345,6 +325,8 @@ U_BOOT_DRIVER(gpio_mxc) = {
.id = UCLASS_GPIO,
.ops = &gpio_mxc_ops,
.probe = mxc_gpio_probe,
+ .ofdata_to_platdata = mxc_gpio_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct mxc_gpio_plat),
.priv_auto_alloc_size = sizeof(struct mxc_bank_info),
.of_match = mxc_gpio_ids,
.bind = mxc_gpio_bind,
diff --git a/drivers/misc/imx8/fuse.c b/drivers/misc/imx8/fuse.c
index 4d7f2f5..be18122 100644
--- a/drivers/misc/imx8/fuse.c
+++ b/drivers/misc/imx8/fuse.c
@@ -9,6 +9,7 @@
#include <fuse.h>
#include <asm/arch/sci/sci.h>
#include <asm/arch/sys_proto.h>
+#include <linux/arm-smccc.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -36,22 +37,24 @@ int fuse_read(u32 bank, u32 word, u32 *val)
int fuse_sense(u32 bank, u32 word, u32 *val)
{
- unsigned long ret = 0, value = 0;
+ struct arm_smccc_res res;
if (bank != 0) {
printf("Invalid bank argument, ONLY bank 0 is supported\n");
return -EINVAL;
}
- ret = call_imx_sip_ret2(FSL_SIP_OTP_READ, (unsigned long)word, &value,
- 0, 0);
- *val = (u32)value;
+ arm_smccc_smc(FSL_SIP_OTP_READ, (unsigned long)word, 0, 0,
+ 0, 0, 0, 0, &res);
+ *val = (u32)res.a1;
- return ret;
+ return res.a0;
}
int fuse_prog(u32 bank, u32 word, u32 val)
{
+ struct arm_smccc_res res;
+
if (bank != 0) {
printf("Invalid bank argument, ONLY bank 0 is supported\n");
return -EINVAL;
@@ -78,8 +81,10 @@ int fuse_prog(u32 bank, u32 word, u32 val)
}
}
- return call_imx_sip(FSL_SIP_OTP_WRITE, (unsigned long)word,
- (unsigned long)val, 0, 0);
+ arm_smccc_smc(FSL_SIP_OTP_WRITE, (unsigned long)word,
+ (unsigned long)val, 0, 0, 0, 0, 0, &res);
+
+ return res.a0;
}
int fuse_override(u32 bank, u32 word, u32 val)
diff --git a/drivers/misc/imx8/scu_api.c b/drivers/misc/imx8/scu_api.c
index 3e38edb..20b74fb 100644
--- a/drivers/misc/imx8/scu_api.c
+++ b/drivers/misc/imx8/scu_api.c
@@ -374,6 +374,31 @@ void sc_misc_boot_status(sc_ipc_t ipc, sc_misc_boot_status_t status)
__func__, status, RPC_R8(&msg));
}
+int sc_misc_get_boot_container(sc_ipc_t ipc, u8 *idx)
+{
+ struct udevice *dev = gd->arch.scu_dev;
+ int size = sizeof(struct sc_rpc_msg_s);
+ struct sc_rpc_msg_s msg;
+ int ret;
+
+ if (!dev)
+ hang();
+
+ RPC_VER(&msg) = SC_RPC_VERSION;
+ RPC_SIZE(&msg) = 1U;
+ RPC_SVC(&msg) = (u8)SC_RPC_SVC_MISC;
+ RPC_FUNC(&msg) = (u8)MISC_FUNC_GET_BOOT_CONTAINER;
+
+ ret = misc_call(dev, SC_FALSE, &msg, size, &msg, size);
+ if (ret < 0)
+ return ret;
+
+ if (idx)
+ *idx = (u8)RPC_U8(&msg, 0U);
+
+ return 0;
+}
+
void sc_misc_build_info(sc_ipc_t ipc, u32 *build, u32 *commit)
{
struct udevice *dev = gd->arch.scu_dev;
diff --git a/drivers/pinctrl/nxp/pinctrl-imx5.c b/drivers/pinctrl/nxp/pinctrl-imx5.c
index 5d17380..9c3423b 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx5.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx5.c
@@ -10,7 +10,7 @@
#include "pinctrl-imx.h"
-static struct imx_pinctrl_soc_info imx5_pinctrl_soc_info;
+static struct imx_pinctrl_soc_info imx5_pinctrl_soc_info __attribute__((section(".data")));
static int imx5_pinctrl_probe(struct udevice *dev)
{
diff --git a/drivers/pinctrl/nxp/pinctrl-imx7.c b/drivers/pinctrl/nxp/pinctrl-imx7.c
index 769d428..66b58ba 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx7.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx7.c
@@ -9,7 +9,7 @@
#include "pinctrl-imx.h"
-static struct imx_pinctrl_soc_info imx7_pinctrl_soc_info;
+static struct imx_pinctrl_soc_info imx7_pinctrl_soc_info __attribute__((section(".data")));
static struct imx_pinctrl_soc_info imx7_lpsr_pinctrl_soc_info = {
.flags = ZERO_OFFSET_VALID,
diff --git a/drivers/pinctrl/nxp/pinctrl-imx8m.c b/drivers/pinctrl/nxp/pinctrl-imx8m.c
index 5b7cbb6..0626fde 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx8m.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx8m.c
@@ -8,7 +8,7 @@
#include "pinctrl-imx.h"
-static struct imx_pinctrl_soc_info imx8mq_pinctrl_soc_info;
+static struct imx_pinctrl_soc_info imx8mq_pinctrl_soc_info __attribute__((section(".data")));
static int imx8mq_pinctrl_probe(struct udevice *dev)
{
diff --git a/drivers/power/domain/imx8m-power-domain.c b/drivers/power/domain/imx8m-power-domain.c
index 5b6467c..0ef460d 100644
--- a/drivers/power/domain/imx8m-power-domain.c
+++ b/drivers/power/domain/imx8m-power-domain.c
@@ -13,6 +13,7 @@
#include <dm/device-internal.h>
#include <dm/device.h>
#include <imx_sip.h>
+#include <linux/arm-smccc.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -30,6 +31,7 @@ static int imx8m_power_domain_on(struct power_domain *power_domain)
{
struct udevice *dev = power_domain->dev;
struct imx8m_power_domain_platdata *pdata;
+
pdata = dev_get_platdata(dev);
if (pdata->resource_id < 0)
@@ -38,8 +40,8 @@ static int imx8m_power_domain_on(struct power_domain *power_domain)
if (pdata->has_pd)
power_domain_on(&pdata->pd);
- call_imx_sip(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN,
- pdata->resource_id, 1, 0);
+ arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN,
+ pdata->resource_id, 1, 0, 0, 0, 0, NULL);
return 0;
}
@@ -53,8 +55,8 @@ static int imx8m_power_domain_off(struct power_domain *power_domain)
if (pdata->resource_id < 0)
return -EINVAL;
- call_imx_sip(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN,
- pdata->resource_id, 0, 0);
+ arm_smccc_smc(IMX_SIP_GPC, IMX_SIP_GPC_PM_DOMAIN,
+ pdata->resource_id, 0, 0, 0, 0, 0, NULL);
if (pdata->has_pd)
power_domain_off(&pdata->pd);
diff --git a/drivers/power/pmic/pmic_pca9450.c b/drivers/power/pmic/pmic_pca9450.c
index 67a9090..d4f2742 100644
--- a/drivers/power/pmic/pmic_pca9450.c
+++ b/drivers/power/pmic/pmic_pca9450.c
@@ -11,26 +11,7 @@
static const char pca9450_name[] = "PCA9450";
-int power_pca9450a_init(unsigned char bus)
-{
- struct pmic *p = pmic_alloc();
-
- if (!p) {
- printf("%s: POWER allocation error!\n", __func__);
- return -ENOMEM;
- }
-
- p->name = pca9450_name;
- p->interface = PMIC_I2C;
- p->number_of_regs = PCA9450_REG_NUM;
- p->hw.i2c.addr = 0x35;
- p->hw.i2c.tx_num = 1;
- p->bus = bus;
-
- return 0;
-}
-
-int power_pca9450b_init(unsigned char bus)
+int power_pca9450_init(unsigned char bus)
{
struct pmic *p = pmic_alloc();
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 3a8add9..30d808d 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -155,6 +155,14 @@ config FSL_QSPI
used to access the SPI NOR flash on platforms embedding this
Freescale IP core.
+config FSL_QSPI_AHB_FULL_MAP
+ bool "Use full AHB memory map space"
+ depends on FSL_QSPI
+ default y if ARCH_MX6 || ARCH_MX7 || ARCH_MX7ULP || ARCH_IMX8M
+ help
+ Enable the Freescale QSPI driver to use full AHB memory map space for
+ flash access.
+
config ICH_SPI
bool "Intel ICH SPI driver"
help
diff --git a/drivers/spi/fsl_qspi.c b/drivers/spi/fsl_qspi.c
index e715f98..eec968e 100644
--- a/drivers/spi/fsl_qspi.c
+++ b/drivers/spi/fsl_qspi.c
@@ -46,6 +46,7 @@ DECLARE_GLOBAL_DATA_PTR;
* read operation, so let's use the last entry (15).
*/
#define SEQID_LUT 15
+#define SEQID_LUT_AHB 14
/* Registers used by the driver */
#define QUADSPI_MCR 0x00
@@ -122,6 +123,10 @@ DECLARE_GLOBAL_DATA_PTR;
#define QUADSPI_LUT_REG(idx) \
(QUADSPI_LUT_BASE + QUADSPI_LUT_OFFSET + (idx) * 4)
+#define QUADSPI_AHB_LUT_OFFSET (SEQID_LUT_AHB * 4 * 4)
+#define QUADSPI_AHB_LUT_REG(idx) \
+ (QUADSPI_LUT_BASE + QUADSPI_AHB_LUT_OFFSET + (idx) * 4)
+
/* Instruction set for the LUT register */
#define LUT_STOP 0
#define LUT_CMD 1
@@ -189,6 +194,11 @@ DECLARE_GLOBAL_DATA_PTR;
*/
#define QUADSPI_QUIRK_USE_TDH_SETTING BIT(5)
+/*
+ * Controller only has Two CS on flash A, no flash B port
+ */
+#define QUADSPI_QUIRK_SINGLE_BUS BIT(6)
+
struct fsl_qspi_devtype_data {
unsigned int rxfifo;
unsigned int txfifo;
@@ -231,6 +241,15 @@ static const struct fsl_qspi_devtype_data imx6ul_data = {
.little_endian = true,
};
+static const struct fsl_qspi_devtype_data imx7ulp_data = {
+ .rxfifo = SZ_64,
+ .txfifo = SZ_64,
+ .ahb_buf_size = SZ_128,
+ .quirks = QUADSPI_QUIRK_TKT253890 | QUADSPI_QUIRK_4X_INT_CLK |
+ QUADSPI_QUIRK_USE_TDH_SETTING | QUADSPI_QUIRK_SINGLE_BUS,
+ .little_endian = true,
+};
+
static const struct fsl_qspi_devtype_data ls1021a_data = {
.rxfifo = SZ_128,
.txfifo = SZ_64,
@@ -260,6 +279,7 @@ struct fsl_qspi {
void __iomem *iobase;
void __iomem *ahb_addr;
u32 memmap_phy;
+ u32 memmap_size;
const struct fsl_qspi_devtype_data *devtype_data;
int selected;
};
@@ -294,6 +314,11 @@ static inline int needs_tdh_setting(struct fsl_qspi *q)
return q->devtype_data->quirks & QUADSPI_QUIRK_USE_TDH_SETTING;
}
+static inline int needs_single_bus(struct fsl_qspi *q)
+{
+ return q->devtype_data->quirks & QUADSPI_QUIRK_SINGLE_BUS;
+}
+
/*
* An IC bug makes it necessary to rearrange the 32-bit data.
* Later chips, such as IMX6SLX, have fixed this bug.
@@ -396,18 +421,27 @@ static void fsl_qspi_prepare_lut(struct fsl_qspi *q,
lutval[0] |= LUT_DEF(0, LUT_CMD, LUT_PAD(op->cmd.buswidth),
op->cmd.opcode);
- /*
- * For some unknown reason, using LUT_ADDR doesn't work in some
- * cases (at least with only one byte long addresses), so
- * let's use LUT_MODE to write the address bytes one by one
- */
- for (i = 0; i < op->addr.nbytes; i++) {
- u8 addrbyte = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
-
- lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_MODE,
- LUT_PAD(op->addr.buswidth),
- addrbyte);
- lutidx++;
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) {
+ if (op->addr.nbytes) {
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_ADDR,
+ LUT_PAD(op->addr.buswidth),
+ (op->addr.nbytes == 4) ? 0x20 : 0x18);
+ lutidx++;
+ }
+ } else {
+ /*
+ * For some unknown reason, using LUT_ADDR doesn't work in some
+ * cases (at least with only one byte long addresses), so
+ * let's use LUT_MODE to write the address bytes one by one
+ */
+ for (i = 0; i < op->addr.nbytes; i++) {
+ u8 addrbyte = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
+
+ lutval[lutidx / 2] |= LUT_DEF(lutidx, LUT_MODE,
+ LUT_PAD(op->addr.buswidth),
+ addrbyte);
+ lutidx++;
+ }
}
if (op->dummy.nbytes) {
@@ -440,6 +474,14 @@ static void fsl_qspi_prepare_lut(struct fsl_qspi *q,
for (i = 0; i < ARRAY_SIZE(lutval); i++)
qspi_writel(q, lutval[i], base + QUADSPI_LUT_REG(i));
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) {
+ if (op->data.nbytes && op->data.dir == SPI_MEM_DATA_IN &&
+ op->addr.nbytes) {
+ for (i = 0; i < ARRAY_SIZE(lutval); i++)
+ qspi_writel(q, lutval[i], base + QUADSPI_AHB_LUT_REG(i));
+ }
+ }
+
/* lock LUT */
qspi_writel(q, QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
qspi_writel(q, QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
@@ -482,10 +524,29 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_slave *slave)
fsl_qspi_invalidate(q);
}
+static u32 fsl_qspi_memsize_per_cs(struct fsl_qspi *q)
+{
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) {
+ if (needs_single_bus(q))
+ return q->memmap_size / 2;
+ else
+ return q->memmap_size / 4;
+ } else {
+ return ALIGN(q->devtype_data->ahb_buf_size, 0x400);
+ }
+}
+
static void fsl_qspi_read_ahb(struct fsl_qspi *q, const struct spi_mem_op *op)
{
+ void __iomem *ahb_read_addr = q->ahb_addr;
+
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) {
+ if (op->addr.nbytes)
+ ahb_read_addr += op->addr.val;
+ }
+
memcpy_fromio(op->data.buf.in,
- q->ahb_addr + q->selected * q->devtype_data->ahb_buf_size,
+ ahb_read_addr + q->selected * fsl_qspi_memsize_per_cs(q),
op->data.nbytes);
}
@@ -588,8 +649,13 @@ static int fsl_qspi_exec_op(struct spi_slave *slave,
if (needs_amba_base_offset(q))
addr_offset = q->memmap_phy;
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP)) {
+ if (op->addr.nbytes)
+ addr_offset += op->addr.val;
+ }
+
qspi_writel(q,
- q->selected * q->devtype_data->ahb_buf_size + addr_offset,
+ q->selected * fsl_qspi_memsize_per_cs(q) + addr_offset,
base + QUADSPI_SFAR);
qspi_writel(q, qspi_readl(q, base + QUADSPI_MCR) |
@@ -646,7 +712,7 @@ static int fsl_qspi_adjust_op_size(struct spi_slave *slave,
static int fsl_qspi_default_setup(struct fsl_qspi *q)
{
void __iomem *base = q->iobase;
- u32 reg, addr_offset = 0;
+ u32 reg, addr_offset = 0, memsize_cs;
/* Reset the module */
qspi_writel(q, QUADSPI_MCR_SWRSTSD_MASK | QUADSPI_MCR_SWRSTHD_MASK,
@@ -678,8 +744,13 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q)
qspi_writel(q, 0, base + QUADSPI_BUF1IND);
qspi_writel(q, 0, base + QUADSPI_BUF2IND);
- qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT),
- q->iobase + QUADSPI_BFGENCR);
+ if (IS_ENABLED(CONFIG_FSL_QSPI_AHB_FULL_MAP))
+ qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT_AHB),
+ q->iobase + QUADSPI_BFGENCR);
+ else
+ qspi_writel(q, QUADSPI_BFGENCR_SEQID(SEQID_LUT),
+ q->iobase + QUADSPI_BFGENCR);
+
qspi_writel(q, QUADSPI_RBCT_WMRK_MASK, base + QUADSPI_RBCT);
qspi_writel(q, QUADSPI_BUF3CR_ALLMST_MASK |
QUADSPI_BUF3CR_ADATSZ(q->devtype_data->ahb_buf_size / 8),
@@ -695,14 +766,17 @@ static int fsl_qspi_default_setup(struct fsl_qspi *q)
* We use ahb_buf_size for each chip and set SFA1AD, SFA2AD, SFB1AD,
* SFB2AD accordingly.
*/
- qspi_writel(q, q->devtype_data->ahb_buf_size + addr_offset,
+ memsize_cs = fsl_qspi_memsize_per_cs(q);
+ qspi_writel(q, memsize_cs + addr_offset,
base + QUADSPI_SFA1AD);
- qspi_writel(q, q->devtype_data->ahb_buf_size * 2 + addr_offset,
+ qspi_writel(q, memsize_cs * 2 + addr_offset,
base + QUADSPI_SFA2AD);
- qspi_writel(q, q->devtype_data->ahb_buf_size * 3 + addr_offset,
- base + QUADSPI_SFB1AD);
- qspi_writel(q, q->devtype_data->ahb_buf_size * 4 + addr_offset,
- base + QUADSPI_SFB2AD);
+ if (!needs_single_bus(q)) {
+ qspi_writel(q, memsize_cs * 3 + addr_offset,
+ base + QUADSPI_SFB1AD);
+ qspi_writel(q, memsize_cs * 4 + addr_offset,
+ base + QUADSPI_SFB2AD);
+ }
q->selected = -1;
@@ -750,6 +824,7 @@ static int fsl_qspi_probe(struct udevice *bus)
q->ahb_addr = map_physmem(res.start, res.end - res.start, MAP_NOCACHE);
q->memmap_phy = res.start;
+ q->memmap_size = res.end - res.start;
dm_bus->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency",
66000000);
@@ -799,6 +874,7 @@ static const struct udevice_id fsl_qspi_ids[] = {
{ .compatible = "fsl,imx6sx-qspi", .data = (ulong)&imx6sx_data, },
{ .compatible = "fsl,imx6ul-qspi", .data = (ulong)&imx6ul_data, },
{ .compatible = "fsl,imx7d-qspi", .data = (ulong)&imx7d_data, },
+ { .compatible = "fsl,imx7ulp-qspi", .data = (ulong)&imx7ulp_data, },
{ .compatible = "fsl,ls1021a-qspi", .data = (ulong)&ls1021a_data, },
{ .compatible = "fsl,ls1088a-qspi", .data = (ulong)&ls1088a_data, },
{ .compatible = "fsl,ls2080a-qspi", .data = (ulong)&ls2080a_data, },
diff --git a/drivers/watchdog/imx_watchdog.c b/drivers/watchdog/imx_watchdog.c
index 01762df..b90c2da 100644
--- a/drivers/watchdog/imx_watchdog.c
+++ b/drivers/watchdog/imx_watchdog.c
@@ -16,6 +16,10 @@
#include <asm/arch/immap_lsch2.h>
#endif
#include <fsl_wdog.h>
+#include <div64.h>
+
+#define TIMEOUT_MAX 128000
+#define TIMEOUT_MIN 500
static void imx_watchdog_expire_now(struct watchdog_regs *wdog, bool ext_reset)
{
@@ -57,9 +61,9 @@ static void imx_watchdog_reset(struct watchdog_regs *wdog)
#endif /* CONFIG_WATCHDOG_RESET_DISABLE*/
}
-static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset)
+static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset,
+ u64 timeout)
{
- u16 timeout;
u16 wcr;
/*
@@ -70,7 +74,11 @@ static void imx_watchdog_init(struct watchdog_regs *wdog, bool ext_reset)
#ifndef CONFIG_WATCHDOG_TIMEOUT_MSECS
#define CONFIG_WATCHDOG_TIMEOUT_MSECS 128000
#endif
- timeout = (CONFIG_WATCHDOG_TIMEOUT_MSECS / 500) - 1;
+
+ timeout = max_t(u64, timeout, TIMEOUT_MIN);
+ timeout = min_t(u64, timeout, TIMEOUT_MAX);
+ timeout = lldiv(timeout, 500) - 1;
+
#ifdef CONFIG_FSL_LSCH2
wcr = (WCR_WDA | WCR_SRS | WCR_WDE) << 8 | timeout;
#else
@@ -95,7 +103,7 @@ void hw_watchdog_init(void)
{
struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;
- imx_watchdog_init(wdog, true);
+ imx_watchdog_init(wdog, true, CONFIG_WATCHDOG_TIMEOUT_MSECS);
}
#else
struct imx_wdt_priv {
@@ -126,7 +134,7 @@ static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
{
struct imx_wdt_priv *priv = dev_get_priv(dev);
- imx_watchdog_init(priv->base, priv->ext_reset);
+ imx_watchdog_init(priv->base, priv->ext_reset, timeout);
return 0;
}