diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/imx/clk-imx8mm.c | 63 | ||||
-rw-r--r-- | drivers/clk/imx/clk-imx8mn.c | 108 | ||||
-rw-r--r-- | drivers/clk/imx/clk-imx8mp.c | 52 | ||||
-rw-r--r-- | drivers/ddr/imx/imx8m/Kconfig | 7 | ||||
-rw-r--r-- | drivers/ddr/imx/imx8m/ddr_init.c | 79 | ||||
-rw-r--r-- | drivers/ddr/imx/imx8m/ddrphy_train.c | 7 | ||||
-rw-r--r-- | drivers/ddr/imx/imx8m/ddrphy_utils.c | 164 | ||||
-rw-r--r-- | drivers/gpio/mxc_gpio.c | 36 | ||||
-rw-r--r-- | drivers/misc/imx8/fuse.c | 19 | ||||
-rw-r--r-- | drivers/misc/imx8/scu_api.c | 25 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-imx5.c | 2 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-imx7.c | 2 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-imx8m.c | 2 | ||||
-rw-r--r-- | drivers/power/domain/imx8m-power-domain.c | 10 | ||||
-rw-r--r-- | drivers/power/pmic/pmic_pca9450.c | 21 | ||||
-rw-r--r-- | drivers/spi/Kconfig | 8 | ||||
-rw-r--r-- | drivers/spi/fsl_qspi.c | 122 | ||||
-rw-r--r-- | drivers/watchdog/imx_watchdog.c | 18 |
18 files changed, 586 insertions, 159 deletions
diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 66c9601b0c..d32ff8409a 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 2d8e373131..e29d902544 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 124138cf51..c77500bcce 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 5bf61eb258..a5f5524fbe 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 bbddee6ca8..99a67edfb0 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 f2a997b50a..08fed6178f 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 d5eef53573..20ae47bfb5 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 316dcc757b..90d36fb87b 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 4d7f2f524d..be18122937 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 3e38edbf5d..20b74fbb18 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 5d17380919..9c3423bef3 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 769d428dda..66b58ba472 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 5b7cbb69ae..0626fde58f 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 5b6467cda7..0ef460df8c 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 67a9090200..d4f27428bd 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 3a8add98f7..30d808d7bb 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 e715f9838f..eec968e5ec 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 01762df019..b90c2daece 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; } |