diff options
author | Tom Rini <trini@konsulko.com> | 2019-11-12 07:18:23 -0500 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-11-12 07:18:23 -0500 |
commit | 5f7ff6d63eeb81ad2c071ff5f5adae5bcc94f7a4 (patch) | |
tree | eb3707f7e5b4ae1d0f3094cc8814ef8bc389aa8c /drivers | |
parent | a965a8b904093c9e6790d0460d18a144cefa5e42 (diff) | |
parent | bdcf3a88cc582ce8bb9ea024fa917d9a52e05479 (diff) | |
download | u-boot-5f7ff6d63eeb81ad2c071ff5f5adae5bcc94f7a4.tar.gz |
Merge tag 'u-boot-imx-20191105' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
u-boot-imx-20191105
-------------------
i.MX8MN SoC support
ROM API image download support
i.MX8MM enet enabling
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/imx/Kconfig | 16 | ||||
-rw-r--r-- | drivers/clk/imx/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/imx/clk-imx8mm.c | 46 | ||||
-rw-r--r-- | drivers/clk/imx/clk-imx8mn.c | 415 | ||||
-rw-r--r-- | drivers/misc/imx8/scu.c | 46 | ||||
-rw-r--r-- | drivers/net/Kconfig | 2 | ||||
-rw-r--r-- | drivers/net/fec_mxc.c | 79 | ||||
-rw-r--r-- | drivers/net/fec_mxc.h | 4 | ||||
-rw-r--r-- | drivers/pinctrl/nxp/pinctrl-imx8m.c | 1 | ||||
-rw-r--r-- | drivers/power/domain/Makefile | 2 | ||||
-rw-r--r-- | drivers/power/domain/imx8-power-domain-legacy.c | 315 | ||||
-rw-r--r-- | drivers/power/domain/imx8-power-domain.c | 270 |
12 files changed, 893 insertions, 305 deletions
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index aae69cf9b0..0ba8bc9f63 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -36,3 +36,19 @@ config CLK_IMX8MM select CLK_CCF help This enables support clock driver for i.MX8MM platforms. + +config SPL_CLK_IMX8MN + bool "SPL clock support for i.MX8MN" + depends on ARCH_IMX8M && SPL + select SPL_CLK + select SPL_CLK_CCF + help + This enables SPL DM/DTS support for clock driver in i.MX8MN + +config CLK_IMX8MN + bool "Clock support for i.MX8MN" + depends on ARCH_IMX8M + select CLK + select CLK_CCF + help + This enables support clock driver for i.MX8MN platforms. diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 5ad7967fe9..222c5a4e08 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -12,3 +12,5 @@ obj-$(CONFIG_IMX8QM) += clk-imx8qm.o endif obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += clk-imx8mm.o clk-pll14xx.o \ clk-composite-8m.o +obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ + clk-composite-8m.o diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index f4913e70ab..091b092bbb 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -80,6 +80,17 @@ static const char *imx8mm_ahb_sels[] = {"osc_24m", "sys_pll1_133m", "sys_pll1_80 static const char *imx8mm_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 *imx8mm_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 *imx8mm_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 *imx8mm_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 *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", }; @@ -164,11 +175,30 @@ static int imx8mm_clk_enable(struct clk *clk) return __imx8mm_clk_enable(clk, 1); } +static int imx8mm_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; + + return clk_set_parent(c, cp); +} + static struct clk_ops imx8mm_clk_ops = { .set_rate = imx8mm_clk_set_rate, .get_rate = imx8mm_clk_get_rate, .enable = imx8mm_clk_enable, .disable = imx8mm_clk_disable, + .set_parent = imx8mm_clk_set_parent, }; static int imx8mm_clk_probe(struct udevice *dev) @@ -363,6 +393,22 @@ static int imx8mm_clk_probe(struct udevice *dev) clk_dm(IMX8MM_CLK_USDHC3_ROOT, imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0)); + /* clks not needed in SPL stage */ +#ifndef CONFIG_SPL_BUILD + clk_dm(IMX8MM_CLK_ENET_REF, + imx8m_clk_composite("enet_ref", imx8mm_enet_ref_sels, + base + 0xa980)); + clk_dm(IMX8MM_CLK_ENET_TIMER, + imx8m_clk_composite("enet_timer", imx8mm_enet_timer_sels, + base + 0xaa00)); + clk_dm(IMX8MM_CLK_ENET_PHY_REF, + imx8m_clk_composite("enet_phy", imx8mm_enet_phy_sels, + base + 0xaa80)); + clk_dm(IMX8MM_CLK_ENET1_ROOT, + imx_clk_gate4("enet1_root_clk", "enet_axi", + base + 0x40a0, 0)); +#endif + #ifdef CONFIG_SPL_BUILD struct clk *clkp, *clkp1; diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c new file mode 100644 index 0000000000..4048cc63cc --- /dev/null +++ b/drivers/clk/imx/clk-imx8mn.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP + * Peng Fan <peng.fan@nxp.com> + */ + +#include <common.h> +#include <clk.h> +#include <clk-uclass.h> +#include <dm.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <dt-bindings/clock/imx8mn-clock.h> + +#include "clk.h" + +#define PLL_1416X_RATE(_rate, _m, _p, _s) \ + { \ + .rate = (_rate), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + } + +#define PLL_1443X_RATE(_rate, _m, _p, _s, _k) \ + { \ + .rate = (_rate), \ + .mdiv = (_m), \ + .pdiv = (_p), \ + .sdiv = (_s), \ + .kdiv = (_k), \ + } + +static const struct imx_pll14xx_rate_table imx8mn_pll1416x_tbl[] = { + PLL_1416X_RATE(1800000000U, 225, 3, 0), + PLL_1416X_RATE(1600000000U, 200, 3, 0), + PLL_1416X_RATE(1200000000U, 300, 3, 1), + PLL_1416X_RATE(1000000000U, 250, 3, 1), + PLL_1416X_RATE(800000000U, 200, 3, 1), + PLL_1416X_RATE(750000000U, 250, 2, 2), + PLL_1416X_RATE(700000000U, 350, 3, 2), + PLL_1416X_RATE(600000000U, 300, 3, 2), +}; + +static const struct imx_pll14xx_rate_table imx8mn_drampll_tbl[] = { + PLL_1443X_RATE(650000000U, 325, 3, 2, 0), +}; + +static struct imx_pll14xx_clk imx8mn_dram_pll __initdata = { + .type = PLL_1443X, + .rate_table = imx8mn_drampll_tbl, + .rate_count = ARRAY_SIZE(imx8mn_drampll_tbl), +}; + +static struct imx_pll14xx_clk imx8mn_arm_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx8mn_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx8mn_pll1416x_tbl), +}; + +static struct imx_pll14xx_clk imx8mn_sys_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx8mn_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx8mn_pll1416x_tbl), +}; + +static const char *pll_ref_sels[] = { "clock-osc-24m", "dummy", "dummy", "dummy", }; +static const char *dram_pll_bypass_sels[] = {"dram_pll", "dram_pll_ref_sel", }; +static const char *arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *sys_pll1_bypass_sels[] = {"sys_pll1", "sys_pll1_ref_sel", }; +static const char *sys_pll2_bypass_sels[] = {"sys_pll2", "sys_pll2_ref_sel", }; +static const char *sys_pll3_bypass_sels[] = {"sys_pll3", "sys_pll3_ref_sel", }; + +static const char *imx8mn_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll2_500m", "sys_pll2_1000m", + "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", }; + +static const char *imx8mn_ahb_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_800m", "sys_pll1_400m", + "sys_pll2_125m", "sys_pll3_out", "audio_pll1_out", "video_pll1_out", }; + +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", }; + +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 *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", }; + +static const char *imx8mn_usdhc2_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 *imx8mn_i2c1_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mn_i2c2_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mn_i2c3_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mn_i2c4_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_pll2_50m", "sys_pll3_out", "audio_pll1_out", + "video_pll1_out", "audio_pll2_out", "sys_pll1_133m", }; + +static const char *imx8mn_wdog_sels[] = {"clock-osc-24m", "sys_pll1_133m", "sys_pll1_160m", "vpu_pll_out", + "sys_pll2_125m", "sys_pll3_out", "sys_pll1_80m", "sys_pll2_166m", }; + +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 ulong imx8mn_clk_get_rate(struct clk *clk) +{ + struct clk *c; + int ret; + + debug("%s(#%lu)\n", __func__, clk->id); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + return clk_get_rate(c); +} + +static ulong imx8mn_clk_set_rate(struct clk *clk, unsigned long rate) +{ + struct clk *c; + int ret; + + debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + return clk_set_rate(c, rate); +} + +static int __imx8mn_clk_enable(struct clk *clk, bool enable) +{ + struct clk *c; + int ret; + + debug("%s(#%lu) en: %d\n", __func__, clk->id, enable); + + ret = clk_get_by_id(clk->id, &c); + if (ret) + return ret; + + if (enable) + ret = clk_enable(c); + else + ret = clk_disable(c); + + return ret; +} + +static int imx8mn_clk_disable(struct clk *clk) +{ + return __imx8mn_clk_enable(clk, 0); +} + +static int imx8mn_clk_enable(struct clk *clk) +{ + return __imx8mn_clk_enable(clk, 1); +} + +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, +}; + +static int imx8mn_clk_probe(struct udevice *dev) +{ + void __iomem *base; + + base = (void *)ANATOP_BASE_ADDR; + + clk_dm(IMX8MN_DRAM_PLL_REF_SEL, + imx_clk_mux("dram_pll_ref_sel", base + 0x50, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MN_ARM_PLL_REF_SEL, + imx_clk_mux("arm_pll_ref_sel", base + 0x84, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MN_SYS_PLL1_REF_SEL, + imx_clk_mux("sys_pll1_ref_sel", base + 0x94, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MN_SYS_PLL2_REF_SEL, + imx_clk_mux("sys_pll2_ref_sel", base + 0x104, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MN_SYS_PLL3_REF_SEL, + imx_clk_mux("sys_pll3_ref_sel", base + 0x114, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + + clk_dm(IMX8MN_DRAM_PLL, + imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", + base + 0x50, &imx8mn_dram_pll)); + clk_dm(IMX8MN_ARM_PLL, + imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", + base + 0x84, &imx8mn_arm_pll)); + clk_dm(IMX8MN_SYS_PLL1, + imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", + base + 0x94, &imx8mn_sys_pll)); + clk_dm(IMX8MN_SYS_PLL2, + imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", + base + 0x104, &imx8mn_sys_pll)); + clk_dm(IMX8MN_SYS_PLL3, + imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", + base + 0x114, &imx8mn_sys_pll)); + + /* PLL bypass out */ + clk_dm(IMX8MN_DRAM_PLL_BYPASS, + imx_clk_mux_flags("dram_pll_bypass", base + 0x50, 4, 1, + dram_pll_bypass_sels, + ARRAY_SIZE(dram_pll_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MN_ARM_PLL_BYPASS, + imx_clk_mux_flags("arm_pll_bypass", base + 0x84, 4, 1, + arm_pll_bypass_sels, + ARRAY_SIZE(arm_pll_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MN_SYS_PLL1_BYPASS, + imx_clk_mux_flags("sys_pll1_bypass", base + 0x94, 4, 1, + sys_pll1_bypass_sels, + ARRAY_SIZE(sys_pll1_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MN_SYS_PLL2_BYPASS, + imx_clk_mux_flags("sys_pll2_bypass", base + 0x104, 4, 1, + sys_pll2_bypass_sels, + ARRAY_SIZE(sys_pll2_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MN_SYS_PLL3_BYPASS, + imx_clk_mux_flags("sys_pll3_bypass", base + 0x114, 4, 1, + sys_pll3_bypass_sels, + ARRAY_SIZE(sys_pll3_bypass_sels), + CLK_SET_RATE_PARENT)); + + /* PLL out gate */ + clk_dm(IMX8MN_DRAM_PLL_OUT, + imx_clk_gate("dram_pll_out", "dram_pll_bypass", + base + 0x50, 13)); + clk_dm(IMX8MN_ARM_PLL_OUT, + imx_clk_gate("arm_pll_out", "arm_pll_bypass", + base + 0x84, 11)); + clk_dm(IMX8MN_SYS_PLL1_OUT, + imx_clk_gate("sys_pll1_out", "sys_pll1_bypass", + base + 0x94, 11)); + clk_dm(IMX8MN_SYS_PLL2_OUT, + imx_clk_gate("sys_pll2_out", "sys_pll2_bypass", + base + 0x104, 11)); + clk_dm(IMX8MN_SYS_PLL3_OUT, + imx_clk_gate("sys_pll3_out", "sys_pll3_bypass", + base + 0x114, 11)); + + /* SYS PLL fixed output */ + clk_dm(IMX8MN_SYS_PLL1_40M, + imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20)); + clk_dm(IMX8MN_SYS_PLL1_80M, + imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10)); + clk_dm(IMX8MN_SYS_PLL1_100M, + imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8)); + clk_dm(IMX8MN_SYS_PLL1_133M, + imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6)); + clk_dm(IMX8MN_SYS_PLL1_160M, + imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5)); + clk_dm(IMX8MN_SYS_PLL1_200M, + imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4)); + clk_dm(IMX8MN_SYS_PLL1_266M, + imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3)); + clk_dm(IMX8MN_SYS_PLL1_400M, + imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2)); + clk_dm(IMX8MN_SYS_PLL1_800M, + imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1)); + + clk_dm(IMX8MN_SYS_PLL2_50M, + imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20)); + clk_dm(IMX8MN_SYS_PLL2_100M, + imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10)); + clk_dm(IMX8MN_SYS_PLL2_125M, + imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8)); + clk_dm(IMX8MN_SYS_PLL2_166M, + imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6)); + clk_dm(IMX8MN_SYS_PLL2_200M, + imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5)); + clk_dm(IMX8MN_SYS_PLL2_250M, + imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4)); + clk_dm(IMX8MN_SYS_PLL2_333M, + imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3)); + clk_dm(IMX8MN_SYS_PLL2_500M, + imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2)); + clk_dm(IMX8MN_SYS_PLL2_1000M, + imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1)); + + base = dev_read_addr_ptr(dev); + if (base == (void *)FDT_ADDR_T_NONE) + return -EINVAL; + + clk_dm(IMX8MN_CLK_A53_SRC, + imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, + imx8mn_a53_sels, ARRAY_SIZE(imx8mn_a53_sels))); + clk_dm(IMX8MN_CLK_A53_CG, + imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28)); + clk_dm(IMX8MN_CLK_A53_DIV, + imx_clk_divider2("arm_a53_div", "arm_a53_cg", + base + 0x8000, 0, 3)); + + clk_dm(IMX8MN_CLK_AHB, + imx8m_clk_composite_critical("ahb", imx8mn_ahb_sels, + base + 0x9000)); + clk_dm(IMX8MN_CLK_IPG_ROOT, + imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1)); + + clk_dm(IMX8MN_CLK_ENET_AXI, + imx8m_clk_composite("enet_axi", imx8mn_enet_axi_sels, + base + 0x8880)); + clk_dm(IMX8MN_CLK_NAND_USDHC_BUS, + imx8m_clk_composite_critical("nand_usdhc_bus", + imx8mn_nand_usdhc_sels, + base + 0x8900)); + + /* IP */ + clk_dm(IMX8MN_CLK_USDHC1, + imx8m_clk_composite("usdhc1", imx8mn_usdhc1_sels, + base + 0xac00)); + clk_dm(IMX8MN_CLK_USDHC2, + imx8m_clk_composite("usdhc2", imx8mn_usdhc2_sels, + base + 0xac80)); + clk_dm(IMX8MN_CLK_I2C1, + imx8m_clk_composite("i2c1", imx8mn_i2c1_sels, base + 0xad00)); + clk_dm(IMX8MN_CLK_I2C2, + imx8m_clk_composite("i2c2", imx8mn_i2c2_sels, base + 0xad80)); + clk_dm(IMX8MN_CLK_I2C3, + imx8m_clk_composite("i2c3", imx8mn_i2c3_sels, base + 0xae00)); + clk_dm(IMX8MN_CLK_I2C4, + imx8m_clk_composite("i2c4", imx8mn_i2c4_sels, base + 0xae80)); + clk_dm(IMX8MN_CLK_WDOG, + imx8m_clk_composite("wdog", imx8mn_wdog_sels, base + 0xb900)); + clk_dm(IMX8MN_CLK_USDHC3, + imx8m_clk_composite("usdhc3", imx8mn_usdhc3_sels, + base + 0xbc80)); + + clk_dm(IMX8MN_CLK_I2C1_ROOT, + imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0)); + clk_dm(IMX8MN_CLK_I2C2_ROOT, + imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0)); + clk_dm(IMX8MN_CLK_I2C3_ROOT, + imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0)); + clk_dm(IMX8MN_CLK_I2C4_ROOT, + imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0)); + clk_dm(IMX8MN_CLK_OCOTP_ROOT, + imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0)); + clk_dm(IMX8MN_CLK_USDHC1_ROOT, + imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0)); + clk_dm(IMX8MN_CLK_USDHC2_ROOT, + imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0)); + clk_dm(IMX8MN_CLK_WDOG1_ROOT, + imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0)); + clk_dm(IMX8MN_CLK_WDOG2_ROOT, + imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0)); + clk_dm(IMX8MN_CLK_WDOG3_ROOT, + 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); +#endif + + return 0; +} + +static const struct udevice_id imx8mn_clk_ids[] = { + { .compatible = "fsl,imx8mn-ccm" }, + { }, +}; + +U_BOOT_DRIVER(imx8mn_clk) = { + .name = "clk_imx8mn", + .id = UCLASS_CLK, + .of_match = imx8mn_clk_ids, + .ops = &imx8mn_clk_ops, + .probe = imx8mn_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/misc/imx8/scu.c b/drivers/misc/imx8/scu.c index 9ec00457b8..a7654a7817 100644 --- a/drivers/misc/imx8/scu.c +++ b/drivers/misc/imx8/scu.c @@ -26,8 +26,6 @@ struct mu_type { struct imx8_scu { struct mu_type *base; - struct udevice *clk; - struct udevice *pinclk; }; #define MU_CR_GIE_MASK 0xF0000000u @@ -202,9 +200,6 @@ static int imx8_scu_probe(struct udevice *dev) gd->arch.scu_dev = dev; - device_probe(plat->clk); - device_probe(plat->pinclk); - return 0; } @@ -215,44 +210,17 @@ static int imx8_scu_remove(struct udevice *dev) static int imx8_scu_bind(struct udevice *dev) { - struct imx8_scu *plat = dev_get_platdata(dev); int ret; struct udevice *child; - int node; - char *clk_compatible, *iomuxc_compatible; - - if (IS_ENABLED(CONFIG_IMX8QXP)) { - clk_compatible = "fsl,imx8qxp-clk"; - iomuxc_compatible = "fsl,imx8qxp-iomuxc"; - } else if (IS_ENABLED(CONFIG_IMX8QM)) { - clk_compatible = "fsl,imx8qm-clk"; - iomuxc_compatible = "fsl,imx8qm-iomuxc"; - } else { - return -EINVAL; - } + ofnode node; debug("%s(dev=%p)\n", __func__, dev); - - node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, clk_compatible); - if (node < 0) - panic("No clk node found\n"); - - ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child, true); - if (ret) - return ret; - - plat->clk = child; - - node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, - iomuxc_compatible); - if (node < 0) - panic("No iomuxc node found\n"); - - ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child, true); - if (ret) - return ret; - - plat->pinclk = child; + ofnode_for_each_subnode(node, dev_ofnode(dev)) { + ret = lists_bind_fdt(dev, node, &child, true); + if (ret) + return ret; + debug("bind child dev %s\n", child->name); + } return 0; } diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index eb3d7ed45f..4182897d89 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -236,7 +236,7 @@ config FEC_MXC_MDIO_BASE config FEC_MXC bool "FEC Ethernet controller" - depends on MX28 || MX5 || MX6 || MX7 || IMX8 || VF610 + depends on MX28 || MX5 || MX6 || MX7 || IMX8 || IMX8M || VF610 help This driver supports the 10/100 Fast Ethernet controller for NXP i.MX processors. diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index 080dbcf7db..131d1998a7 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -123,30 +123,38 @@ static int fec_mdio_read(struct ethernet_regs *eth, uint8_t phyaddr, return val; } +#ifndef imx_get_fecclk +u32 __weak imx_get_fecclk(void) +{ + return 0; +} +#endif + static int fec_get_clk_rate(void *udev, int idx) { -#if IS_ENABLED(CONFIG_IMX8) struct fec_priv *fec; struct udevice *dev; int ret; - dev = udev; - if (!dev) { - ret = uclass_get_device(UCLASS_ETH, idx, &dev); - if (ret < 0) { - debug("Can't get FEC udev: %d\n", ret); - return ret; + if (IS_ENABLED(CONFIG_IMX8) || + CONFIG_IS_ENABLED(CLK_CCF)) { + dev = udev; + if (!dev) { + ret = uclass_get_device(UCLASS_ETH, idx, &dev); + if (ret < 0) { + debug("Can't get FEC udev: %d\n", ret); + return ret; + } } - } - fec = dev_get_priv(dev); - if (fec) - return fec->clk_rate; + fec = dev_get_priv(dev); + if (fec) + return fec->clk_rate; - return -EINVAL; -#else - return imx_get_fecclk(); -#endif + return -EINVAL; + } else { + return imx_get_fecclk(); + } } static void fec_mii_setspeed(struct ethernet_regs *eth) @@ -1336,6 +1344,47 @@ static int fecmxc_probe(struct udevice *dev) } priv->clk_rate = clk_get_rate(&priv->ipg_clk); + } else if (CONFIG_IS_ENABLED(CLK_CCF)) { + ret = clk_get_by_name(dev, "ipg", &priv->ipg_clk); + if (ret < 0) { + debug("Can't get FEC ipg clk: %d\n", ret); + return ret; + } + ret = clk_enable(&priv->ipg_clk); + if(ret) + return ret; + + ret = clk_get_by_name(dev, "ahb", &priv->ahb_clk); + if (ret < 0) { + debug("Can't get FEC ahb clk: %d\n", ret); + return ret; + } + ret = clk_enable(&priv->ahb_clk); + if (ret) + return ret; + + ret = clk_get_by_name(dev, "enet_out", &priv->clk_enet_out); + if (!ret) { + ret = clk_enable(&priv->clk_enet_out); + if (ret) + return ret; + } + + ret = clk_get_by_name(dev, "enet_clk_ref", &priv->clk_ref); + if (!ret) { + ret = clk_enable(&priv->clk_ref); + if (ret) + return ret; + } + + ret = clk_get_by_name(dev, "ptp", &priv->clk_ptp); + if (!ret) { + ret = clk_enable(&priv->clk_ptp); + if (ret) + return ret; + } + + priv->clk_rate = clk_get_rate(&priv->ipg_clk); } ret = fec_alloc_descs(priv); diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h index e5f2dd75c5..723b06a651 100644 --- a/drivers/net/fec_mxc.h +++ b/drivers/net/fec_mxc.h @@ -264,6 +264,10 @@ struct fec_priv { u32 interface; #endif struct clk ipg_clk; + struct clk ahb_clk; + struct clk clk_enet_out; + struct clk clk_ref; + struct clk clk_ptp; u32 clk_rate; }; diff --git a/drivers/pinctrl/nxp/pinctrl-imx8m.c b/drivers/pinctrl/nxp/pinctrl-imx8m.c index 8bb03b7a62..b3844314b3 100644 --- a/drivers/pinctrl/nxp/pinctrl-imx8m.c +++ b/drivers/pinctrl/nxp/pinctrl-imx8m.c @@ -21,6 +21,7 @@ static int imx8mq_pinctrl_probe(struct udevice *dev) static const struct udevice_id imx8m_pinctrl_match[] = { { .compatible = "fsl,imx8mq-iomuxc", .data = (ulong)&imx8mq_pinctrl_soc_info }, { .compatible = "fsl,imx8mm-iomuxc", .data = (ulong)&imx8mq_pinctrl_soc_info }, + { .compatible = "fsl,imx8mn-iomuxc", .data = (ulong)&imx8mq_pinctrl_soc_info }, { /* sentinel */ } }; diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile index d0dce14a08..45bf9f6383 100644 --- a/drivers/power/domain/Makefile +++ b/drivers/power/domain/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_$(SPL_)POWER_DOMAIN) += power-domain-uclass.o obj-$(CONFIG_BCM6328_POWER_DOMAIN) += bcm6328-power-domain.o -obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain.o +obj-$(CONFIG_IMX8_POWER_DOMAIN) += imx8-power-domain-legacy.o imx8-power-domain.o obj-$(CONFIG_IMX8M_POWER_DOMAIN) += imx8m-power-domain.o obj-$(CONFIG_MTK_POWER_DOMAIN) += mtk-power-domain.o obj-$(CONFIG_MESON_GX_VPU_POWER_DOMAIN) += meson-gx-pwrc-vpu.o diff --git a/drivers/power/domain/imx8-power-domain-legacy.c b/drivers/power/domain/imx8-power-domain-legacy.c new file mode 100644 index 0000000000..d51dbaa6c0 --- /dev/null +++ b/drivers/power/domain/imx8-power-domain-legacy.c @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2017 NXP + */ + +#include <common.h> +#include <dm.h> +#include <power-domain-uclass.h> +#include <asm/io.h> +#include <asm/arch/power-domain.h> +#include <dm/device-internal.h> +#include <dm/device.h> +#include <asm/arch/sci/sci.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct imx8_power_domain_priv { + bool state_on; +}; + +static int imx8_power_domain_request(struct power_domain *power_domain) +{ + debug("%s(power_domain=%p)\n", __func__, power_domain); + + return 0; +} + +static int imx8_power_domain_free(struct power_domain *power_domain) +{ + debug("%s(power_domain=%p)\n", __func__, power_domain); + + return 0; +} + +static int imx8_power_domain_on(struct power_domain *power_domain) +{ + struct udevice *dev = power_domain->dev; + struct imx8_power_domain_platdata *pdata; + struct imx8_power_domain_priv *ppriv; + sc_err_t ret; + int err; + + struct power_domain parent_domain; + struct udevice *parent = dev_get_parent(dev); + + /* Need to power on parent node first */ + if (device_get_uclass_id(parent) == UCLASS_POWER_DOMAIN) { + parent_domain.dev = parent; + err = imx8_power_domain_on(&parent_domain); + if (err) + return err; + } + + pdata = (struct imx8_power_domain_platdata *)dev_get_platdata(dev); + ppriv = (struct imx8_power_domain_priv *)dev_get_priv(dev); + + debug("%s(power_domain=%s) resource_id %d\n", __func__, dev->name, + pdata->resource_id); + + /* Already powered on */ + if (ppriv->state_on) + return 0; + + if (pdata->resource_id != SC_R_LAST) { + ret = sc_pm_set_resource_power_mode(-1, pdata->resource_id, + SC_PM_PW_MODE_ON); + if (ret) { + printf("Error: %s Power up failed! (error = %d)\n", + dev->name, ret); + return -EIO; + } + } + + ppriv->state_on = true; + debug("%s is powered on\n", dev->name); + + return 0; +} + +static int imx8_power_domain_off_node(struct power_domain *power_domain) +{ + struct udevice *dev = power_domain->dev; + struct udevice *child; + struct imx8_power_domain_priv *ppriv; + struct imx8_power_domain_priv *child_ppriv; + struct imx8_power_domain_platdata *pdata; + sc_err_t ret; + + ppriv = dev_get_priv(dev); + pdata = dev_get_platdata(dev); + + debug("%s, %s, state_on %d\n", __func__, dev->name, ppriv->state_on); + + /* Already powered off */ + if (!ppriv->state_on) + return 0; + + /* Check if all subnodes are off */ + for (device_find_first_child(dev, &child); + child; + device_find_next_child(&child)) { + if (device_active(child)) { + child_ppriv = + (struct imx8_power_domain_priv *)dev_get_priv(child); + if (child_ppriv->state_on) + return -EPERM; + } + } + + if (pdata->resource_id != SC_R_LAST) { + if (!sc_rm_is_resource_owned(-1, pdata->resource_id)) { + printf("%s not owned by curr partition\n", dev->name); + return 0; + } + ret = sc_pm_set_resource_power_mode(-1, pdata->resource_id, + SC_PM_PW_MODE_OFF); + if (ret) { + printf("Error: %s Power off failed! (error = %d)\n", + dev->name, ret); + return -EIO; + } + } + + ppriv->state_on = false; + debug("%s is powered off\n", dev->name); + + return 0; +} + +static int imx8_power_domain_off_parentnodes(struct power_domain *power_domain) +{ + struct udevice *dev = power_domain->dev; + struct udevice *parent = dev_get_parent(dev); + struct udevice *child; + struct imx8_power_domain_priv *ppriv; + struct imx8_power_domain_priv *child_ppriv; + struct imx8_power_domain_platdata *pdata; + sc_err_t ret; + struct power_domain parent_pd; + + if (device_get_uclass_id(parent) == UCLASS_POWER_DOMAIN) { + pdata = + (struct imx8_power_domain_platdata *)dev_get_platdata(parent); + ppriv = (struct imx8_power_domain_priv *)dev_get_priv(parent); + + debug("%s, %s, state_on %d\n", __func__, parent->name, + ppriv->state_on); + + /* Already powered off */ + if (!ppriv->state_on) + return 0; + + /* + * Check if all sibling nodes are off. If yes, + * power off parent + */ + for (device_find_first_child(parent, &child); child; + device_find_next_child(&child)) { + if (device_active(child)) { + child_ppriv = (struct imx8_power_domain_priv *) + dev_get_priv(child); + /* Find a power on sibling */ + if (child_ppriv->state_on) { + debug("sibling %s, state_on %d\n", + child->name, + child_ppriv->state_on); + return 0; + } + } + } + + /* power off parent */ + if (pdata->resource_id != SC_R_LAST) { + ret = sc_pm_set_resource_power_mode(-1, + pdata->resource_id, + SC_PM_PW_MODE_OFF); + if (ret) { + printf("%s Power off failed! (error = %d)\n", + parent->name, ret); + return -EIO; + } + } + + ppriv->state_on = false; + debug("%s is powered off\n", parent->name); + + parent_pd.dev = parent; + imx8_power_domain_off_parentnodes(&parent_pd); + } + + return 0; +} + +static int imx8_power_domain_off(struct power_domain *power_domain) +{ + int ret; + + debug("%s(power_domain=%p)\n", __func__, power_domain); + + /* Turn off the node */ + ret = imx8_power_domain_off_node(power_domain); + if (ret) { + debug("Can't power off the node of dev %s, ret = %d\n", + power_domain->dev->name, ret); + return ret; + } + + /* Turn off parent nodes, if sibling nodes are all off */ + ret = imx8_power_domain_off_parentnodes(power_domain); + if (ret) { + printf("Failed to power off parent nodes of dev %s, ret = %d\n", + power_domain->dev->name, ret); + return ret; + } + + return 0; +} + +static int imx8_power_domain_of_xlate(struct power_domain *power_domain, + struct ofnode_phandle_args *args) +{ + debug("%s(power_domain=%p)\n", __func__, power_domain); + + /* Do nothing to the xlate, since we don't have args used */ + + return 0; +} + +static int imx8_power_domain_bind(struct udevice *dev) +{ + int offset; + const char *name; + int ret = 0; + + debug("%s(dev=%p)\n", __func__, dev); + + offset = dev_of_offset(dev); + for (offset = fdt_first_subnode(gd->fdt_blob, offset); offset > 0; + offset = fdt_next_subnode(gd->fdt_blob, offset)) { + /* Bind the subnode to this driver */ + name = fdt_get_name(gd->fdt_blob, offset, NULL); + + ret = device_bind_with_driver_data(dev, dev->driver, name, + dev->driver_data, + offset_to_ofnode(offset), + NULL); + + if (ret == -ENODEV) + printf("Driver '%s' refuses to bind\n", + dev->driver->name); + + if (ret) + printf("Error binding driver '%s': %d\n", + dev->driver->name, ret); + } + + return 0; +} + +static int imx8_power_domain_probe(struct udevice *dev) +{ + struct imx8_power_domain_priv *ppriv; + + debug("%s(dev=%s)\n", __func__, dev->name); + + ppriv = (struct imx8_power_domain_priv *)dev_get_priv(dev); + + /* Set default to power off */ + if (ppriv) + ppriv->state_on = false; + + return 0; +} + +static int imx8_power_domain_ofdata_to_platdata(struct udevice *dev) +{ + int reg; + struct imx8_power_domain_platdata *pdata = dev_get_platdata(dev); + + reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1); + if (reg == -1) { + debug("%s: Invalid resource id %d\n", __func__, reg); + return -EINVAL; + } + pdata->resource_id = (sc_rsrc_t)reg; + + debug("%s resource_id %d\n", __func__, pdata->resource_id); + + return 0; +} + +static const struct udevice_id imx8_power_domain_ids[] = { + { .compatible = "nxp,imx8-pd" }, + { } +}; + +struct power_domain_ops imx8_power_domain_ops = { + .request = imx8_power_domain_request, + .free = imx8_power_domain_free, + .on = imx8_power_domain_on, + .off = imx8_power_domain_off, + .of_xlate = imx8_power_domain_of_xlate, +}; + +U_BOOT_DRIVER(imx8_power_domain) = { + .name = "imx8_power_domain", + .id = UCLASS_POWER_DOMAIN, + .of_match = imx8_power_domain_ids, + .bind = imx8_power_domain_bind, + .probe = imx8_power_domain_probe, + .ofdata_to_platdata = imx8_power_domain_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct imx8_power_domain_platdata), + .priv_auto_alloc_size = sizeof(struct imx8_power_domain_priv), + .ops = &imx8_power_domain_ops, +}; diff --git a/drivers/power/domain/imx8-power-domain.c b/drivers/power/domain/imx8-power-domain.c index d51dbaa6c0..aa768365b4 100644 --- a/drivers/power/domain/imx8-power-domain.c +++ b/drivers/power/domain/imx8-power-domain.c @@ -1,23 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2017 NXP + * Copyright 2019 NXP */ +#define DEBUG #include <common.h> #include <dm.h> #include <power-domain-uclass.h> -#include <asm/io.h> #include <asm/arch/power-domain.h> -#include <dm/device-internal.h> -#include <dm/device.h> #include <asm/arch/sci/sci.h> -DECLARE_GLOBAL_DATA_PTR; - -struct imx8_power_domain_priv { - bool state_on; -}; - static int imx8_power_domain_request(struct power_domain *power_domain) { debug("%s(power_domain=%p)\n", __func__, power_domain); @@ -34,158 +26,16 @@ static int imx8_power_domain_free(struct power_domain *power_domain) static int imx8_power_domain_on(struct power_domain *power_domain) { - struct udevice *dev = power_domain->dev; - struct imx8_power_domain_platdata *pdata; - struct imx8_power_domain_priv *ppriv; - sc_err_t ret; - int err; - - struct power_domain parent_domain; - struct udevice *parent = dev_get_parent(dev); - - /* Need to power on parent node first */ - if (device_get_uclass_id(parent) == UCLASS_POWER_DOMAIN) { - parent_domain.dev = parent; - err = imx8_power_domain_on(&parent_domain); - if (err) - return err; - } - - pdata = (struct imx8_power_domain_platdata *)dev_get_platdata(dev); - ppriv = (struct imx8_power_domain_priv *)dev_get_priv(dev); - - debug("%s(power_domain=%s) resource_id %d\n", __func__, dev->name, - pdata->resource_id); - - /* Already powered on */ - if (ppriv->state_on) - return 0; - - if (pdata->resource_id != SC_R_LAST) { - ret = sc_pm_set_resource_power_mode(-1, pdata->resource_id, - SC_PM_PW_MODE_ON); - if (ret) { - printf("Error: %s Power up failed! (error = %d)\n", - dev->name, ret); - return -EIO; - } - } - - ppriv->state_on = true; - debug("%s is powered on\n", dev->name); - - return 0; -} - -static int imx8_power_domain_off_node(struct power_domain *power_domain) -{ - struct udevice *dev = power_domain->dev; - struct udevice *child; - struct imx8_power_domain_priv *ppriv; - struct imx8_power_domain_priv *child_ppriv; - struct imx8_power_domain_platdata *pdata; - sc_err_t ret; - - ppriv = dev_get_priv(dev); - pdata = dev_get_platdata(dev); - - debug("%s, %s, state_on %d\n", __func__, dev->name, ppriv->state_on); - - /* Already powered off */ - if (!ppriv->state_on) - return 0; - - /* Check if all subnodes are off */ - for (device_find_first_child(dev, &child); - child; - device_find_next_child(&child)) { - if (device_active(child)) { - child_ppriv = - (struct imx8_power_domain_priv *)dev_get_priv(child); - if (child_ppriv->state_on) - return -EPERM; - } - } - - if (pdata->resource_id != SC_R_LAST) { - if (!sc_rm_is_resource_owned(-1, pdata->resource_id)) { - printf("%s not owned by curr partition\n", dev->name); - return 0; - } - ret = sc_pm_set_resource_power_mode(-1, pdata->resource_id, - SC_PM_PW_MODE_OFF); - if (ret) { - printf("Error: %s Power off failed! (error = %d)\n", - dev->name, ret); - return -EIO; - } - } - - ppriv->state_on = false; - debug("%s is powered off\n", dev->name); - - return 0; -} - -static int imx8_power_domain_off_parentnodes(struct power_domain *power_domain) -{ - struct udevice *dev = power_domain->dev; - struct udevice *parent = dev_get_parent(dev); - struct udevice *child; - struct imx8_power_domain_priv *ppriv; - struct imx8_power_domain_priv *child_ppriv; - struct imx8_power_domain_platdata *pdata; - sc_err_t ret; - struct power_domain parent_pd; - - if (device_get_uclass_id(parent) == UCLASS_POWER_DOMAIN) { - pdata = - (struct imx8_power_domain_platdata *)dev_get_platdata(parent); - ppriv = (struct imx8_power_domain_priv *)dev_get_priv(parent); - - debug("%s, %s, state_on %d\n", __func__, parent->name, - ppriv->state_on); - - /* Already powered off */ - if (!ppriv->state_on) - return 0; - - /* - * Check if all sibling nodes are off. If yes, - * power off parent - */ - for (device_find_first_child(parent, &child); child; - device_find_next_child(&child)) { - if (device_active(child)) { - child_ppriv = (struct imx8_power_domain_priv *) - dev_get_priv(child); - /* Find a power on sibling */ - if (child_ppriv->state_on) { - debug("sibling %s, state_on %d\n", - child->name, - child_ppriv->state_on); - return 0; - } - } - } - - /* power off parent */ - if (pdata->resource_id != SC_R_LAST) { - ret = sc_pm_set_resource_power_mode(-1, - pdata->resource_id, - SC_PM_PW_MODE_OFF); - if (ret) { - printf("%s Power off failed! (error = %d)\n", - parent->name, ret); - return -EIO; - } - } + u32 resource_id = power_domain->id; + int ret; - ppriv->state_on = false; - debug("%s is powered off\n", parent->name); + debug("%s: resource_id %u\n", __func__, resource_id); - parent_pd.dev = parent; - imx8_power_domain_off_parentnodes(&parent_pd); + ret = sc_pm_set_resource_power_mode(-1, resource_id, SC_PM_PW_MODE_ON); + if (ret) { + printf("Error: %u Power up failed! (error = %d)\n", + resource_id, ret); + return ret; } return 0; @@ -193,123 +43,45 @@ static int imx8_power_domain_off_parentnodes(struct power_domain *power_domain) static int imx8_power_domain_off(struct power_domain *power_domain) { + u32 resource_id = power_domain->id; int ret; - debug("%s(power_domain=%p)\n", __func__, power_domain); + debug("%s: resource_id %u\n", __func__, resource_id); - /* Turn off the node */ - ret = imx8_power_domain_off_node(power_domain); + ret = sc_pm_set_resource_power_mode(-1, resource_id, SC_PM_PW_MODE_OFF); if (ret) { - debug("Can't power off the node of dev %s, ret = %d\n", - power_domain->dev->name, ret); + printf("Error: %u Power off failed! (error = %d)\n", + resource_id, ret); return ret; } - /* Turn off parent nodes, if sibling nodes are all off */ - ret = imx8_power_domain_off_parentnodes(power_domain); - if (ret) { - printf("Failed to power off parent nodes of dev %s, ret = %d\n", - power_domain->dev->name, ret); - return ret; - } - - return 0; -} - -static int imx8_power_domain_of_xlate(struct power_domain *power_domain, - struct ofnode_phandle_args *args) -{ - debug("%s(power_domain=%p)\n", __func__, power_domain); - - /* Do nothing to the xlate, since we don't have args used */ - - return 0; -} - -static int imx8_power_domain_bind(struct udevice *dev) -{ - int offset; - const char *name; - int ret = 0; - - debug("%s(dev=%p)\n", __func__, dev); - - offset = dev_of_offset(dev); - for (offset = fdt_first_subnode(gd->fdt_blob, offset); offset > 0; - offset = fdt_next_subnode(gd->fdt_blob, offset)) { - /* Bind the subnode to this driver */ - name = fdt_get_name(gd->fdt_blob, offset, NULL); - - ret = device_bind_with_driver_data(dev, dev->driver, name, - dev->driver_data, - offset_to_ofnode(offset), - NULL); - - if (ret == -ENODEV) - printf("Driver '%s' refuses to bind\n", - dev->driver->name); - - if (ret) - printf("Error binding driver '%s': %d\n", - dev->driver->name, ret); - } - return 0; } static int imx8_power_domain_probe(struct udevice *dev) { - struct imx8_power_domain_priv *ppriv; - debug("%s(dev=%s)\n", __func__, dev->name); - ppriv = (struct imx8_power_domain_priv *)dev_get_priv(dev); - - /* Set default to power off */ - if (ppriv) - ppriv->state_on = false; - - return 0; -} - -static int imx8_power_domain_ofdata_to_platdata(struct udevice *dev) -{ - int reg; - struct imx8_power_domain_platdata *pdata = dev_get_platdata(dev); - - reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1); - if (reg == -1) { - debug("%s: Invalid resource id %d\n", __func__, reg); - return -EINVAL; - } - pdata->resource_id = (sc_rsrc_t)reg; - - debug("%s resource_id %d\n", __func__, pdata->resource_id); - return 0; } static const struct udevice_id imx8_power_domain_ids[] = { - { .compatible = "nxp,imx8-pd" }, + { .compatible = "fsl,imx8qxp-scu-pd" }, + { .compatible = "fsl,scu-pd" }, { } }; -struct power_domain_ops imx8_power_domain_ops = { +struct power_domain_ops imx8_power_domain_ops_v2 = { .request = imx8_power_domain_request, .free = imx8_power_domain_free, .on = imx8_power_domain_on, .off = imx8_power_domain_off, - .of_xlate = imx8_power_domain_of_xlate, }; -U_BOOT_DRIVER(imx8_power_domain) = { - .name = "imx8_power_domain", +U_BOOT_DRIVER(imx8_power_domain_v2) = { + .name = "imx8_power_domain_v2", .id = UCLASS_POWER_DOMAIN, .of_match = imx8_power_domain_ids, - .bind = imx8_power_domain_bind, .probe = imx8_power_domain_probe, - .ofdata_to_platdata = imx8_power_domain_ofdata_to_platdata, - .platdata_auto_alloc_size = sizeof(struct imx8_power_domain_platdata), - .priv_auto_alloc_size = sizeof(struct imx8_power_domain_priv), - .ops = &imx8_power_domain_ops, + .ops = &imx8_power_domain_ops_v2, }; |