diff options
Diffstat (limited to 'drivers')
38 files changed, 2266 insertions, 415 deletions
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index cdd348020b0..04d252a1e03 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -71,6 +71,24 @@ config CLK_IMX8MP help This enables support clock driver for i.MX8MP platforms. +config SPL_CLK_IMX8MQ + bool "SPL clock support for i.MX8MQ" + depends on ARCH_IMX8M && SPL + select SPL_CLK + select SPL_CLK_CCF + select SPL_CLK_COMPOSITE_CCF + help + This enables SPL DM/DTS support for clock driver in i.MX8MQ + +config CLK_IMX8MQ + bool "Clock support for i.MX8MQ" + depends on ARCH_IMX8M + select CLK + select CLK_CCF + select CLK_COMPOSITE_CCF + help + This enables support clock driver for i.MX8MQ platforms. + config SPL_CLK_IMXRT1020 bool "SPL clock support for i.MXRT1020" depends on ARCH_IMXRT && SPL diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 01bbbdf3aea..c5766901f2b 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -16,6 +16,8 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ clk-composite-8m.o obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MP) += clk-imx8mp.o clk-pll14xx.o \ clk-composite-8m.o +obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MQ) += clk-imx8mq.o clk-pll14xx.o \ + clk-composite-8m.o obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1020) += clk-imxrt1020.o obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c index 443bbdae332..542aa31f7ac 100644 --- a/drivers/clk/imx/clk-imx8mm.c +++ b/drivers/clk/imx/clk-imx8mm.c @@ -15,56 +15,6 @@ #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 imx8mm_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 imx8mm_drampll_tbl[] = { - PLL_1443X_RATE(650000000U, 325, 3, 2, 0), -}; - -static struct imx_pll14xx_clk imx8mm_dram_pll __initdata = { - .type = PLL_1443X, - .rate_table = imx8mm_drampll_tbl, - .rate_count = ARRAY_SIZE(imx8mm_drampll_tbl), -}; - -static struct imx_pll14xx_clk imx8mm_arm_pll __initdata = { - .type = PLL_1416X, - .rate_table = imx8mm_pll1416x_tbl, - .rate_count = ARRAY_SIZE(imx8mm_pll1416x_tbl), -}; - -static struct imx_pll14xx_clk imx8mm_sys_pll __initdata = { - .type = PLL_1416X, - .rate_table = imx8mm_pll1416x_tbl, - .rate_count = ARRAY_SIZE(imx8mm_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", }; @@ -116,6 +66,18 @@ static const char *imx8mm_i2c3_sels[] = {"clock-osc-24m", "sys_pll1_160m", "sys_ static const char *imx8mm_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 *imx8mm_pwm1_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m", + "sys_pll3_out", "clk_ext1", "sys_pll1_80m", "video_pll1_out", }; + +static const char *imx8mm_pwm2_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m", + "sys_pll3_out", "clk_ext1", "sys_pll1_80m", "video_pll1_out", }; + +static const char *imx8mm_pwm3_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m", + "sys_pll3_out", "clk_ext2", "sys_pll1_80m", "video_pll1_out", }; + +static const char *imx8mm_pwm4_sels[] = {"clock-osc-24m", "sys_pll2_100m", "sys_pll1_160m", "sys_pll1_40m", + "sys_pll3_out", "clk_ext2", "sys_pll1_80m", "video_pll1_out", }; + static const char *imx8mm_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", }; @@ -164,19 +126,19 @@ static int imx8mm_clk_probe(struct udevice *dev) clk_dm(IMX8MM_DRAM_PLL, imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", - base + 0x50, &imx8mm_dram_pll)); + base + 0x50, &imx_1443x_dram_pll)); clk_dm(IMX8MM_ARM_PLL, imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", - base + 0x84, &imx8mm_arm_pll)); + base + 0x84, &imx_1416x_pll)); clk_dm(IMX8MM_SYS_PLL1, imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", - base + 0x94, &imx8mm_sys_pll)); + base + 0x94, &imx_1416x_pll)); clk_dm(IMX8MM_SYS_PLL2, imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", - base + 0x104, &imx8mm_sys_pll)); + base + 0x104, &imx_1416x_pll)); clk_dm(IMX8MM_SYS_PLL3, imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", - base + 0x114, &imx8mm_sys_pll)); + base + 0x114, &imx_1416x_pll)); /* PLL bypass out */ clk_dm(IMX8MM_DRAM_PLL_BYPASS, @@ -305,6 +267,14 @@ static int imx8mm_clk_probe(struct udevice *dev) imx8m_clk_composite("i2c3", imx8mm_i2c3_sels, base + 0xae00)); clk_dm(IMX8MM_CLK_I2C4, imx8m_clk_composite("i2c4", imx8mm_i2c4_sels, base + 0xae80)); + clk_dm(IMX8MM_CLK_PWM1, + imx8m_clk_composite("pwm1", imx8mm_pwm1_sels, base + 0xb380)); + clk_dm(IMX8MM_CLK_PWM2, + imx8m_clk_composite("pwm2", imx8mm_pwm2_sels, base + 0xb400)); + clk_dm(IMX8MM_CLK_PWM3, + imx8m_clk_composite("pwm3", imx8mm_pwm3_sels, base + 0xb480)); + clk_dm(IMX8MM_CLK_PWM4, + imx8m_clk_composite("pwm4", imx8mm_pwm4_sels, base + 0xb500)); clk_dm(IMX8MM_CLK_WDOG, imx8m_clk_composite("wdog", imx8mm_wdog_sels, base + 0xb900)); clk_dm(IMX8MM_CLK_USDHC3, @@ -339,6 +309,14 @@ static int imx8mm_clk_probe(struct udevice *dev) imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0)); clk_dm(IMX8MM_CLK_OCOTP_ROOT, imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0)); + clk_dm(IMX8MM_CLK_PWM1_ROOT, + imx_clk_gate4("pwm1_root_clk", "pwm1", base + 0x4280, 0)); + clk_dm(IMX8MM_CLK_PWM2_ROOT, + imx_clk_gate4("pwm2_root_clk", "pwm2", base + 0x4290, 0)); + clk_dm(IMX8MM_CLK_PWM3_ROOT, + imx_clk_gate4("pwm3_root_clk", "pwm3", base + 0x42a0, 0)); + clk_dm(IMX8MM_CLK_PWM4_ROOT, + imx_clk_gate4("pwm4_root_clk", "pwm4", base + 0x42b0, 0)); clk_dm(IMX8MM_CLK_USDHC1_ROOT, imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0)); clk_dm(IMX8MM_CLK_USDHC2_ROOT, diff --git a/drivers/clk/imx/clk-imx8mn.c b/drivers/clk/imx/clk-imx8mn.c index bb62138f8ca..15d7599cfb7 100644 --- a/drivers/clk/imx/clk-imx8mn.c +++ b/drivers/clk/imx/clk-imx8mn.c @@ -15,56 +15,6 @@ #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", }; @@ -172,19 +122,19 @@ static int imx8mn_clk_probe(struct udevice *dev) clk_dm(IMX8MN_DRAM_PLL, imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", - base + 0x50, &imx8mn_dram_pll)); + base + 0x50, &imx_1443x_dram_pll)); clk_dm(IMX8MN_ARM_PLL, imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", - base + 0x84, &imx8mn_arm_pll)); + base + 0x84, &imx_1416x_pll)); clk_dm(IMX8MN_SYS_PLL1, imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", - base + 0x94, &imx8mn_sys_pll)); + base + 0x94, &imx_1416x_pll)); clk_dm(IMX8MN_SYS_PLL2, imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", - base + 0x104, &imx8mn_sys_pll)); + base + 0x104, &imx_1416x_pll)); clk_dm(IMX8MN_SYS_PLL3, imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", - base + 0x114, &imx8mn_sys_pll)); + base + 0x114, &imx_1416x_pll)); /* PLL bypass out */ clk_dm(IMX8MN_DRAM_PLL_BYPASS, diff --git a/drivers/clk/imx/clk-imx8mp.c b/drivers/clk/imx/clk-imx8mp.c index ad84ce38ede..ac727b7e404 100644 --- a/drivers/clk/imx/clk-imx8mp.c +++ b/drivers/clk/imx/clk-imx8mp.c @@ -15,56 +15,6 @@ #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 imx8mp_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 imx8mp_drampll_tbl[] = { - PLL_1443X_RATE(650000000U, 325, 3, 2, 0), -}; - -static struct imx_pll14xx_clk imx8mp_dram_pll __initdata = { - .type = PLL_1443X, - .rate_table = imx8mp_drampll_tbl, - .rate_count = ARRAY_SIZE(imx8mp_drampll_tbl), -}; - -static struct imx_pll14xx_clk imx8mp_arm_pll __initdata = { - .type = PLL_1416X, - .rate_table = imx8mp_pll1416x_tbl, - .rate_count = ARRAY_SIZE(imx8mp_pll1416x_tbl), -}; - -static struct imx_pll14xx_clk imx8mp_sys_pll __initdata = { - .type = PLL_1416X, - .rate_table = imx8mp_pll1416x_tbl, - .rate_count = ARRAY_SIZE(imx8mp_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", }; @@ -76,6 +26,10 @@ static const char *imx8mp_a53_sels[] = {"clock-osc-24m", "arm_pll_out", "sys_pll "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m", "audio_pll1_out", "sys_pll3_out", }; +static const char *imx8mp_hsio_axi_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 *imx8mp_main_axi_sels[] = {"clock-osc-24m", "sys_pll2_333m", "sys_pll1_800m", "sys_pll2_250m", "sys_pll2_1000m", "audio_pll1_out", "video_pll1_out", "sys_pll1_100m",}; @@ -156,10 +110,30 @@ static const char *imx8mp_uart4_sels[] = {"clock-osc-24m", "sys_pll1_80m", "sys_ "sys_pll2_100m", "sys_pll3_out", "clk_ext2", "clk_ext3", "audio_pll2_out", }; +static const char *imx8mp_usb_core_ref_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 *imx8mp_usb_phy_ref_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 *imx8mp_gic_sels[] = {"clock-osc-24m", "sys_pll2_200m", "sys_pll1_40m", "sys_pll2_100m", "sys_pll1_800m", "sys_pll2_500m", "clk_ext4", "audio_pll2_out" }; +static const char *imx8mp_ecspi1_sels[] = {"clock-osc_24m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char *imx8mp_ecspi2_sels[] = {"clock-osc_24m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char *imx8mp_ecspi3_sels[] = {"clock-osc_24m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + static const char *imx8mp_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" }; @@ -188,7 +162,9 @@ static const char *imx8mp_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", } static int imx8mp_clk_probe(struct udevice *dev) { + struct clk osc_24m_clk, osc_32k_clk; void __iomem *base; + int ret; base = (void *)ANATOP_BASE_ADDR; @@ -198,11 +174,16 @@ static int imx8mp_clk_probe(struct udevice *dev) clk_dm(IMX8MP_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(IMX8MP_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(IMX8MP_DRAM_PLL, imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50, &imx8mp_dram_pll)); - clk_dm(IMX8MP_ARM_PLL, imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84, &imx8mp_arm_pll)); - clk_dm(IMX8MP_SYS_PLL1, imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", base + 0x94, &imx8mp_sys_pll)); - clk_dm(IMX8MP_SYS_PLL2, imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", base + 0x104, &imx8mp_sys_pll)); - clk_dm(IMX8MP_SYS_PLL3, imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114, &imx8mp_sys_pll)); + clk_dm(IMX8MP_DRAM_PLL, imx_clk_pll14xx("dram_pll", "dram_pll_ref_sel", base + 0x50, + &imx_1443x_dram_pll)); + clk_dm(IMX8MP_ARM_PLL, imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", base + 0x84, + &imx_1416x_pll)); + clk_dm(IMX8MP_SYS_PLL1, imx_clk_pll14xx("sys_pll1", "sys_pll1_ref_sel", base + 0x94, + &imx_1416x_pll)); + clk_dm(IMX8MP_SYS_PLL2, imx_clk_pll14xx("sys_pll2", "sys_pll2_ref_sel", base + 0x104, + &imx_1416x_pll)); + clk_dm(IMX8MP_SYS_PLL3, imx_clk_pll14xx("sys_pll3", "sys_pll3_ref_sel", base + 0x114, + &imx_1416x_pll)); clk_dm(IMX8MP_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(IMX8MP_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)); @@ -236,6 +217,16 @@ static int imx8mp_clk_probe(struct udevice *dev) clk_dm(IMX8MP_SYS_PLL2_500M, imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2)); clk_dm(IMX8MP_SYS_PLL2_1000M, imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1)); + ret = clk_get_by_name(dev, "osc_24m", &osc_24m_clk); + if (ret) + return ret; + clk_dm(IMX8MP_CLK_24M, dev_get_clk_ptr(osc_24m_clk.dev)); + + ret = clk_get_by_name(dev, "osc_32k", &osc_32k_clk); + if (ret) + return ret; + clk_dm(IMX8MP_CLK_32K, dev_get_clk_ptr(osc_32k_clk.dev)); + base = dev_read_addr_ptr(dev); if (!base) return -EINVAL; @@ -244,6 +235,7 @@ static int imx8mp_clk_probe(struct udevice *dev) clk_dm(IMX8MP_CLK_A53_CG, imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28)); clk_dm(IMX8MP_CLK_A53_DIV, imx_clk_divider2("arm_a53_div", "arm_a53_cg", base + 0x8000, 0, 3)); + clk_dm(IMX8MP_CLK_HSIO_AXI, imx8m_clk_composite("hsio_axi", imx8mp_hsio_axi_sels, base + 0x8380)); 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)); @@ -273,7 +265,12 @@ static int imx8mp_clk_probe(struct udevice *dev) clk_dm(IMX8MP_CLK_UART2, imx8m_clk_composite("uart2", imx8mp_uart2_sels, base + 0xaf80)); clk_dm(IMX8MP_CLK_UART3, imx8m_clk_composite("uart3", imx8mp_uart3_sels, base + 0xb000)); clk_dm(IMX8MP_CLK_UART4, imx8m_clk_composite("uart4", imx8mp_uart4_sels, base + 0xb080)); + clk_dm(IMX8MP_CLK_USB_CORE_REF, imx8m_clk_composite("usb_core_ref", imx8mp_usb_core_ref_sels, base + 0xb100)); + clk_dm(IMX8MP_CLK_USB_PHY_REF, imx8m_clk_composite("usb_phy_ref", imx8mp_usb_phy_ref_sels, base + 0xb180)); clk_dm(IMX8MP_CLK_GIC, imx8m_clk_composite_critical("gic", imx8mp_gic_sels, base + 0xb200)); + clk_dm(IMX8MP_CLK_ECSPI1, imx8m_clk_composite("ecspi1", imx8mp_ecspi1_sels, base + 0xb280)); + clk_dm(IMX8MP_CLK_ECSPI2, imx8m_clk_composite("ecspi2", imx8mp_ecspi2_sels, base + 0xb300)); + clk_dm(IMX8MP_CLK_ECSPI3, imx8m_clk_composite("ecspi3", imx8mp_ecspi3_sels, base + 0xc180)); clk_dm(IMX8MP_CLK_WDOG, imx8m_clk_composite("wdog", imx8mp_wdog_sels, base + 0xb900)); clk_dm(IMX8MP_CLK_USDHC3, imx8m_clk_composite("usdhc3", imx8mp_usdhc3_sels, base + 0xbc80)); @@ -282,7 +279,9 @@ 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_ECSPI1_ROOT, imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0)); + clk_dm(IMX8MP_CLK_ECSPI2_ROOT, imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0)); + clk_dm(IMX8MP_CLK_ECSPI3_ROOT, imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0)); 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)); @@ -301,11 +300,14 @@ static int imx8mp_clk_probe(struct udevice *dev) 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)); clk_dm(IMX8MP_CLK_UART4_ROOT, imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0)); + clk_dm(IMX8MP_CLK_USB_ROOT, imx_clk_gate4("usb_root_clk", "osc_32k", base + 0x44d0, 0)); + clk_dm(IMX8MP_CLK_USB_PHY_ROOT, imx_clk_gate4("usb_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0)); clk_dm(IMX8MP_CLK_USDHC1_ROOT, imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0)); clk_dm(IMX8MP_CLK_USDHC2_ROOT, imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0)); clk_dm(IMX8MP_CLK_WDOG1_ROOT, imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0)); clk_dm(IMX8MP_CLK_WDOG2_ROOT, imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0)); clk_dm(IMX8MP_CLK_WDOG3_ROOT, imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0)); + clk_dm(IMX8MP_CLK_HSIO_ROOT, imx_clk_gate4("hsio_root_clk", "ipg_root", base + 0x45c0, 0)); clk_dm(IMX8MP_CLK_USDHC3_ROOT, imx_clk_gate4("usdhc3_root_clk", "usdhc3", base + 0x45e0, 0)); diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c new file mode 100644 index 00000000000..cf197df96db --- /dev/null +++ b/drivers/clk/imx/clk-imx8mq.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP + * Copyright 2022 Purism + * Peng Fan <peng.fan@nxp.com> + */ + +#include <common.h> +#include <clk.h> +#include <clk-uclass.h> +#include <dm.h> +#include <log.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <dt-bindings/clock/imx8mq-clock.h> + +#include "clk.h" + +static const char *const pll_ref_sels[] = { "clock-osc-25m", "clock-osc-27m", "clock-phy-27m", "dummy", }; +static const char *const arm_pll_bypass_sels[] = {"arm_pll", "arm_pll_ref_sel", }; +static const char *const gpu_pll_bypass_sels[] = {"gpu_pll", "gpu_pll_ref_sel", }; +static const char *const vpu_pll_bypass_sels[] = {"vpu_pll", "vpu_pll_ref_sel", }; +static const char *const audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_ref_sel", }; +static const char *const audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; +static const char *const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; + +static const char *const imx8mq_a53_core_sels[] = {"arm_a53_div", "arm_pll_out", }; +static const char *const imx8mq_a53_sels[] = {"clock-osc-25m", "arm_pll_out", "sys_pll2_500m", + "sys_pll2_1000m", "sys_pll1_800m", "sys_pll1_400m", + "audio_pll1_out", "sys_pll3_out", }; + +static const char *const imx8mq_ahb_sels[] = {"clock-osc-25m", "sys_pll1_133m", "sys_pll1_800m", + "sys_pll1_400m", "sys_pll2_125m", "sys_pll3_out", + "audio_pll1_out", "video_pll1_out", }; + +static const char *const imx8mq_dram_alt_sels[] = {"osc_25m", "sys_pll1_800m", "sys_pll1_100m", + "sys_pll2_500m", "sys_pll2_250m", + "sys_pll1_400m", "audio_pll1_out", "sys_pll1_266m", } ; + +static const char * const imx8mq_dram_apb_sels[] = {"osc_25m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char *const imx8mq_enet_axi_sels[] = {"clock-osc-25m", "sys_pll1_266m", "sys_pll1_800m", + "sys_pll2_250m", "sys_pll2_200m", "audio_pll1_out", + "video_pll1_out", "sys_pll3_out", }; + +static const char *const imx8mq_enet_ref_sels[] = {"clock-osc-25m", "sys_pll2_125m", "sys_pll2_50m", + "sys_pll2_100m", "sys_pll1_160m", "audio_pll1_out", + "video_pll1_out", "clk_ext4", }; + +static const char *const imx8mq_enet_timer_sels[] = {"clock-osc-25m", "sys_pll2_100m", "audio_pll1_out", + "clk_ext1", "clk_ext2", "clk_ext3", "clk_ext4", + "video_pll1_out", }; + +static const char *const imx8mq_enet_phy_sels[] = {"clock-osc-25m", "sys_pll2_50m", "sys_pll2_125m", + "sys_pll2_200m", "sys_pll2_500m", "video_pll1_out", + "audio_pll2_out", }; + +static const char *const imx8mq_nand_usdhc_sels[] = {"clock-osc-25m", "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 imx8mq_usb_bus_sels[] = {"clock-osc-25m", "sys_pll2_500m", "sys_pll1_800m", + "sys_pll2_100m", "sys_pll2_200m", "clk_ext2", + "clk_ext4", "audio_pll2_out", }; + +static const char *const imx8mq_usdhc1_sels[] = {"clock-osc-25m", "sys_pll1_400m", "sys_pll1_800m", + "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", + "audio_pll2_out", "sys_pll1_100m", }; + +static const char *const imx8mq_usdhc2_sels[] = {"clock-osc-25m", "sys_pll1_400m", "sys_pll1_800m", + "sys_pll2_500m", "sys_pll3_out", "sys_pll1_266m", + "audio_pll2_out", "sys_pll1_100m", }; + +static const char *const imx8mq_i2c1_sels[] = {"clock-osc-25m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char *const imx8mq_i2c2_sels[] = {"clock-osc-25m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char *const imx8mq_i2c3_sels[] = {"clock-osc-25m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char *const imx8mq_i2c4_sels[] = {"clock-osc-25m", "sys_pll1_160m", "sys_pll2_50m", + "sys_pll3_out", "audio_pll1_out", "video_pll1_out", + "audio_pll2_out", "sys_pll1_133m", }; + +static const char *const imx8mq_uart1_sels[] = {"clock-osc-25m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext4", "audio_pll2_out", }; + +static const char *const imx8mq_uart2_sels[] = {"clock-osc-25m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char *const imx8mq_uart3_sels[] = {"clock-osc-25m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext4", "audio_pll2_out", }; + +static const char *const imx8mq_uart4_sels[] = {"clock-osc-25m", "sys_pll1_80m", "sys_pll2_200m", + "sys_pll2_100m", "sys_pll3_out", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char *const imx8mq_wdog_sels[] = {"clock-osc-25m", "sys_pll1_133m", "sys_pll1_160m", + "vpu_pll_out", "sys_pll2_125m", "sys_pll3_out", + "sys_pll1_80m", "sys_pll2_166m", }; + +static const char *const imx8mq_qspi_sels[] = {"clock-osc-25m", "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 imx8mq_usb_core_sels[] = {"clock-osc-25m", "sys_pll1_100m", "sys_pll1_40m", + "sys_pll2_100m", "sys_pll2_200m", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char *const imx8mq_usb_phy_sels[] = {"clock-osc-25m", "sys_pll1_100m", "sys_pll1_40m", + "sys_pll2_100m", "sys_pll2_200m", "clk_ext2", + "clk_ext3", "audio_pll2_out", }; + +static const char *const imx8mq_ecspi1_sels[] = {"clock-osc-25m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char *const imx8mq_ecspi2_sels[] = {"clock-osc-25m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char *const imx8mq_ecspi3_sels[] = {"clock-osc-25m", "sys_pll2_200m", "sys_pll1_40m", + "sys_pll1_160m", "sys_pll1_800m", "sys_pll3_out", + "sys_pll2_250m", "audio_pll2_out", }; + +static const char *const imx8mq_dram_core_sels[] = {"dram_pll_out", "dram_alt_root", }; + +static const char *const pllout_monitor_sels[] = {"clock-osc-25m", "clock-osc-27m", "clock-phy-27m", + "dummy", "clock-ckil", "audio_pll1_out_monitor", + "audio_pll2_out_monitor", "gpu_pll_out_monitor", + "vpu_pll_out_monitor", "video_pll1_out_monitor", + "arm_pll_out_monitor", "sys_pll1_out_monitor", + "sys_pll2_out_monitor", "sys_pll3_out_monitor", + "video_pll2_out_monitor", "dram_pll_out_monitor", }; + +static int imx8mq_clk_probe(struct udevice *dev) +{ + void __iomem *base; + + base = (void *)ANATOP_BASE_ADDR; + + clk_dm(IMX8MQ_CLK_32K, clk_register_fixed_rate(NULL, "ckil", 32768)); + clk_dm(IMX8MQ_CLK_27M, clk_register_fixed_rate(NULL, "clock-osc-27m", 27000000)); + + clk_dm(IMX8MQ_DRAM_PLL1_REF_SEL, + imx_clk_mux("dram_pll_ref_sel", base + 0x60, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MQ_ARM_PLL_REF_SEL, + imx_clk_mux("arm_pll_ref_sel", base + 0x28, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MQ_GPU_PLL_REF_SEL, + imx_clk_mux("gpu_pll_ref_sel", base + 0x18, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MQ_VPU_PLL_REF_SEL, + imx_clk_mux("vpu_pll_ref_sel", base + 0x20, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MQ_SYS3_PLL1_REF_SEL, + imx_clk_mux("sys3_pll_ref_sel", base + 0x48, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MQ_AUDIO_PLL1_REF_SEL, + imx_clk_mux("audio_pll1_ref_sel", base + 0x0, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MQ_AUDIO_PLL2_REF_SEL, + imx_clk_mux("audio_pll2_ref_sel", base + 0x8, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MQ_VIDEO_PLL1_REF_SEL, + imx_clk_mux("video_pll1_ref_sel", base + 0x10, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMX8MQ_VIDEO2_PLL1_REF_SEL, + imx_clk_mux("video_pll2_ref_sel", base + 0x54, 0, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + + clk_dm(IMX8MQ_ARM_PLL, + imx_clk_pll14xx("arm_pll", "arm_pll_ref_sel", + base + 0x28, &imx_1416x_pll)); + clk_dm(IMX8MQ_GPU_PLL, + imx_clk_pll14xx("gpu_pll", "gpu_pll_ref_sel", + base + 0x18, &imx_1416x_pll)); + clk_dm(IMX8MQ_VPU_PLL, + imx_clk_pll14xx("vpu_pll", "vpu_pll_ref_sel", + base + 0x20, &imx_1416x_pll)); + + clk_dm(IMX8MQ_SYS1_PLL1, + clk_register_fixed_rate(NULL, "sys1_pll", 800000000)); + clk_dm(IMX8MQ_SYS2_PLL1, + clk_register_fixed_rate(NULL, "sys2_pll", 1000000000)); + clk_dm(IMX8MQ_SYS2_PLL1, + clk_register_fixed_rate(NULL, "sys3_pll", 1000000000)); + clk_dm(IMX8MQ_AUDIO_PLL1, + imx_clk_pll14xx("audio_pll1", "audio_pll1_ref_sel", + base + 0x0, &imx_1443x_pll)); + clk_dm(IMX8MQ_AUDIO_PLL2, + imx_clk_pll14xx("audio_pll2", "audio_pll2_ref_sel", + base + 0x8, &imx_1443x_pll)); + clk_dm(IMX8MQ_VIDEO_PLL1, + imx_clk_pll14xx("video_pll1", "video_pll1_ref_sel", + base + 0x10, &imx_1443x_pll)); + + /* PLL bypass out */ + clk_dm(IMX8MQ_ARM_PLL_BYPASS, + imx_clk_mux_flags("arm_pll_bypass", base + 0x28, 4, 1, + arm_pll_bypass_sels, + ARRAY_SIZE(arm_pll_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MQ_GPU_PLL_BYPASS, + imx_clk_mux_flags("gpu_pll_bypass", base + 0x18, 4, 1, + gpu_pll_bypass_sels, + ARRAY_SIZE(gpu_pll_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MQ_VPU_PLL_BYPASS, + imx_clk_mux_flags("vpu_pll_bypass", base + 0x20, 4, 1, + vpu_pll_bypass_sels, + ARRAY_SIZE(vpu_pll_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MQ_AUDIO_PLL1_BYPASS, + imx_clk_mux_flags("audio_pll1_bypass", base + 0x0, 4, 1, + audio_pll1_bypass_sels, + ARRAY_SIZE(audio_pll1_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MQ_AUDIO_PLL2_BYPASS, + imx_clk_mux_flags("audio_pll2_bypass", base + 0x8, 4, 1, + audio_pll2_bypass_sels, + ARRAY_SIZE(audio_pll2_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MQ_VIDEO_PLL1_BYPASS, + imx_clk_mux_flags("video_pll1_bypass", base + 0x10, 4, 1, + video_pll1_bypass_sels, + ARRAY_SIZE(video_pll1_bypass_sels), + CLK_SET_RATE_PARENT)); + + /* PLL out gate */ + clk_dm(IMX8MQ_DRAM_PLL_OUT, + imx_clk_gate("dram_pll_out", "dram_pll_ref_sel", + base + 0x60, 13)); + clk_dm(IMX8MQ_ARM_PLL_OUT, + imx_clk_gate("arm_pll_out", "arm_pll_bypass", + base + 0x28, 11)); + clk_dm(IMX8MQ_GPU_PLL_OUT, + imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", + base + 0x18, 11)); + clk_dm(IMX8MQ_VPU_PLL_OUT, + imx_clk_gate("vpu_pll_out", "vpu_pll_bypass", + base + 0x20, 11)); + clk_dm(IMX8MQ_AUDIO_PLL1_OUT, + imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", + base + 0x0, 11)); + clk_dm(IMX8MQ_AUDIO_PLL2_OUT, + imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", + base + 0x8, 11)); + clk_dm(IMX8MQ_VIDEO_PLL1_OUT, + imx_clk_gate("video_pll1_out", "video_pll1_bypass", + base + 0x10, 11)); + + clk_dm(IMX8MQ_SYS1_PLL_OUT, + imx_clk_gate("sys_pll1_out", "sys1_pll", + base + 0x30, 11)); + clk_dm(IMX8MQ_SYS2_PLL_OUT, + imx_clk_gate("sys_pll2_out", "sys2_pll", + base + 0x3c, 11)); + clk_dm(IMX8MQ_SYS3_PLL_OUT, + imx_clk_gate("sys_pll3_out", "sys3_pll", + base + 0x48, 11)); + clk_dm(IMX8MQ_VIDEO2_PLL_OUT, + imx_clk_gate("video_pll2_out", "video_pll2_ref_sel", + base + 0x54, 11)); + + /* SYS PLL fixed output */ + clk_dm(IMX8MQ_SYS1_PLL_40M, + imx_clk_fixed_factor("sys_pll1_40m", "sys_pll1_out", 1, 20)); + clk_dm(IMX8MQ_SYS1_PLL_80M, + imx_clk_fixed_factor("sys_pll1_80m", "sys_pll1_out", 1, 10)); + clk_dm(IMX8MQ_SYS1_PLL_100M, + imx_clk_fixed_factor("sys_pll1_100m", "sys_pll1_out", 1, 8)); + clk_dm(IMX8MQ_SYS1_PLL_133M, + imx_clk_fixed_factor("sys_pll1_133m", "sys_pll1_out", 1, 6)); + clk_dm(IMX8MQ_SYS1_PLL_160M, + imx_clk_fixed_factor("sys_pll1_160m", "sys_pll1_out", 1, 5)); + clk_dm(IMX8MQ_SYS1_PLL_200M, + imx_clk_fixed_factor("sys_pll1_200m", "sys_pll1_out", 1, 4)); + clk_dm(IMX8MQ_SYS1_PLL_266M, + imx_clk_fixed_factor("sys_pll1_266m", "sys_pll1_out", 1, 3)); + clk_dm(IMX8MQ_SYS1_PLL_400M, + imx_clk_fixed_factor("sys_pll1_400m", "sys_pll1_out", 1, 2)); + clk_dm(IMX8MQ_SYS1_PLL_800M, + imx_clk_fixed_factor("sys_pll1_800m", "sys_pll1_out", 1, 1)); + + clk_dm(IMX8MQ_SYS2_PLL_50M, + imx_clk_fixed_factor("sys_pll2_50m", "sys_pll2_out", 1, 20)); + clk_dm(IMX8MQ_SYS2_PLL_100M, + imx_clk_fixed_factor("sys_pll2_100m", "sys_pll2_out", 1, 10)); + clk_dm(IMX8MQ_SYS2_PLL_125M, + imx_clk_fixed_factor("sys_pll2_125m", "sys_pll2_out", 1, 8)); + clk_dm(IMX8MQ_SYS2_PLL_166M, + imx_clk_fixed_factor("sys_pll2_166m", "sys_pll2_out", 1, 6)); + clk_dm(IMX8MQ_SYS2_PLL_200M, + imx_clk_fixed_factor("sys_pll2_200m", "sys_pll2_out", 1, 5)); + clk_dm(IMX8MQ_SYS2_PLL_250M, + imx_clk_fixed_factor("sys_pll2_250m", "sys_pll2_out", 1, 4)); + clk_dm(IMX8MQ_SYS2_PLL_333M, + imx_clk_fixed_factor("sys_pll2_333m", "sys_pll2_out", 1, 3)); + clk_dm(IMX8MQ_SYS2_PLL_500M, + imx_clk_fixed_factor("sys_pll2_500m", "sys_pll2_out", 1, 2)); + clk_dm(IMX8MQ_SYS2_PLL_1000M, + imx_clk_fixed_factor("sys_pll2_1000m", "sys_pll2_out", 1, 1)); + + clk_dm(IMX8MQ_CLK_MON_AUDIO_PLL1_DIV, + imx_clk_divider("audio_pll1_out_monitor", "audio_pll1_bypass", base + 0x78, 0, 3)); + clk_dm(IMX8MQ_CLK_MON_AUDIO_PLL2_DIV, + imx_clk_divider("audio_pll2_out_monitor", "audio_pll2_bypass", base + 0x78, 4, 3)); + clk_dm(IMX8MQ_CLK_MON_VIDEO_PLL1_DIV, + imx_clk_divider("video_pll1_out_monitor", "video_pll1_bypass", base + 0x78, 8, 3)); + clk_dm(IMX8MQ_CLK_MON_GPU_PLL_DIV, + imx_clk_divider("gpu_pll_out_monitor", "gpu_pll_bypass", base + 0x78, 12, 3)); + clk_dm(IMX8MQ_CLK_MON_VPU_PLL_DIV, + imx_clk_divider("vpu_pll_out_monitor", "vpu_pll_bypass", base + 0x78, 16, 3)); + clk_dm(IMX8MQ_CLK_MON_ARM_PLL_DIV, + imx_clk_divider("arm_pll_out_monitor", "arm_pll_bypass", base + 0x78, 20, 3)); + clk_dm(IMX8MQ_CLK_MON_SYS_PLL1_DIV, + imx_clk_divider("sys_pll1_out_monitor", "sys_pll1_out", base + 0x7c, 0, 3)); + clk_dm(IMX8MQ_CLK_MON_SYS_PLL2_DIV, + imx_clk_divider("sys_pll2_out_monitor", "sys_pll2_out", base + 0x7c, 4, 3)); + clk_dm(IMX8MQ_CLK_MON_SYS_PLL3_DIV, + imx_clk_divider("sys_pll3_out_monitor", "sys_pll3_out", base + 0x7c, 8, 3)); + clk_dm(IMX8MQ_CLK_MON_DRAM_PLL_DIV, + imx_clk_divider("dram_pll_out_monitor", "dram_pll_out", base + 0x7c, 12, 3)); + clk_dm(IMX8MQ_CLK_MON_VIDEO_PLL2_DIV, + imx_clk_divider("video_pll2_out_monitor", "video_pll2_out", base + 0x7c, 16, 3)); + clk_dm(IMX8MQ_CLK_MON_SEL, + imx_clk_mux_flags("pllout_monitor_sel", base + 0x74, 0, 4, + pllout_monitor_sels, + ARRAY_SIZE(pllout_monitor_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX8MQ_CLK_MON_CLK2_OUT, + imx_clk_gate4("pllout_monitor_clk2", "pllout_monitor_sel", base + 0x74, 4)); + + base = dev_read_addr_ptr(dev); + if (!base) { + printf("%s : base failed\n", __func__); + return -EINVAL; + } + + clk_dm(IMX8MQ_CLK_A53_SRC, + imx_clk_mux2("arm_a53_src", base + 0x8000, 24, 3, + imx8mq_a53_sels, ARRAY_SIZE(imx8mq_a53_sels))); + clk_dm(IMX8MQ_CLK_A53_CG, + imx_clk_gate3("arm_a53_cg", "arm_a53_src", base + 0x8000, 28)); + clk_dm(IMX8MQ_CLK_A53_DIV, + imx_clk_divider2("arm_a53_div", "arm_a53_cg", + base + 0x8000, 0, 3)); + clk_dm(IMX8MQ_CLK_A53_CORE, + imx_clk_mux2("arm_a53_src", base + 0x9880, 24, 1, + imx8mq_a53_core_sels, ARRAY_SIZE(imx8mq_a53_core_sels))); + + clk_dm(IMX8MQ_CLK_AHB, + imx8m_clk_composite_critical("ahb", imx8mq_ahb_sels, + base + 0x9000)); + clk_dm(IMX8MQ_CLK_IPG_ROOT, + imx_clk_divider2("ipg_root", "ahb", base + 0x9080, 0, 1)); + + clk_dm(IMX8MQ_CLK_ENET_AXI, + imx8m_clk_composite("enet_axi", imx8mq_enet_axi_sels, + base + 0x8880)); + clk_dm(IMX8MQ_CLK_NAND_USDHC_BUS, + imx8m_clk_composite_critical("nand_usdhc_bus", + imx8mq_nand_usdhc_sels, + base + 0x8900)); + clk_dm(IMX8MQ_CLK_USB_BUS, + imx8m_clk_composite("usb_bus", imx8mq_usb_bus_sels, base + 0x8b80)); + + /* DRAM */ + clk_dm(IMX8MQ_CLK_DRAM_CORE, + imx_clk_mux2("dram_core_clk", base + 0x9800, 24, 1, + imx8mq_dram_core_sels, ARRAY_SIZE(imx8mq_dram_core_sels))); + clk_dm(IMX8MQ_CLK_DRAM_ALT, + imx8m_clk_composite("dram_alt", imx8mq_dram_alt_sels, base + 0xa000)); + clk_dm(IMX8MQ_CLK_DRAM_APB, + imx8m_clk_composite_critical("dram_apb", imx8mq_dram_apb_sels, base + 0xa080)); + + /* IP */ + clk_dm(IMX8MQ_CLK_USDHC1, + imx8m_clk_composite("usdhc1", imx8mq_usdhc1_sels, + base + 0xac00)); + clk_dm(IMX8MQ_CLK_USDHC2, + imx8m_clk_composite("usdhc2", imx8mq_usdhc2_sels, + base + 0xac80)); + clk_dm(IMX8MQ_CLK_I2C1, + imx8m_clk_composite("i2c1", imx8mq_i2c1_sels, base + 0xad00)); + clk_dm(IMX8MQ_CLK_I2C2, + imx8m_clk_composite("i2c2", imx8mq_i2c2_sels, base + 0xad80)); + clk_dm(IMX8MQ_CLK_I2C3, + imx8m_clk_composite("i2c3", imx8mq_i2c3_sels, base + 0xae00)); + clk_dm(IMX8MQ_CLK_I2C4, + imx8m_clk_composite("i2c4", imx8mq_i2c4_sels, base + 0xae80)); + clk_dm(IMX8MQ_CLK_WDOG, + imx8m_clk_composite("wdog", imx8mq_wdog_sels, base + 0xb900)); + clk_dm(IMX8MQ_CLK_UART1, + imx8m_clk_composite("uart1", imx8mq_uart1_sels, base + 0xaf00)); + clk_dm(IMX8MQ_CLK_UART2, + imx8m_clk_composite("uart2", imx8mq_uart2_sels, base + 0xaf80)); + clk_dm(IMX8MQ_CLK_UART3, + imx8m_clk_composite("uart3", imx8mq_uart3_sels, base + 0xb000)); + clk_dm(IMX8MQ_CLK_UART4, + imx8m_clk_composite("uart4", imx8mq_uart4_sels, base + 0xb080)); + clk_dm(IMX8MQ_CLK_QSPI, + imx8m_clk_composite("qspi", imx8mq_qspi_sels, base + 0xab80)); + clk_dm(IMX8MQ_CLK_USB_CORE_REF, + imx8m_clk_composite("usb_core_ref", imx8mq_usb_core_sels, base + 0xb100)); + clk_dm(IMX8MQ_CLK_USB_PHY_REF, + imx8m_clk_composite("usb_phy_ref", imx8mq_usb_phy_sels, base + 0xb180)); + clk_dm(IMX8MQ_CLK_ECSPI1, + imx8m_clk_composite("ecspi1", imx8mq_ecspi1_sels, base + 0xb280)); + clk_dm(IMX8MQ_CLK_ECSPI2, + imx8m_clk_composite("ecspi2", imx8mq_ecspi2_sels, base + 0xb300)); + clk_dm(IMX8MQ_CLK_ECSPI3, + imx8m_clk_composite("ecspi3", imx8mq_ecspi3_sels, base + 0xc180)); + + clk_dm(IMX8MQ_CLK_ECSPI1_ROOT, + imx_clk_gate4("ecspi1_root_clk", "ecspi1", base + 0x4070, 0)); + clk_dm(IMX8MQ_CLK_ECSPI2_ROOT, + imx_clk_gate4("ecspi2_root_clk", "ecspi2", base + 0x4080, 0)); + clk_dm(IMX8MQ_CLK_ECSPI3_ROOT, + imx_clk_gate4("ecspi3_root_clk", "ecspi3", base + 0x4090, 0)); + clk_dm(IMX8MQ_CLK_I2C1_ROOT, + imx_clk_gate4("i2c1_root_clk", "i2c1", base + 0x4170, 0)); + clk_dm(IMX8MQ_CLK_I2C2_ROOT, + imx_clk_gate4("i2c2_root_clk", "i2c2", base + 0x4180, 0)); + clk_dm(IMX8MQ_CLK_I2C3_ROOT, + imx_clk_gate4("i2c3_root_clk", "i2c3", base + 0x4190, 0)); + clk_dm(IMX8MQ_CLK_I2C4_ROOT, + imx_clk_gate4("i2c4_root_clk", "i2c4", base + 0x41a0, 0)); + clk_dm(IMX8MQ_CLK_UART1_ROOT, + imx_clk_gate4("uart1_root_clk", "uart1", base + 0x4490, 0)); + clk_dm(IMX8MQ_CLK_UART2_ROOT, + imx_clk_gate4("uart2_root_clk", "uart2", base + 0x44a0, 0)); + clk_dm(IMX8MQ_CLK_UART3_ROOT, + imx_clk_gate4("uart3_root_clk", "uart3", base + 0x44b0, 0)); + clk_dm(IMX8MQ_CLK_UART4_ROOT, + imx_clk_gate4("uart4_root_clk", "uart4", base + 0x44c0, 0)); + clk_dm(IMX8MQ_CLK_OCOTP_ROOT, + imx_clk_gate4("ocotp_root_clk", "ipg_root", base + 0x4220, 0)); + clk_dm(IMX8MQ_CLK_USDHC1_ROOT, + imx_clk_gate4("usdhc1_root_clk", "usdhc1", base + 0x4510, 0)); + clk_dm(IMX8MQ_CLK_USDHC2_ROOT, + imx_clk_gate4("usdhc2_root_clk", "usdhc2", base + 0x4520, 0)); + clk_dm(IMX8MQ_CLK_WDOG1_ROOT, + imx_clk_gate4("wdog1_root_clk", "wdog", base + 0x4530, 0)); + clk_dm(IMX8MQ_CLK_WDOG2_ROOT, + imx_clk_gate4("wdog2_root_clk", "wdog", base + 0x4540, 0)); + clk_dm(IMX8MQ_CLK_WDOG3_ROOT, + imx_clk_gate4("wdog3_root_clk", "wdog", base + 0x4550, 0)); + clk_dm(IMX8MQ_CLK_QSPI_ROOT, + imx_clk_gate4("qspi_root_clk", "qspi", base + 0x42f0, 0)); + clk_dm(IMX8MQ_CLK_USB1_CTRL_ROOT, + imx_clk_gate4("usb1_ctrl_root_clk", "usb_bus", base + 0x44d0, 0)); + clk_dm(IMX8MQ_CLK_USB2_CTRL_ROOT, + imx_clk_gate4("usb2_ctrl_root_clk", "usb_bus", base + 0x44e0, 0)); + clk_dm(IMX8MQ_CLK_USB1_PHY_ROOT, + imx_clk_gate4("usb1_phy_root_clk", "usb_phy_ref", base + 0x44f0, 0)); + clk_dm(IMX8MQ_CLK_USB2_PHY_ROOT, + imx_clk_gate4("usb2_phy_root_clk", "usb_phy_ref", base + 0x4500, 0)); + + clk_dm(IMX8MQ_CLK_ENET_REF, + imx8m_clk_composite("enet_ref", imx8mq_enet_ref_sels, + base + 0xa980)); + clk_dm(IMX8MQ_CLK_ENET_TIMER, + imx8m_clk_composite("enet_timer", imx8mq_enet_timer_sels, + base + 0xaa00)); + clk_dm(IMX8MQ_CLK_ENET_PHY_REF, + imx8m_clk_composite("enet_phy", imx8mq_enet_phy_sels, + base + 0xaa80)); + clk_dm(IMX8MQ_CLK_ENET1_ROOT, + imx_clk_gate4("enet1_root_clk", "enet_axi", + base + 0x40a0, 0)); + + clk_dm(IMX8MQ_CLK_DRAM_ALT_ROOT, + imx_clk_fixed_factor("dram_alt_root", "dram_alt", 1, 4)); + + return 0; +} + +static const struct udevice_id imx8mq_clk_ids[] = { + { .compatible = "fsl,imx8mq-ccm" }, + { }, +}; + +U_BOOT_DRIVER(imx8mq_clk) = { + .name = "clk_imx8mq", + .id = UCLASS_CLK, + .of_match = imx8mq_clk_ids, + .ops = &ccf_clk_ops, + .probe = imx8mq_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/clk/imx/clk-imxrt1020.c b/drivers/clk/imx/clk-imxrt1020.c index 3f8b4df3c5a..dc91ac5adbf 100644 --- a/drivers/clk/imx/clk-imxrt1020.c +++ b/drivers/clk/imx/clk-imxrt1020.c @@ -36,7 +36,7 @@ static int imxrt1020_clk_probe(struct udevice *dev) void *base; /* Anatop clocks */ - base = (void *)ANATOP_BASE_ADDR; + base = (void *)ofnode_get_addr(ofnode_by_compatible(ofnode_null(), "fsl,imxrt-anatop")); clk_dm(IMXRT1020_CLK_PLL2_SYS, imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", "osc", diff --git a/drivers/clk/imx/clk-imxrt1050.c b/drivers/clk/imx/clk-imxrt1050.c index 5cb5e3bc15a..d40635d17a4 100644 --- a/drivers/clk/imx/clk-imxrt1050.c +++ b/drivers/clk/imx/clk-imxrt1050.c @@ -34,7 +34,7 @@ static int imxrt1050_clk_probe(struct udevice *dev) void *base; /* Anatop clocks */ - base = (void *)ANATOP_BASE_ADDR; + base = (void *)ofnode_get_addr(ofnode_by_compatible(ofnode_null(), "fsl,imxrt-anatop")); clk_dm(IMXRT1050_CLK_PLL1_REF_SEL, imx_clk_mux("pll1_arm_ref_sel", base + 0x0, 14, 2, diff --git a/drivers/clk/imx/clk-pll14xx.c b/drivers/clk/imx/clk-pll14xx.c index b0ccb6c8eda..b93c0bc64e7 100644 --- a/drivers/clk/imx/clk-pll14xx.c +++ b/drivers/clk/imx/clk-pll14xx.c @@ -52,6 +52,67 @@ struct clk_pll14xx { #define to_clk_pll14xx(_clk) container_of(_clk, struct clk_pll14xx, clk) +#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 imx_pll1416x_tbl[] = { + PLL_1416X_RATE(1800000000U, 225, 3, 0), + PLL_1416X_RATE(1600000000U, 200, 3, 0), + PLL_1416X_RATE(1500000000U, 375, 3, 1), + PLL_1416X_RATE(1400000000U, 350, 3, 1), + 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), +}; + +const struct imx_pll14xx_rate_table imx_pll1443x_tbl[] = { + PLL_1443X_RATE(1039500000U, 173, 2, 1, 16384), + PLL_1443X_RATE(650000000U, 325, 3, 2, 0), + PLL_1443X_RATE(594000000U, 198, 2, 2, 0), + PLL_1443X_RATE(519750000U, 173, 2, 2, 16384), + PLL_1443X_RATE(393216000U, 262, 2, 3, 9437), + PLL_1443X_RATE(361267200U, 361, 3, 3, 17511), +}; + +struct imx_pll14xx_clk imx_1443x_pll __initdata = { + .type = PLL_1443X, + .rate_table = imx_pll1443x_tbl, + .rate_count = ARRAY_SIZE(imx_pll1443x_tbl), +}; +EXPORT_SYMBOL_GPL(imx_1443x_pll); + +struct imx_pll14xx_clk imx_1443x_dram_pll __initdata = { + .type = PLL_1443X, + .rate_table = imx_pll1443x_tbl, + .rate_count = ARRAY_SIZE(imx_pll1443x_tbl), + .flags = CLK_GET_RATE_NOCACHE, +}; +EXPORT_SYMBOL_GPL(imx_1443x_dram_pll); + +struct imx_pll14xx_clk imx_1416x_pll __initdata = { + .type = PLL_1416X, + .rate_table = imx_pll1416x_tbl, + .rate_count = ARRAY_SIZE(imx_pll1416x_tbl), +}; +EXPORT_SYMBOL_GPL(imx_1416x_pll); + static const struct imx_pll14xx_rate_table *imx_get_pll_settings( struct clk_pll14xx *pll, unsigned long rate) { diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h index 60f287046b9..0e1eaf03d41 100644 --- a/drivers/clk/imx/clk.h +++ b/drivers/clk/imx/clk.h @@ -41,6 +41,10 @@ struct imx_pll14xx_clk { int flags; }; +extern struct imx_pll14xx_clk imx_1416x_pll; +extern struct imx_pll14xx_clk imx_1443x_pll; +extern struct imx_pll14xx_clk imx_1443x_dram_pll; + struct clk *imx_clk_pll14xx(const char *name, const char *parent_name, void __iomem *base, const struct imx_pll14xx_clk *pll_clk); diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig index 94ff5401119..e03fcdd9c7e 100644 --- a/drivers/crypto/fsl/Kconfig +++ b/drivers/crypto/fsl/Kconfig @@ -2,6 +2,7 @@ config FSL_CAAM bool "Freescale Crypto Driver Support" select SHA_HW_ACCEL # hw_sha1() under drivers/crypto, and needed with SHA_HW_ACCEL + select MISC if DM imply SPL_CRYPTO if (ARM && SPL) imply CMD_HASH help @@ -11,7 +12,7 @@ config FSL_CAAM config CAAM_64BIT bool - default y if PHYS_64BIT && !ARCH_IMX8M + default y if PHYS_64BIT && !ARCH_IMX8M && !ARCH_IMX8 help Select Crypto driver for 64 bits CAAM version diff --git a/drivers/crypto/fsl/jr.c b/drivers/crypto/fsl/jr.c index 22b649219e8..1d951cf0a64 100644 --- a/drivers/crypto/fsl/jr.c +++ b/drivers/crypto/fsl/jr.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2008-2014 Freescale Semiconductor, Inc. - * Copyright 2018 NXP + * Copyright 2018, 2021 NXP * * Based on CAAM driver in drivers/crypto/caam in Linux */ @@ -11,7 +11,7 @@ #include <linux/kernel.h> #include <log.h> #include <malloc.h> -#include "fsl_sec.h" +#include <power-domain.h> #include "jr.h" #include "jobdesc.h" #include "desc_constr.h" @@ -21,7 +21,10 @@ #include <asm/cache.h> #include <asm/fsl_pamu.h> #endif +#include <dm.h> #include <dm/lists.h> +#include <dm/root.h> +#include <dm/device-internal.h> #include <linux/delay.h> #define CIRC_CNT(head, tail, size) (((head) - (tail)) & (size - 1)) @@ -35,20 +38,29 @@ uint32_t sec_offset[CONFIG_SYS_FSL_MAX_NUM_OF_SEC] = { #endif }; +#if CONFIG_IS_ENABLED(DM) +struct udevice *caam_dev; +#else #define SEC_ADDR(idx) \ (ulong)((CONFIG_SYS_FSL_SEC_ADDR + sec_offset[idx])) #define SEC_JR0_ADDR(idx) \ (ulong)(SEC_ADDR(idx) + \ (CONFIG_SYS_FSL_JR0_OFFSET - CONFIG_SYS_FSL_SEC_OFFSET)) +struct caam_regs caam_st; +#endif -struct jobring jr0[CONFIG_SYS_FSL_MAX_NUM_OF_SEC]; +static inline u32 jr_start_reg(u8 jrid) +{ + return (1 << jrid); +} -static inline void start_jr0(uint8_t sec_idx) +static inline void start_jr(struct caam_regs *caam) { - ccsr_sec_t *sec = (void *)SEC_ADDR(sec_idx); + ccsr_sec_t *sec = caam->sec; u32 ctpr_ms = sec_in32(&sec->ctpr_ms); u32 scfgr = sec_in32(&sec->scfgr); + u32 jrstart = jr_start_reg(caam->jrid); if (ctpr_ms & SEC_CTPR_MS_VIRT_EN_INCL) { /* VIRT_EN_INCL = 1 & VIRT_EN_POR = 1 or @@ -56,23 +68,16 @@ static inline void start_jr0(uint8_t sec_idx) */ if ((ctpr_ms & SEC_CTPR_MS_VIRT_EN_POR) || (scfgr & SEC_SCFGR_VIRT_EN)) - sec_out32(&sec->jrstartr, CONFIG_JRSTARTR_JR0); + sec_out32(&sec->jrstartr, jrstart); } else { /* VIRT_EN_INCL = 0 && VIRT_EN_POR_VALUE = 1 */ if (ctpr_ms & SEC_CTPR_MS_VIRT_EN_POR) - sec_out32(&sec->jrstartr, CONFIG_JRSTARTR_JR0); + sec_out32(&sec->jrstartr, jrstart); } } -static inline void jr_reset_liodn(uint8_t sec_idx) -{ - ccsr_sec_t *sec = (void *)SEC_ADDR(sec_idx); - sec_out32(&sec->jrliodnr[0].ls, 0); -} - -static inline void jr_disable_irq(uint8_t sec_idx) +static inline void jr_disable_irq(struct jr_regs *regs) { - struct jr_regs *regs = (struct jr_regs *)SEC_JR0_ADDR(sec_idx); uint32_t jrcfg = sec_in32(®s->jrcfg1); jrcfg = jrcfg | JR_INTMASK; @@ -80,10 +85,10 @@ static inline void jr_disable_irq(uint8_t sec_idx) sec_out32(®s->jrcfg1, jrcfg); } -static void jr_initregs(uint8_t sec_idx) +static void jr_initregs(uint8_t sec_idx, struct caam_regs *caam) { - struct jr_regs *regs = (struct jr_regs *)SEC_JR0_ADDR(sec_idx); - struct jobring *jr = &jr0[sec_idx]; + struct jr_regs *regs = caam->regs; + struct jobring *jr = &caam->jr[sec_idx]; caam_dma_addr_t ip_base = virt_to_phys((void *)jr->input_ring); caam_dma_addr_t op_base = virt_to_phys((void *)jr->output_ring); @@ -103,16 +108,18 @@ static void jr_initregs(uint8_t sec_idx) sec_out32(®s->irs, JR_SIZE); if (!jr->irq) - jr_disable_irq(sec_idx); + jr_disable_irq(regs); } -static int jr_init(uint8_t sec_idx) +static int jr_init(uint8_t sec_idx, struct caam_regs *caam) { - struct jobring *jr = &jr0[sec_idx]; - + struct jobring *jr = &caam->jr[sec_idx]; +#if CONFIG_IS_ENABLED(OF_CONTROL) + ofnode scu_node = ofnode_by_compatible(ofnode_null(), "fsl,imx8-mu"); +#endif memset(jr, 0, sizeof(struct jobring)); - jr->jq_id = DEFAULT_JR_ID; + jr->jq_id = caam->jrid; jr->irq = DEFAULT_IRQ; #ifdef CONFIG_FSL_CORENET @@ -134,53 +141,12 @@ static int jr_init(uint8_t sec_idx) memset(jr->input_ring, 0, JR_SIZE * sizeof(caam_dma_addr_t)); memset(jr->output_ring, 0, jr->op_size); - start_jr0(sec_idx); - - jr_initregs(sec_idx); - - return 0; -} - -static int jr_sw_cleanup(uint8_t sec_idx) -{ - struct jobring *jr = &jr0[sec_idx]; - - jr->head = 0; - jr->tail = 0; - jr->read_idx = 0; - jr->write_idx = 0; - memset(jr->info, 0, sizeof(jr->info)); - memset(jr->input_ring, 0, jr->size * sizeof(caam_dma_addr_t)); - memset(jr->output_ring, 0, jr->size * sizeof(struct op_ring)); - - return 0; -} - -static int jr_hw_reset(uint8_t sec_idx) -{ - struct jr_regs *regs = (struct jr_regs *)SEC_JR0_ADDR(sec_idx); - uint32_t timeout = 100000; - uint32_t jrint, jrcr; - - sec_out32(®s->jrcr, JRCR_RESET); - do { - jrint = sec_in32(®s->jrint); - } while (((jrint & JRINT_ERR_HALT_MASK) == - JRINT_ERR_HALT_INPROGRESS) && --timeout); - - jrint = sec_in32(®s->jrint); - if (((jrint & JRINT_ERR_HALT_MASK) != - JRINT_ERR_HALT_INPROGRESS) && timeout == 0) - return -1; - - timeout = 100000; - sec_out32(®s->jrcr, JRCR_RESET); - do { - jrcr = sec_in32(®s->jrcr); - } while ((jrcr & JRCR_RESET) && --timeout); +#if CONFIG_IS_ENABLED(OF_CONTROL) + if (!ofnode_valid(scu_node)) +#endif + start_jr(caam); - if (timeout == 0) - return -1; + jr_initregs(sec_idx, caam); return 0; } @@ -188,10 +154,10 @@ static int jr_hw_reset(uint8_t sec_idx) /* -1 --- error, can't enqueue -- no space available */ static int jr_enqueue(uint32_t *desc_addr, void (*callback)(uint32_t status, void *arg), - void *arg, uint8_t sec_idx) + void *arg, uint8_t sec_idx, struct caam_regs *caam) { - struct jr_regs *regs = (struct jr_regs *)SEC_JR0_ADDR(sec_idx); - struct jobring *jr = &jr0[sec_idx]; + struct jr_regs *regs = caam->regs; + struct jobring *jr = &caam->jr[sec_idx]; int head = jr->head; uint32_t desc_word; int length = desc_len(desc_addr); @@ -263,10 +229,10 @@ static int jr_enqueue(uint32_t *desc_addr, return 0; } -static int jr_dequeue(int sec_idx) +static int jr_dequeue(int sec_idx, struct caam_regs *caam) { - struct jr_regs *regs = (struct jr_regs *)SEC_JR0_ADDR(sec_idx); - struct jobring *jr = &jr0[sec_idx]; + struct jr_regs *regs = caam->regs; + struct jobring *jr = &caam->jr[sec_idx]; int head = jr->head; int tail = jr->tail; int idx, i, found; @@ -349,14 +315,18 @@ static void desc_done(uint32_t status, void *arg) { struct result *x = arg; x->status = status; -#ifndef CONFIG_SPL_BUILD caam_jr_strstatus(status); -#endif x->done = 1; } static inline int run_descriptor_jr_idx(uint32_t *desc, uint8_t sec_idx) { + struct caam_regs *caam; +#if CONFIG_IS_ENABLED(DM) + caam = dev_get_priv(caam_dev); +#else + caam = &caam_st; +#endif unsigned long long timeval = 0; unsigned long long timeout = CONFIG_USEC_DEQ_TIMEOUT; struct result op; @@ -364,7 +334,7 @@ static inline int run_descriptor_jr_idx(uint32_t *desc, uint8_t sec_idx) memset(&op, 0, sizeof(op)); - ret = jr_enqueue(desc, desc_done, &op, sec_idx); + ret = jr_enqueue(desc, desc_done, &op, sec_idx, caam); if (ret) { debug("Error in SEC enq\n"); ret = JQ_ENQ_ERR; @@ -375,7 +345,7 @@ static inline int run_descriptor_jr_idx(uint32_t *desc, uint8_t sec_idx) udelay(1); timeval += 1; - ret = jr_dequeue(sec_idx); + ret = jr_dequeue(sec_idx, caam); if (ret) { debug("Error in SEC deq\n"); ret = JQ_DEQ_ERR; @@ -402,13 +372,62 @@ int run_descriptor_jr(uint32_t *desc) return run_descriptor_jr_idx(desc, 0); } +static int jr_sw_cleanup(uint8_t sec_idx, struct caam_regs *caam) +{ + struct jobring *jr = &caam->jr[sec_idx]; + + jr->head = 0; + jr->tail = 0; + jr->read_idx = 0; + jr->write_idx = 0; + memset(jr->info, 0, sizeof(jr->info)); + memset(jr->input_ring, 0, jr->size * sizeof(caam_dma_addr_t)); + memset(jr->output_ring, 0, jr->size * sizeof(struct op_ring)); + + return 0; +} + +static int jr_hw_reset(struct jr_regs *regs) +{ + uint32_t timeout = 100000; + uint32_t jrint, jrcr; + + sec_out32(®s->jrcr, JRCR_RESET); + do { + jrint = sec_in32(®s->jrint); + } while (((jrint & JRINT_ERR_HALT_MASK) == + JRINT_ERR_HALT_INPROGRESS) && --timeout); + + jrint = sec_in32(®s->jrint); + if (((jrint & JRINT_ERR_HALT_MASK) != + JRINT_ERR_HALT_INPROGRESS) && timeout == 0) + return -1; + + timeout = 100000; + sec_out32(®s->jrcr, JRCR_RESET); + do { + jrcr = sec_in32(®s->jrcr); + } while ((jrcr & JRCR_RESET) && --timeout); + + if (timeout == 0) + return -1; + + return 0; +} + static inline int jr_reset_sec(uint8_t sec_idx) { - if (jr_hw_reset(sec_idx) < 0) + struct caam_regs *caam; +#if CONFIG_IS_ENABLED(DM) + caam = dev_get_priv(caam_dev); +#else + caam = &caam_st; +#endif + if (jr_hw_reset(caam->regs) < 0) return -1; /* Clean up the jobring structure maintained by software */ - jr_sw_cleanup(sec_idx); + jr_sw_cleanup(sec_idx, caam); return 0; } @@ -418,9 +437,15 @@ int jr_reset(void) return jr_reset_sec(0); } -static inline int sec_reset_idx(uint8_t sec_idx) +int sec_reset(void) { - ccsr_sec_t *sec = (void *)SEC_ADDR(sec_idx); + struct caam_regs *caam; +#if CONFIG_IS_ENABLED(DM) + caam = dev_get_priv(caam_dev); +#else + caam = &caam_st; +#endif + ccsr_sec_t *sec = caam->sec; uint32_t mcfgr = sec_in32(&sec->mcfgr); uint32_t timeout = 100000; @@ -446,11 +471,7 @@ static inline int sec_reset_idx(uint8_t sec_idx) return 0; } -int sec_reset(void) -{ - return sec_reset_idx(0); -} -#ifndef CONFIG_SPL_BUILD + static int deinstantiate_rng(u8 sec_idx, int state_handle_mask) { u32 *desc; @@ -496,12 +517,11 @@ static int deinstantiate_rng(u8 sec_idx, int state_handle_mask) return ret; } -static int instantiate_rng(u8 sec_idx, int gen_sk) +static int instantiate_rng(uint8_t sec_idx, ccsr_sec_t *sec, int gen_sk) { u32 *desc; u32 rdsta_val; int ret = 0, sh_idx, size; - ccsr_sec_t __iomem *sec = (ccsr_sec_t __iomem *)SEC_ADDR(sec_idx); struct rng4tst __iomem *rng = (struct rng4tst __iomem *)&sec->rng; @@ -554,9 +574,8 @@ static int instantiate_rng(u8 sec_idx, int gen_sk) return ret; } -static u8 get_rng_vid(uint8_t sec_idx) +static u8 get_rng_vid(ccsr_sec_t *sec) { - ccsr_sec_t *sec = (void *)SEC_ADDR(sec_idx); u8 vid; if (caam_get_era() < 10) { @@ -574,9 +593,8 @@ static u8 get_rng_vid(uint8_t sec_idx) * By default, the TRNG runs for 200 clocks per sample; * 1200 clocks per sample generates better entropy. */ -static void kick_trng(int ent_delay, uint8_t sec_idx) +static void kick_trng(int ent_delay, ccsr_sec_t *sec) { - ccsr_sec_t __iomem *sec = (ccsr_sec_t __iomem *)SEC_ADDR(sec_idx); struct rng4tst __iomem *rng = (struct rng4tst __iomem *)&sec->rng; u32 val; @@ -603,10 +621,9 @@ static void kick_trng(int ent_delay, uint8_t sec_idx) sec_clrbits32(&rng->rtmctl, RTMCTL_PRGM); } -static int rng_init(uint8_t sec_idx) +static int rng_init(uint8_t sec_idx, ccsr_sec_t *sec) { int ret, gen_sk, ent_delay = RTSDCTL_ENT_DLY_MIN; - ccsr_sec_t __iomem *sec = (ccsr_sec_t __iomem *)SEC_ADDR(sec_idx); struct rng4tst __iomem *rng = (struct rng4tst __iomem *)&sec->rng; u32 inst_handles; @@ -624,7 +641,7 @@ static int rng_init(uint8_t sec_idx) * the TRNG parameters. */ if (!inst_handles) { - kick_trng(ent_delay, sec_idx); + kick_trng(ent_delay, sec); ent_delay += 400; } /* @@ -634,7 +651,7 @@ static int rng_init(uint8_t sec_idx) * interval, leading to a sucessful initialization of * the RNG. */ - ret = instantiate_rng(sec_idx, gen_sk); + ret = instantiate_rng(sec_idx, sec, gen_sk); } while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); if (ret) { printf("SEC%u: Failed to instantiate RNG\n", sec_idx); @@ -646,13 +663,35 @@ static int rng_init(uint8_t sec_idx) return ret; } -#endif + int sec_init_idx(uint8_t sec_idx) { - ccsr_sec_t *sec = (void *)SEC_ADDR(sec_idx); - uint32_t mcr = sec_in32(&sec->mcfgr); int ret = 0; + struct caam_regs *caam; +#if CONFIG_IS_ENABLED(DM) + if (!caam_dev) { + printf("caam_jr: caam not found\n"); + return -1; + } + caam = dev_get_priv(caam_dev); +#else + caam_st.sec = (void *)SEC_ADDR(sec_idx); + caam_st.regs = (struct jr_regs *)SEC_JR0_ADDR(sec_idx); + caam_st.jrid = 0; + caam = &caam_st; +#endif +#if CONFIG_IS_ENABLED(OF_CONTROL) + ofnode scu_node = ofnode_by_compatible(ofnode_null(), "fsl,imx8-mu"); + + if (ofnode_valid(scu_node)) + goto init; +#endif + ccsr_sec_t *sec = caam->sec; + uint32_t mcr = sec_in32(&sec->mcfgr); +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_IMX8M) + uint32_t jrdid_ms = 0; +#endif #ifdef CONFIG_FSL_CORENET uint32_t liodnr; uint32_t liodn_ns; @@ -682,6 +721,11 @@ int sec_init_idx(uint8_t sec_idx) mcr |= (1 << MCFGR_PS_SHIFT); #endif sec_out32(&sec->mcfgr, mcr); +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_IMX8M) + jrdid_ms = JRDID_MS_TZ_OWN | JRDID_MS_PRIM_TZ | JRDID_MS_PRIM_DID; + sec_out32(&sec->jrliodnr[caam->jrid].ms, jrdid_ms); +#endif + jr_reset(); #ifdef CONFIG_FSL_CORENET #ifdef CONFIG_SPL_BUILD @@ -693,24 +737,30 @@ int sec_init_idx(uint8_t sec_idx) liodn_ns = CONFIG_SPL_JR0_LIODN_NS & JRNSLIODN_MASK; liodn_s = CONFIG_SPL_JR0_LIODN_S & JRSLIODN_MASK; - liodnr = sec_in32(&sec->jrliodnr[0].ls) & + liodnr = sec_in32(&sec->jrliodnr[caam->jrid].ls) & ~(JRNSLIODN_MASK | JRSLIODN_MASK); liodnr = liodnr | (liodn_ns << JRNSLIODN_SHIFT) | (liodn_s << JRSLIODN_SHIFT); - sec_out32(&sec->jrliodnr[0].ls, liodnr); + sec_out32(&sec->jrliodnr[caam->jrid].ls, liodnr); #else - liodnr = sec_in32(&sec->jrliodnr[0].ls); + liodnr = sec_in32(&sec->jrliodnr[caam->jrid].ls); liodn_ns = (liodnr & JRNSLIODN_MASK) >> JRNSLIODN_SHIFT; liodn_s = (liodnr & JRSLIODN_MASK) >> JRSLIODN_SHIFT; #endif #endif - - ret = jr_init(sec_idx); +#if CONFIG_IS_ENABLED(OF_CONTROL) +init: +#endif + ret = jr_init(sec_idx, caam); if (ret < 0) { printf("SEC%u: initialization failed\n", sec_idx); return -1; } +#if CONFIG_IS_ENABLED(OF_CONTROL) + if (ofnode_valid(scu_node)) + return ret; +#endif #ifdef CONFIG_FSL_CORENET ret = sec_config_pamu_table(liodn_ns, liodn_s); @@ -719,9 +769,9 @@ int sec_init_idx(uint8_t sec_idx) pamu_enable(); #endif -#ifndef CONFIG_SPL_BUILD - if (get_rng_vid(sec_idx) >= 4) { - if (rng_init(sec_idx) < 0) { + + if (get_rng_vid(caam->sec) >= 4) { + if (rng_init(sec_idx, caam->sec) < 0) { printf("SEC%u: RNG instantiation failed\n", sec_idx); return -1; } @@ -735,7 +785,6 @@ int sec_init_idx(uint8_t sec_idx) printf("SEC%u: RNG instantiated\n", sec_idx); } -#endif return ret; } @@ -743,3 +792,98 @@ int sec_init(void) { return sec_init_idx(0); } + +#if CONFIG_IS_ENABLED(DM) +static int jr_power_on(ofnode node) +{ +#if CONFIG_IS_ENABLED(POWER_DOMAIN) + struct udevice __maybe_unused jr_dev; + struct power_domain pd; + + dev_set_ofnode(&jr_dev, node); + + /* Power on Job Ring before access it */ + if (!power_domain_get(&jr_dev, &pd)) { + if (power_domain_on(&pd)) + return -EINVAL; + } +#endif + return 0; +} + +static int caam_jr_ioctl(struct udevice *dev, unsigned long request, void *buf) +{ + if (request != CAAM_JR_RUN_DESC) + return -ENOSYS; + + return run_descriptor_jr(buf); +} + +static int caam_jr_probe(struct udevice *dev) +{ + struct caam_regs *caam = dev_get_priv(dev); + fdt_addr_t addr; + ofnode node, scu_node; + unsigned int jr_node = 0; + + caam_dev = dev; + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) { + printf("caam_jr: crypto not found\n"); + return -EINVAL; + } + caam->sec = (ccsr_sec_t *)(uintptr_t)addr; + caam->regs = (struct jr_regs *)caam->sec; + + /* Check for enabled job ring node */ + ofnode_for_each_subnode(node, dev_ofnode(dev)) { + if (!ofnode_is_available(node)) + continue; + + jr_node = ofnode_read_u32_default(node, "reg", -1); + if (jr_node > 0) { + caam->regs = (struct jr_regs *)((ulong)caam->sec + jr_node); + while (!(jr_node & 0x0F)) + jr_node = jr_node >> 4; + + caam->jrid = jr_node - 1; + scu_node = ofnode_by_compatible(ofnode_null(), "fsl,imx8-mu"); + if (ofnode_valid(scu_node)) { + if (jr_power_on(node)) + return -EINVAL; + } + break; + } + } + + if (sec_init()) + printf("\nsec_init failed!\n"); + + return 0; +} + +static int caam_jr_bind(struct udevice *dev) +{ + return 0; +} + +static const struct misc_ops caam_jr_ops = { + .ioctl = caam_jr_ioctl, +}; + +static const struct udevice_id caam_jr_match[] = { + { .compatible = "fsl,sec-v4.0" }, + { } +}; + +U_BOOT_DRIVER(caam_jr) = { + .name = "caam_jr", + .id = UCLASS_MISC, + .of_match = caam_jr_match, + .ops = &caam_jr_ops, + .bind = caam_jr_bind, + .probe = caam_jr_probe, + .priv_auto = sizeof(struct caam_regs), +}; +#endif diff --git a/drivers/crypto/fsl/jr.h b/drivers/crypto/fsl/jr.h index 1047aa772c4..3eb7be79da4 100644 --- a/drivers/crypto/fsl/jr.h +++ b/drivers/crypto/fsl/jr.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright 2008-2014 Freescale Semiconductor, Inc. + * Copyright 2021 NXP * */ @@ -8,7 +9,9 @@ #define __JR_H #include <linux/compiler.h> +#include "fsl_sec.h" #include "type.h" +#include <misc.h> #define JR_SIZE 4 /* Timeout currently defined as 10 sec */ @@ -35,12 +38,21 @@ #define JRSLIODN_SHIFT 0 #define JRSLIODN_MASK 0x00000fff -#define JQ_DEQ_ERR -1 -#define JQ_DEQ_TO_ERR -2 -#define JQ_ENQ_ERR -3 +#define JRDID_MS_PRIM_DID BIT(0) +#define JRDID_MS_PRIM_TZ BIT(4) +#define JRDID_MS_TZ_OWN BIT(15) + +#define JQ_DEQ_ERR (-1) +#define JQ_DEQ_TO_ERR (-2) +#define JQ_ENQ_ERR (-3) #define RNG4_MAX_HANDLES 2 +enum { + /* Run caam jobring descriptor(in buf) */ + CAAM_JR_RUN_DESC, +}; + struct op_ring { caam_dma_addr_t desc; uint32_t status; @@ -102,6 +114,19 @@ struct result { uint32_t status; }; +/* + * struct caam_regs - CAAM initialization register interface + * + * Interface to caam memory map, jobring register, jobring storage. + */ +struct caam_regs { + ccsr_sec_t *sec; /*caam initialization registers*/ + struct jr_regs *regs; /*jobring configuration registers*/ + u8 jrid; /*id to identify a jobring*/ + /*Private sub-storage for a single JobR*/ + struct jobring jr[CONFIG_SYS_FSL_MAX_NUM_OF_SEC]; +}; + void caam_jr_strstatus(u32 status); int run_descriptor_jr(uint32_t *desc); diff --git a/drivers/ddr/imx/imx8m/ddrphy_utils.c b/drivers/ddr/imx/imx8m/ddrphy_utils.c index 0f8baefb1f8..a54449e5f14 100644 --- a/drivers/ddr/imx/imx8m/ddrphy_utils.c +++ b/drivers/ddr/imx/imx8m/ddrphy_utils.c @@ -117,6 +117,10 @@ void ddrphy_init_set_dfi_clk(unsigned int drate) dram_pll_init(MHZ(1000)); dram_disable_bypass(); break; + case 3732: + dram_pll_init(MHZ(933)); + dram_disable_bypass(); + break; case 3200: dram_pll_init(MHZ(800)); dram_disable_bypass(); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 7029bb7b5c5..10fd601278e 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -46,6 +46,14 @@ config ATSHA204A CryptoAuthentication module found for example on the Turris Omnia board. +config GATEWORKS_SC + bool "Gateworks System Controller Support" + depends on MISC + help + Enable access for the Gateworks System Controller used on Gateworks + boards to provide a boot watchdog, power control, temperature monitor, + voltage ADCs, and EEPROM. + config ROCKCHIP_EFUSE bool "Rockchip e-fuse support" depends on MISC diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index f22eff601a1..6150d01e884 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_FSL_IIM) += fsl_iim.o obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o obj-$(CONFIG_$(SPL_)FS_LOADER) += fs_loader.o +obj-$(CONFIG_GATEWORKS_SC) += gsc.o obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o diff --git a/drivers/misc/gsc.c b/drivers/misc/gsc.c new file mode 100644 index 00000000000..ec24ca807b0 --- /dev/null +++ b/drivers/misc/gsc.c @@ -0,0 +1,633 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2022 Gateworks Corporation + */ + +#include <command.h> +#include <gsc.h> +#include <i2c.h> +#include <rtc.h> +#include <asm/unaligned.h> +#include <linux/delay.h> +#include <dm/device.h> +#include <dm/device-internal.h> +#include <dm/ofnode.h> +#include <dm/read.h> + +#define GSC_BUSNO 0 +#define GSC_SC_ADDR 0x20 +#define GSC_HWMON_ADDR 0x29 +#define GSC_RTC_ADDR 0x68 + +/* System Controller registers */ +enum { + GSC_SC_CTRL0 = 0, + GSC_SC_CTRL1 = 1, + GSC_SC_TIME = 2, + GSC_SC_TIME_ADD = 6, + GSC_SC_STATUS = 10, + GSC_SC_FWCRC = 12, + GSC_SC_FWVER = 14, + GSC_SC_WP = 15, + GSC_SC_RST_CAUSE = 16, + GSC_SC_THERM_PROTECT = 19, +}; + +/* System Controller Control1 bits */ +enum { + GSC_SC_CTRL1_SLEEP_EN = 0, /* 1 = enable sleep */ + GSC_SC_CTRL1_SLEEP_ACTIVATE = 1, /* 1 = activate sleep */ + GSC_SC_CTRL1_SLEEP_ADD = 2, /* 1 = latch and add sleep time */ + GSC_SC_CTRL1_SLEEP_NOWAKEPB = 3, /* 1 = do not wake on sleep on button press */ + GSC_SC_CTRL1_WDTIME = 4, /* 1 = 60s timeout, 0 = 30s timeout */ + GSC_SC_CTRL1_WDEN = 5, /* 1 = enable, 0 = disable */ + GSC_SC_CTRL1_BOOT_CHK = 6, /* 1 = enable alt boot check */ + GSC_SC_CTRL1_WDDIS = 7, /* 1 = disable boot watchdog */ +}; + +/* System Controller Interrupt bits */ +enum { + GSC_SC_IRQ_PB = 0, /* Pushbutton switch */ + GSC_SC_IRQ_SECURE = 1, /* Secure Key erase operation complete */ + GSC_SC_IRQ_EEPROM_WP = 2, /* EEPROM write violation */ + GSC_SC_IRQ_GPIO = 4, /* GPIO change */ + GSC_SC_IRQ_TAMPER = 5, /* Tamper detect */ + GSC_SC_IRQ_WATCHDOG = 6, /* Watchdog trip */ + GSC_SC_IRQ_PBLONG = 7, /* Pushbutton long hold */ +}; + +/* System Controller WP bits */ +enum { + GSC_SC_WP_ALL = 0, /* Write Protect All EEPROM regions */ + GSC_SC_WP_BOARDINFO = 1, /* Write Protect Board Info region */ +}; + +/* System Controller Reset Cause */ +enum { + GSC_SC_RST_CAUSE_VIN = 0, + GSC_SC_RST_CAUSE_PB = 1, + GSC_SC_RST_CAUSE_WDT = 2, + GSC_SC_RST_CAUSE_CPU = 3, + GSC_SC_RST_CAUSE_TEMP_LOCAL = 4, + GSC_SC_RST_CAUSE_TEMP_REMOTE = 5, + GSC_SC_RST_CAUSE_SLEEP = 6, + GSC_SC_RST_CAUSE_BOOT_WDT = 7, + GSC_SC_RST_CAUSE_BOOT_WDT_MAN = 8, + GSC_SC_RST_CAUSE_SOFT_PWR = 9, + GSC_SC_RST_CAUSE_MAX = 10, +}; + +#if (IS_ENABLED(CONFIG_DM_I2C)) + +struct gsc_priv { + int gscver; + int fwver; + int fwcrc; + struct udevice *hwmon; + struct udevice *rtc; +}; + +/* + * GSCv2 will fail to ACK an I2C transaction if it is busy, which can occur + * during its 1HZ timer tick while reading ADC's. When this does occur, + * it will never be busy longer than 2 back-to-back transfers so retry 3 times. + */ +static int gsc_i2c_read(struct udevice *dev, uint addr, u8 *buf, int len) +{ + struct gsc_priv *priv = dev_get_priv(dev); + int retry = (priv->gscver == 3) ? 1 : 3; + int n = 0; + int ret; + + while (n++ < retry) { + ret = dm_i2c_read(dev, addr, buf, len); + if (!ret) + break; + if (ret != -EREMOTEIO) + break; + mdelay(10); + } + return ret; +} + +static int gsc_i2c_write(struct udevice *dev, uint addr, const u8 *buf, int len) +{ + struct gsc_priv *priv = dev_get_priv(dev); + int retry = (priv->gscver == 3) ? 1 : 3; + int n = 0; + int ret; + + while (n++ < retry) { + ret = dm_i2c_write(dev, addr, buf, len); + if (!ret) + break; + if (ret != -EREMOTEIO) + break; + mdelay(10); + } + return ret; +} + +static struct udevice *gsc_get_dev(int busno, int slave) +{ + struct udevice *dev, *bus; + int ret; + + ret = uclass_get_device_by_seq(UCLASS_I2C, busno, &bus); + if (ret) + return NULL; + ret = dm_i2c_probe(bus, slave, 0, &dev); + if (ret) + return NULL; + + return dev; +} + +static int gsc_thermal_get_info(struct udevice *dev, u8 *outreg, int *tmax, bool *enable) +{ + struct gsc_priv *priv = dev_get_priv(dev); + int ret; + u8 reg; + + if (priv->gscver > 2 && priv->fwver > 52) { + ret = gsc_i2c_read(dev, GSC_SC_THERM_PROTECT, ®, 1); + if (!ret) { + if (outreg) + *outreg = reg; + if (tmax) { + *tmax = ((reg & 0xf8) >> 3) * 2; + if (*tmax) + *tmax += 70; + else + *tmax = 120; + } + if (enable) + *enable = reg & 1; + } + } else { + ret = -ENODEV; + } + + return ret; +} + +static int gsc_thermal_get_temp(struct udevice *dev) +{ + struct gsc_priv *priv = dev_get_priv(dev); + u32 reg, mode, val; + const char *label; + ofnode node; + u8 buf[2]; + + ofnode_for_each_subnode(node, dev_read_subnode(dev, "adc")) { + if (ofnode_read_u32(node, "reg", ®)) + reg = -1; + if (ofnode_read_u32(node, "gw,mode", &mode)) + mode = -1; + label = ofnode_read_string(node, "label"); + + if ((reg == -1) || (mode == -1) || !label) + continue; + + if (mode != 0 || strcmp(label, "temp")) + continue; + + memset(buf, 0, sizeof(buf)); + if (!gsc_i2c_read(priv->hwmon, reg, buf, sizeof(buf))) { + val = buf[0] | buf[1] << 8; + if (val > 0x8000) + val -= 0xffff; + return val; + } + } + + return 0; +} + +static void gsc_thermal_info(struct udevice *dev) +{ + struct gsc_priv *priv = dev_get_priv(dev); + + switch (priv->gscver) { + case 2: + printf("board_temp:%dC ", gsc_thermal_get_temp(dev) / 10); + break; + case 3: + if (priv->fwver > 52) { + bool enabled; + int tmax; + + if (!gsc_thermal_get_info(dev, NULL, &tmax, &enabled)) { + puts("Thermal protection:"); + if (enabled) + printf("enabled at %dC ", tmax); + else + puts("disabled "); + } + } + break; + } +} + +static void gsc_reset_info(struct udevice *dev) +{ + struct gsc_priv *priv = dev_get_priv(dev); + static const char * const names[] = { + "VIN", + "PB", + "WDT", + "CPU", + "TEMP_L", + "TEMP_R", + "SLEEP", + "BOOT_WDT1", + "BOOT_WDT2", + "SOFT_PWR", + }; + u8 reg; + + /* reset cause */ + switch (priv->gscver) { + case 2: + if (!gsc_i2c_read(dev, GSC_SC_STATUS, ®, 1)) { + if (reg & BIT(GSC_SC_IRQ_WATCHDOG)) { + puts("RST:WDT"); + reg &= ~BIT(GSC_SC_IRQ_WATCHDOG); + gsc_i2c_write(dev, GSC_SC_STATUS, ®, 1); + } else { + puts("RST:VIN"); + } + printf(" WDT:%sabled ", + (reg & BIT(GSC_SC_CTRL1_WDEN)) ? "en" : "dis"); + } + break; + case 3: + if (priv->fwver > 52 && + !gsc_i2c_read(dev, GSC_SC_RST_CAUSE, ®, 1)) { + puts("RST:"); + if (reg < ARRAY_SIZE(names)) + printf("%s ", names[reg]); + else + printf("0x%02x ", reg); + } + break; + } +} + +/* display hardware monitor ADC channels */ +static int gsc_hwmon(struct udevice *dev) +{ + struct gsc_priv *priv = dev_get_priv(dev); + u32 reg, mode, val, offset; + const char *label; + ofnode node; + u8 buf[2]; + u32 r[2]; + int ret; + + /* iterate over hwmon nodes */ + ofnode_for_each_subnode(node, dev_read_subnode(dev, "adc")) { + if (ofnode_read_u32(node, "reg", ®)) + reg = -1; + if (ofnode_read_u32(node, "gw,mode", &mode)) + mode = -1; + label = ofnode_read_string(node, "label"); + if ((reg == -1) || (mode == -1) || !label) + continue; + + memset(buf, 0, sizeof(buf)); + ret = gsc_i2c_read(priv->hwmon, reg, buf, sizeof(buf)); + if (ret) { + printf("i2c error: %d\n", ret); + continue; + } + val = buf[0] | buf[1] << 8; + + switch (mode) { + case 0: /* temperature (C*10) */ + if (val > 0x8000) + val -= 0xffff; + printf("%-8s: %d.%ldC\n", label, val / 10, abs(val % 10)); + break; + case 1: /* prescaled voltage */ + if (val != 0xffff) + printf("%-8s: %d.%03dV\n", label, val / 1000, val % 1000); + break; + case 2: /* scaled based on ref volt and resolution */ + val *= 2500; + val /= 1 << 12; + + /* apply pre-scaler voltage divider */ + if (!ofnode_read_u32_index(node, "gw,voltage-divider-ohms", 0, &r[0]) && + !ofnode_read_u32_index(node, "gw,voltage-divider-ohms", 1, &r[1]) && + r[0] && r[1]) { + val *= (r[0] + r[1]); + val /= r[1]; + } + + /* adjust by offset */ + val += (offset / 1000); + + printf("%-8s: %d.%03dV\n", label, val / 1000, val % 1000); + break; + } + } + + return 0; +} + +static int gsc_banner(struct udevice *dev) +{ + struct gsc_priv *priv = dev_get_priv(dev); + + /* banner */ + printf("GSCv%d : v%d 0x%04x ", priv->gscver, priv->fwver, priv->fwcrc); + gsc_reset_info(dev); + gsc_thermal_info(dev); + puts("\n"); + + /* Display RTC */ + if (priv->rtc) { + u8 buf[4]; + time_t timestamp; + struct rtc_time tm; + + if (!gsc_i2c_read(priv->rtc, 0, buf, 4)) { + timestamp = get_unaligned_le32(buf); + rtc_to_tm(timestamp, &tm); + printf("RTC : %4d-%02d-%02d %2d:%02d:%02d UTC\n", + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + } + } + + return 0; +} + +static int gsc_probe(struct udevice *dev) +{ + struct gsc_priv *priv = dev_get_priv(dev); + u8 buf[32]; + int ret; + + ret = gsc_i2c_read(dev, 0, buf, sizeof(buf)); + if (ret) + return ret; + + /* + * GSC chip version: + * GSCv2 has 16 registers (which overlap) + * GSCv3 has 32 registers + */ + priv->gscver = memcmp(buf, buf + 16, 16) ? 3 : 2; + priv->fwver = buf[GSC_SC_FWVER]; + priv->fwcrc = buf[GSC_SC_FWCRC] | buf[GSC_SC_FWCRC + 1] << 8; + priv->hwmon = gsc_get_dev(GSC_BUSNO, GSC_HWMON_ADDR); + if (priv->hwmon) + dev_set_priv(priv->hwmon, priv); + priv->rtc = gsc_get_dev(GSC_BUSNO, GSC_RTC_ADDR); + if (priv->rtc) + dev_set_priv(priv->rtc, priv); + +#ifdef CONFIG_SPL_BUILD + gsc_banner(dev); +#endif + + return 0; +}; + +static const struct udevice_id gsc_ids[] = { + { .compatible = "gw,gsc", }, + { } +}; + +U_BOOT_DRIVER(gsc) = { + .name = "gsc", + .id = UCLASS_MISC, + .of_match = gsc_ids, + .probe = gsc_probe, + .priv_auto = sizeof(struct gsc_priv), + .flags = DM_FLAG_PRE_RELOC, +}; + +static int gsc_sleep(struct udevice *dev, unsigned long secs) +{ + u8 regs[4]; + int ret; + + printf("GSC Sleeping for %ld seconds\n", secs); + put_unaligned_le32(secs, regs); + ret = gsc_i2c_write(dev, GSC_SC_TIME_ADD, regs, sizeof(regs)); + if (ret) + goto err; + ret = gsc_i2c_read(dev, GSC_SC_CTRL1, regs, 1); + if (ret) + goto err; + regs[0] |= BIT(GSC_SC_CTRL1_SLEEP_ADD); + ret = gsc_i2c_write(dev, GSC_SC_CTRL1, regs, 1); + if (ret) + goto err; + regs[0] &= ~BIT(GSC_SC_CTRL1_SLEEP_ADD); + regs[0] |= BIT(GSC_SC_CTRL1_SLEEP_EN) | BIT(GSC_SC_CTRL1_SLEEP_ACTIVATE); + ret = gsc_i2c_write(dev, GSC_SC_CTRL1, regs, 1); + if (ret) + goto err; + + return 0; + +err: + printf("i2c error: %d\n", ret); + return ret; +} + +static int gsc_wd_disable(struct udevice *dev) +{ + int ret; + u8 reg; + + ret = gsc_i2c_read(dev, GSC_SC_CTRL1, ®, 1); + if (ret) + goto err; + reg |= BIT(GSC_SC_CTRL1_WDDIS); + reg &= ~BIT(GSC_SC_CTRL1_BOOT_CHK); + ret = gsc_i2c_write(dev, GSC_SC_CTRL1, ®, 1); + if (ret) + goto err; + puts("GSC : boot watchdog disabled\n"); + + return 0; + +err: + puts("i2c error"); + return ret; +} + +static int gsc_thermal(struct udevice *dev, const char *cmd, const char *val) +{ + struct gsc_priv *priv = dev_get_priv(dev); + int ret, tmax; + bool enabled; + u8 reg; + + if (priv->gscver < 3 || priv->fwver < 53) + return -EINVAL; + ret = gsc_thermal_get_info(dev, ®, &tmax, &enabled); + if (ret) + return ret; + if (cmd && !strcmp(cmd, "enable")) { + if (val && *val) { + tmax = clamp((int)simple_strtoul(val, NULL, 0), 72, 122); + reg &= ~0xf8; + reg |= ((tmax - 70) / 2) << 3; + } + reg |= BIT(0); + gsc_i2c_write(dev, GSC_SC_THERM_PROTECT, ®, 1); + } else if (cmd && !strcmp(cmd, "disable")) { + reg &= ~BIT(0); + gsc_i2c_write(dev, GSC_SC_THERM_PROTECT, ®, 1); + } else if (cmd) { + return -EINVAL; + } + + /* show status */ + gsc_thermal_info(dev); + puts("\n"); + + return 0; +} + +/* override in board files to display additional board EEPROM info */ +__weak void board_gsc_info(void) +{ +} + +static void gsc_info(struct udevice *dev) +{ + gsc_banner(dev); + board_gsc_info(); +} + +static int do_gsc(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + struct udevice *dev; + int ret; + + /* get/probe driver */ + ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(gsc), &dev); + if (ret) + return CMD_RET_USAGE; + if (argc < 2) { + gsc_info(dev); + return CMD_RET_SUCCESS; + } else if (strcasecmp(argv[1], "sleep") == 0) { + if (argc < 3) + return CMD_RET_USAGE; + if (!gsc_sleep(dev, dectoul(argv[2], NULL))) + return CMD_RET_SUCCESS; + } else if (strcasecmp(argv[1], "hwmon") == 0) { + if (!gsc_hwmon(dev)) + return CMD_RET_SUCCESS; + } else if (strcasecmp(argv[1], "wd-disable") == 0) { + if (!gsc_wd_disable(dev)) + return CMD_RET_SUCCESS; + } else if (strcasecmp(argv[1], "thermal") == 0) { + char *cmd, *val; + + cmd = (argc > 2) ? argv[2] : NULL; + val = (argc > 3) ? argv[3] : NULL; + if (!gsc_thermal(dev, cmd, val)) + return CMD_RET_SUCCESS; + } + + return CMD_RET_USAGE; +} + +U_BOOT_CMD(gsc, 4, 1, do_gsc, "Gateworks System Controller", + "[sleep <secs>]|[hwmon]|[wd-disable][thermal [disable|enable [temp]]]\n"); + +/* disable boot watchdog - useful for an SPL that wants to use falcon mode */ +int gsc_boot_wd_disable(void) +{ + struct udevice *dev; + int ret; + + /* get/probe driver */ + ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(gsc), &dev); + if (!ret) + ret = gsc_wd_disable(dev); + + return ret; +} + +# else + +/* + * GSCv2 will fail to ACK an I2C transaction if it is busy, which can occur + * during its 1HZ timer tick while reading ADC's. When this does occur, + * it will never be busy longer than 2 back-to-back transfers so retry 3 times. + */ +static int gsc_i2c_read(uint chip, uint addr, u8 *buf, int len) +{ + int retry = 3; + int n = 0; + int ret; + + while (n++ < retry) { + ret = i2c_read(chip, addr, 1, buf, len); + if (!ret) + break; + if (ret != -EREMOTEIO) + break; +printf("%s 0x%02x retry %d\n", __func__, addr, n); + mdelay(10); + } + return ret; +} + +static int gsc_i2c_write(uint chip, uint addr, u8 *buf, int len) +{ + int retry = 3; + int n = 0; + int ret; + + while (n++ < retry) { + ret = i2c_write(chip, addr, 1, buf, len); + if (!ret) + break; + if (ret != -EREMOTEIO) + break; +printf("%s 0x%02x retry %d\n", __func__, addr, n); + mdelay(10); + } + return ret; +} + +/* disable boot watchdog - useful for an SPL that wants to use falcon mode */ +int gsc_boot_wd_disable(void) +{ + u8 buf[32]; + int ret; + + i2c_set_bus_num(GSC_BUSNO); + ret = gsc_i2c_read(GSC_SC_ADDR, 0, buf, sizeof(buf)); + if (!ret) { + buf[GSC_SC_CTRL1] |= BIT(GSC_SC_CTRL1_WDDIS); + ret = gsc_i2c_write(GSC_SC_ADDR, GSC_SC_CTRL1, &buf[GSC_SC_CTRL1], 1); + printf("GSCv%d: v%d 0x%04x ", + memcmp(buf, buf + 16, 16) ? 3 : 2, + buf[GSC_SC_FWVER], + buf[GSC_SC_FWCRC] | buf[GSC_SC_FWCRC + 1] << 8); + if (buf[GSC_SC_STATUS] & BIT(GSC_SC_IRQ_WATCHDOG)) { + puts("RST:WDT "); + buf[GSC_SC_STATUS] &= ~BIT(GSC_SC_IRQ_WATCHDOG); + gsc_i2c_write(GSC_SC_ADDR, GSC_SC_STATUS, &buf[GSC_SC_STATUS], 1); + } else { + puts("RST:VIN "); + } + puts("WDT:disabled\n"); + } + + return ret; +} + +#endif diff --git a/drivers/misc/imx8ulp/fuse.c b/drivers/misc/imx8ulp/fuse.c index d1feb62ab59..090e702d9f7 100644 --- a/drivers/misc/imx8ulp/fuse.c +++ b/drivers/misc/imx8ulp/fuse.c @@ -34,9 +34,9 @@ struct s400_map_entry { struct fsb_map_entry fsb_mapping_table[] = { { 3, 8 }, { 4, 8 }, + { -1, 48 }, /* Reserve 48 words */ { 5, 8 }, { 6, 8 }, - { -1, 48 }, /* Reserve 48 words */ { 8, 4, true }, { 24, 4, true }, { 26, 4, true }, @@ -61,7 +61,9 @@ struct s400_map_entry s400_api_mapping_table[] = { { 1, 8 }, /* LOCK */ { 2, 8 }, /* ECID */ { 7, 4, 0, 1 }, /* OTP_UNIQ_ID */ + { 15, 8 }, /* OEM SRK HASH */ { 23, 1, 4, 2 }, /* OTFAD */ + { 25, 8 }, /* Test config2 */ }; static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy) diff --git a/drivers/misc/imx8ulp/s400_api.c b/drivers/misc/imx8ulp/s400_api.c index d76a95febe7..3ffdeb2ad2a 100644 --- a/drivers/misc/imx8ulp/s400_api.c +++ b/drivers/misc/imx8ulp/s400_api.c @@ -242,3 +242,66 @@ int ahab_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response) return ret; } + +int ahab_release_caam(u32 core_did, u32 *response) +{ + struct udevice *dev = gd->arch.s400_dev; + int size = sizeof(struct imx8ulp_s400_msg); + struct imx8ulp_s400_msg msg; + int ret; + + if (!dev) { + printf("s400 dev is not initialized\n"); + return -ENODEV; + } + + msg.version = AHAB_VERSION; + msg.tag = AHAB_CMD_TAG; + msg.size = 2; + msg.command = AHAB_CAAM_RELEASE_CID; + msg.data[0] = core_did; + + ret = misc_call(dev, false, &msg, size, &msg, size); + if (ret) + printf("Error: %s: ret %d, response 0x%x\n", + __func__, ret, msg.data[0]); + + if (response) + *response = msg.data[0]; + + return ret; +} + +int ahab_dump_buffer(u32 *buffer, u32 buffer_length) +{ + struct udevice *dev = gd->arch.s400_dev; + int size = sizeof(struct imx8ulp_s400_msg); + struct imx8ulp_s400_msg msg; + int ret, i = 0; + + if (!dev) { + printf("s400 dev is not initialized\n"); + return -ENODEV; + } + + msg.version = AHAB_VERSION; + msg.tag = AHAB_CMD_TAG; + msg.size = 1; + msg.command = AHAB_LOG_CID; + + ret = misc_call(dev, false, &msg, size, &msg, size); + if (ret) { + printf("Error: %s: ret %d, response 0x%x\n", + __func__, ret, msg.data[0]); + + return ret; + } + + if (buffer) { + buffer[i++] = *(u32 *)&msg; /* Need dump the response header */ + for (; i < buffer_length && i < msg.size; i++) + buffer[i] = msg.data[i - 1]; + } + + return i; +} diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 02208a5ade4..893d7e241f2 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -1640,6 +1640,7 @@ static const struct udevice_id fsl_esdhc_ids[] = { { .compatible = "fsl,imx8qm-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, { .compatible = "fsl,imx8mm-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, { .compatible = "fsl,imx8mn-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, + { .compatible = "fsl,imx8mp-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, { .compatible = "fsl,imx8mq-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, { .compatible = "fsl,imxrt-usdhc", }, { .compatible = "fsl,esdhc", }, diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c index f3f9d83ba36..1fdc8415178 100644 --- a/drivers/mmc/rockchip_sdhci.c +++ b/drivers/mmc/rockchip_sdhci.c @@ -202,8 +202,8 @@ static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock) /* REN Enable on STRB Line for HS400 */ writel(RK_CLRSETBITS(0, 1 << 9), &phy->emmcphy_con[2]); - read_poll_timeout(readl, &phy->emmcphy_status, dllrdy, - PHYCTRL_DLL_LOCK_WO_TMOUT(dllrdy), 1, 5000); + read_poll_timeout(readl, dllrdy, PHYCTRL_DLL_LOCK_WO_TMOUT(dllrdy), 1, + 5000, &phy->emmcphy_status); } static void rk3399_emmc_phy_power_off(struct rockchip_emmc_phy *phy) @@ -328,8 +328,9 @@ static int rk3568_sdhci_emmc_set_clock(struct sdhci_host *host, unsigned int clo DWCMSHC_EMMC_DLL_START; sdhci_writel(host, extra, DWCMSHC_EMMC_DLL_CTRL); - ret = read_poll_timeout(readl, host->ioaddr + DWCMSHC_EMMC_DLL_STATUS0, - val, DLL_LOCK_WO_TMOUT(val), 1, 500); + ret = read_poll_timeout(readl, val, DLL_LOCK_WO_TMOUT(val), 1, + 500, + host->ioaddr + DWCMSHC_EMMC_DLL_STATUS0); if (ret) return ret; diff --git a/drivers/mtd/nand/raw/mxs_nand_spl.c b/drivers/mtd/nand/raw/mxs_nand_spl.c index 9e0b8afb522..59a67ee4145 100644 --- a/drivers/mtd/nand/raw/mxs_nand_spl.c +++ b/drivers/mtd/nand/raw/mxs_nand_spl.c @@ -283,11 +283,6 @@ int nand_spl_load_image(uint32_t offs, unsigned int size, void *buf) return 0; } -struct mtd_info *nand_get_mtd(void) -{ - return mtd; -} - int nand_default_bbt(struct mtd_info *mtd) { return 0; diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index 22dad5b2030..ea0c2cfa5b2 100644 --- a/drivers/net/dwc_eth_qos.c +++ b/drivers/net/dwc_eth_qos.c @@ -2032,7 +2032,7 @@ static const struct udevice_id eqos_ids[] = { #endif #if IS_ENABLED(CONFIG_DWC_ETH_QOS_IMX) { - .compatible = "fsl,imx-eqos", + .compatible = "nxp,imx8mp-dwmac-eqos", .data = (ulong)&eqos_imx_config }, #endif diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 014a4de223e..d40ce92cadc 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -215,6 +215,11 @@ config PHY_NXP_C45_TJA11XX Enable support for NXP C45 TJA11XX PHYs. Currently supports only the TJA1103 PHY. +config PHY_NXP_TJA11XX + bool "NXP TJA11XX Ethernet PHYs support" + help + Currently supports the NXP TJA1100 and TJA1101 PHY. + config PHY_REALTEK bool "Realtek Ethernet PHYs support" diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index b28440bc4e5..67ca4d3a69f 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_PHY_MICREL_KSZ90X1) += micrel_ksz90x1.o obj-$(CONFIG_PHY_MESON_GXL) += meson-gxl.o obj-$(CONFIG_PHY_NATSEMI) += natsemi.o obj-$(CONFIG_PHY_NXP_C45_TJA11XX) += nxp-c45-tja11xx.o +obj-$(CONFIG_PHY_NXP_TJA11XX) += nxp-tja11xx.o obj-$(CONFIG_PHY_REALTEK) += realtek.o obj-$(CONFIG_PHY_SMSC) += smsc.o obj-$(CONFIG_PHY_TERANETICS) += teranetics.o diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index f86e31f0d9e..a0f41fab698 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -330,7 +330,7 @@ static int nxp_c45_probe(struct phy_device *phydev) return 0; } -static struct phy_driver nxp_tja11xx = { +static struct phy_driver nxp_c45_tja11xx = { .name = "NXP C45 TJA1103", .uid = PHY_ID_TJA_1103, .mask = 0xfffff0, @@ -341,8 +341,8 @@ static struct phy_driver nxp_tja11xx = { .shutdown = &genphy_shutdown, }; -int phy_nxp_tja11xx_init(void) +int phy_nxp_c45_tja11xx_init(void) { - phy_register(&nxp_tja11xx); + phy_register(&nxp_c45_tja11xx); return 0; } diff --git a/drivers/net/phy/nxp-tja11xx.c b/drivers/net/phy/nxp-tja11xx.c new file mode 100644 index 00000000000..30dec5e605b --- /dev/null +++ b/drivers/net/phy/nxp-tja11xx.c @@ -0,0 +1,277 @@ +// SPDX-License-Identifier: GPL-2.0 +/* NXP TJA1100 BroadRReach PHY driver + * + * Copyright (C) 2022 Michael Trimarchi <michael@amarulasolutions.com> + * Copyright (C) 2022 Ariel D'Alessandro <ariel.dalessandro@collabora.com> + * Copyright (C) 2018 Marek Vasut <marex@denx.de> + */ + +#include <common.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <phy.h> + +#define PHY_ID_MASK 0xfffffff0 +#define PHY_ID_TJA1100 0x0180dc40 +#define PHY_ID_TJA1101 0x0180dd00 + +#define MII_ECTRL 17 +#define MII_ECTRL_LINK_CONTROL BIT(15) +#define MII_ECTRL_POWER_MODE_MASK GENMASK(14, 11) +#define MII_ECTRL_POWER_MODE_NO_CHANGE (0x0 << 11) +#define MII_ECTRL_POWER_MODE_NORMAL (0x3 << 11) +#define MII_ECTRL_POWER_MODE_STANDBY (0xc << 11) +#define MII_ECTRL_CABLE_TEST BIT(5) +#define MII_ECTRL_CONFIG_EN BIT(2) +#define MII_ECTRL_WAKE_REQUEST BIT(0) + +#define MII_CFG1 18 +#define MII_CFG1_MASTER_SLAVE BIT(15) +#define MII_CFG1_AUTO_OP BIT(14) +#define MII_CFG1_SLEEP_CONFIRM BIT(6) +#define MII_CFG1_LED_MODE_MASK GENMASK(5, 4) +#define MII_CFG1_LED_MODE_LINKUP 0 +#define MII_CFG1_LED_ENABLE BIT(3) + +#define MII_CFG2 19 +#define MII_CFG2_SLEEP_REQUEST_TO GENMASK(1, 0) +#define MII_CFG2_SLEEP_REQUEST_TO_16MS 0x3 + +#define MII_INTSRC 21 +#define MII_INTSRC_LINK_FAIL BIT(10) +#define MII_INTSRC_LINK_UP BIT(9) +#define MII_INTSRC_MASK (MII_INTSRC_LINK_FAIL | \ + MII_INTSRC_LINK_UP) +#define MII_INTSRC_UV_ERR BIT(3) +#define MII_INTSRC_TEMP_ERR BIT(1) + +#define MII_INTEN 22 +#define MII_INTEN_LINK_FAIL BIT(10) +#define MII_INTEN_LINK_UP BIT(9) +#define MII_INTEN_UV_ERR BIT(3) +#define MII_INTEN_TEMP_ERR BIT(1) + +#define MII_COMMSTAT 23 +#define MII_COMMSTAT_LINK_UP BIT(15) +#define MII_COMMSTAT_SQI_STATE GENMASK(7, 5) +#define MII_COMMSTAT_SQI_MAX 7 + +#define MII_GENSTAT 24 +#define MII_GENSTAT_PLL_LOCKED BIT(14) + +#define MII_EXTSTAT 25 +#define MII_EXTSTAT_SHORT_DETECT BIT(8) +#define MII_EXTSTAT_OPEN_DETECT BIT(7) +#define MII_EXTSTAT_POLARITY_DETECT BIT(6) + +#define MII_COMMCFG 27 +#define MII_COMMCFG_AUTO_OP BIT(15) + +static inline int tja11xx_set_bits(struct phy_device *phydev, u32 regnum, + u16 val) +{ + return phy_set_bits_mmd(phydev, MDIO_DEVAD_NONE, regnum, val); +} + +static inline int tja11xx_clear_bits(struct phy_device *phydev, u32 regnum, + u16 val) +{ + return phy_clear_bits_mmd(phydev, MDIO_DEVAD_NONE, regnum, val); +} + +static inline int tja11xx_read(struct phy_device *phydev, int regnum) +{ + return phy_read(phydev, MDIO_DEVAD_NONE, regnum); +} + +static inline int tja11xx_modify(struct phy_device *phydev, int regnum, + u16 mask, u16 set) +{ + return phy_modify(phydev, MDIO_DEVAD_NONE, regnum, mask, set); +} + +static int tja11xx_check(struct phy_device *phydev, u8 reg, u16 mask, u16 set) +{ + int val; + + return read_poll_timeout(tja11xx_read, val, (val & mask) == set, 150, + 30000, phydev, reg); +} + +static int tja11xx_modify_check(struct phy_device *phydev, u8 reg, + u16 mask, u16 set) +{ + int ret; + + ret = tja11xx_modify(phydev, reg, mask, set); + if (ret) + return ret; + + return tja11xx_check(phydev, reg, mask, set); +} + +static int tja11xx_enable_reg_write(struct phy_device *phydev) +{ + return tja11xx_set_bits(phydev, MII_ECTRL, MII_ECTRL_CONFIG_EN); +} + +static int tja11xx_enable_link_control(struct phy_device *phydev) +{ + return tja11xx_set_bits(phydev, MII_ECTRL, MII_ECTRL_LINK_CONTROL); +} + +static int tja11xx_wakeup(struct phy_device *phydev) +{ + int ret; + + ret = tja11xx_read(phydev, MII_ECTRL); + if (ret < 0) + return ret; + + switch (ret & MII_ECTRL_POWER_MODE_MASK) { + case MII_ECTRL_POWER_MODE_NO_CHANGE: + break; + case MII_ECTRL_POWER_MODE_NORMAL: + ret = tja11xx_set_bits(phydev, MII_ECTRL, + MII_ECTRL_WAKE_REQUEST); + if (ret) + return ret; + + ret = tja11xx_clear_bits(phydev, MII_ECTRL, + MII_ECTRL_WAKE_REQUEST); + if (ret) + return ret; + break; + case MII_ECTRL_POWER_MODE_STANDBY: + ret = tja11xx_modify_check(phydev, MII_ECTRL, + MII_ECTRL_POWER_MODE_MASK, + MII_ECTRL_POWER_MODE_STANDBY); + if (ret) + return ret; + + ret = tja11xx_modify(phydev, MII_ECTRL, + MII_ECTRL_POWER_MODE_MASK, + MII_ECTRL_POWER_MODE_NORMAL); + if (ret) + return ret; + + ret = tja11xx_modify_check(phydev, MII_GENSTAT, + MII_GENSTAT_PLL_LOCKED, + MII_GENSTAT_PLL_LOCKED); + if (ret) + return ret; + + return tja11xx_enable_link_control(phydev); + default: + break; + } + + return 0; +} + +static int tja11xx_config_init(struct phy_device *phydev) +{ + int ret; + + ret = tja11xx_enable_reg_write(phydev); + if (ret) + return ret; + + phydev->autoneg = AUTONEG_DISABLE; + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + + switch (phydev->phy_id & PHY_ID_MASK) { + case PHY_ID_TJA1100: + ret = tja11xx_modify(phydev, MII_CFG1, + MII_CFG1_AUTO_OP | MII_CFG1_LED_MODE_MASK | + MII_CFG1_LED_ENABLE, + MII_CFG1_AUTO_OP | + MII_CFG1_LED_MODE_LINKUP | + MII_CFG1_LED_ENABLE); + if (ret) + return ret; + break; + case PHY_ID_TJA1101: + ret = tja11xx_set_bits(phydev, MII_COMMCFG, + MII_COMMCFG_AUTO_OP); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + + ret = tja11xx_clear_bits(phydev, MII_CFG1, MII_CFG1_SLEEP_CONFIRM); + if (ret) + return ret; + + ret = tja11xx_modify(phydev, MII_CFG2, MII_CFG2_SLEEP_REQUEST_TO, + MII_CFG2_SLEEP_REQUEST_TO_16MS); + if (ret) + return ret; + + ret = tja11xx_wakeup(phydev); + if (ret < 0) + return ret; + + /* ACK interrupts by reading the status register */ + ret = tja11xx_read(phydev, MII_INTSRC); + if (ret < 0) + return ret; + + return 0; +} + +static int tja11xx_startup(struct phy_device *phydev) +{ + int ret; + + ret = genphy_update_link(phydev); + if (ret) + return ret; + + ret = tja11xx_read(phydev, MII_CFG1); + if (ret < 0) + return ret; + + if (phydev->link) { + ret = tja11xx_read(phydev, MII_COMMSTAT); + if (ret < 0) + return ret; + + if (!(ret & MII_COMMSTAT_LINK_UP)) + phydev->link = 0; + } + + return 0; +} + +static struct phy_driver TJA1100_driver = { + .name = "NXP TJA1100", + .uid = PHY_ID_TJA1100, + .mask = PHY_ID_MASK, + .features = PHY_BASIC_FEATURES, + .config = &tja11xx_config_init, + .startup = &tja11xx_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver TJA1101_driver = { + .name = "NXP TJA1101", + .uid = PHY_ID_TJA1101, + .mask = PHY_ID_MASK, + .features = PHY_BASIC_FEATURES, + .config = &tja11xx_config_init, + .startup = &tja11xx_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_nxp_tja11xx_init(void) +{ + phy_register(&TJA1100_driver); + phy_register(&TJA1101_driver); + + return 0; +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index d4731860f73..36722620f0c 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -530,6 +530,9 @@ int phy_init(void) phy_natsemi_init(); #endif #ifdef CONFIG_NXP_C45_TJA11XX_PHY + phy_nxp_c45_tja11xx_init(); +#endif +#ifdef CONFIG_PHY_NXP_TJA11XX phy_nxp_tja11xx_init(); #endif #ifdef CONFIG_PHY_REALTEK @@ -1110,3 +1113,23 @@ int phy_get_interface_by_name(const char *str) return -1; } + +/** + * phy_modify - Convenience function for modifying a given PHY register + * @phydev: the phy_device struct + * @devad: The MMD to read from + * @regnum: register number to write + * @mask: bit mask of bits to clear + * @set: new value of bits set in mask to write to @regnum + */ +int phy_modify(struct phy_device *phydev, int devad, int regnum, u16 mask, + u16 set) +{ + int ret; + + ret = phy_read(phydev, devad, regnum); + if (ret < 0) + return ret; + + return phy_write(phydev, devad, regnum, (ret & ~mask) | set); +} diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index d79798429b1..c01d9e09b90 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -275,11 +275,11 @@ config PHY_MTK_TPHY so you can easily distinguish them by banks layout. config PHY_IMX8MQ_USB - bool "NXP i.MX8MQ USB PHY Driver" + bool "NXP i.MX8MQ/i.MX8MP USB PHY Driver" depends on PHY - depends on IMX8MQ + depends on IMX8MQ || IMX8MP help - Support the USB3.0 PHY in NXP i.MX8MQ SoC + Support the USB3.0 PHY in NXP i.MX8MQ or i.MX8MP SoC config PHY_XILINX_ZYNQMP tristate "Xilinx ZynqMP PHY driver" diff --git a/drivers/phy/phy-imx8mq-usb.c b/drivers/phy/phy-imx8mq-usb.c index afbc7ad8dd4..69f01de5553 100644 --- a/drivers/phy/phy-imx8mq-usb.c +++ b/drivers/phy/phy-imx8mq-usb.c @@ -9,7 +9,9 @@ #include <dm.h> #include <errno.h> #include <generic-phy.h> +#include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/delay.h> #include <linux/err.h> #include <clk.h> @@ -68,17 +70,22 @@ #define PHY_STS0_FSVPLUS BIT(3) #define PHY_STS0_FSVMINUS BIT(2) +enum imx8mpq_phy_type { + IMX8MQ_PHY, + IMX8MP_PHY, +}; + struct imx8mq_usb_phy { #if CONFIG_IS_ENABLED(CLK) struct clk phy_clk; #endif void __iomem *base; + enum imx8mpq_phy_type type; }; static const struct udevice_id imx8mq_usb_phy_of_match[] = { - { - .compatible = "fsl,imx8mq-usb-phy", - }, + { .compatible = "fsl,imx8mq-usb-phy", .data = IMX8MQ_PHY }, + { .compatible = "fsl,imx8mp-usb-phy", .data = IMX8MP_PHY }, {}, }; @@ -111,6 +118,56 @@ static int imx8mq_usb_phy_init(struct phy *usb_phy) return 0; } +static int imx8mp_usb_phy_init(struct phy *usb_phy) +{ + struct udevice *dev = usb_phy->dev; + struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev); + u32 value; + + /* USB3.0 PHY signal fsel for 24M ref */ + value = readl(imx_phy->base + PHY_CTRL0); + value &= ~PHY_CTRL0_FSEL_MASK; + value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, PHY_CTRL0_FSEL_24M); + writel(value, imx_phy->base + PHY_CTRL0); + + /* Disable alt_clk_en and use internal MPLL clocks */ + value = readl(imx_phy->base + PHY_CTRL6); + value &= ~(PHY_CTRL6_ALT_CLK_SEL | PHY_CTRL6_ALT_CLK_EN); + writel(value, imx_phy->base + PHY_CTRL6); + + value = readl(imx_phy->base + PHY_CTRL1); + value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0); + value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET; + writel(value, imx_phy->base + PHY_CTRL1); + + value = readl(imx_phy->base + PHY_CTRL0); + value |= PHY_CTRL0_REF_SSP_EN; + writel(value, imx_phy->base + PHY_CTRL0); + + value = readl(imx_phy->base + PHY_CTRL2); + value |= PHY_CTRL2_TXENABLEN0 | PHY_CTRL2_OTG_DISABLE; + writel(value, imx_phy->base + PHY_CTRL2); + + udelay(10); + + value = readl(imx_phy->base + PHY_CTRL1); + value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET); + writel(value, imx_phy->base + PHY_CTRL1); + + return 0; +} + +static int imx8mpq_usb_phy_init(struct phy *usb_phy) +{ + struct udevice *dev = usb_phy->dev; + struct imx8mq_usb_phy *imx_phy = dev_get_priv(dev); + + if (imx_phy->type == IMX8MP_PHY) + return imx8mp_usb_phy_init(usb_phy); + else + return imx8mq_usb_phy_init(usb_phy); +} + static int imx8mq_usb_phy_power_on(struct phy *usb_phy) { struct udevice *dev = usb_phy->dev; @@ -158,7 +215,7 @@ static int imx8mq_usb_phy_exit(struct phy *usb_phy) } struct phy_ops imx8mq_usb_phy_ops = { - .init = imx8mq_usb_phy_init, + .init = imx8mpq_usb_phy_init, .power_on = imx8mq_usb_phy_power_on, .power_off = imx8mq_usb_phy_power_off, .exit = imx8mq_usb_phy_exit, @@ -168,6 +225,7 @@ int imx8mq_usb_phy_probe(struct udevice *dev) { struct imx8mq_usb_phy *priv = dev_get_priv(dev); + priv->type = dev_get_driver_data(dev); priv->base = dev_read_addr_ptr(dev); if (!priv->base) diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig index 4fb0916a376..3657e9deb9e 100644 --- a/drivers/pinctrl/nxp/Kconfig +++ b/drivers/pinctrl/nxp/Kconfig @@ -92,7 +92,6 @@ config PINCTRL_IMX8 config PINCTRL_IMX8M bool "IMX8M pinctrl driver" depends on ARCH_IMX8M && PINCTRL_FULL - select DEVRES select PINCTRL_IMX help Say Y here to enable the imx8m pinctrl driver diff --git a/drivers/power/pmic/pca9450.c b/drivers/power/pmic/pca9450.c index a886647f193..2394b196c56 100644 --- a/drivers/power/pmic/pca9450.c +++ b/drivers/power/pmic/pca9450.c @@ -83,6 +83,7 @@ static struct dm_pmic_ops pca9450_ops = { static const struct udevice_id pca9450_ids[] = { { .compatible = "nxp,pca9450a", .data = 0x25, }, { .compatible = "nxp,pca9450b", .data = 0x25, }, + { .compatible = "nxp,pca9450c", .data = 0x25, }, { } }; diff --git a/drivers/power/regulator/fixed.c b/drivers/power/regulator/fixed.c index d3e0fb672d9..90004d1601a 100644 --- a/drivers/power/regulator/fixed.c +++ b/drivers/power/regulator/fixed.c @@ -6,14 +6,21 @@ */ #include <common.h> +#include <clk.h> #include <errno.h> #include <dm.h> +#include <linux/delay.h> #include <log.h> #include <power/pmic.h> #include <power/regulator.h> #include "regulator_common.h" +struct fixed_clock_regulator_plat { + struct clk *enable_clock; + unsigned int clk_enable_counter; +}; + static int fixed_regulator_of_to_plat(struct udevice *dev) { struct dm_regulator_uclass_plat *uc_pdata; @@ -71,6 +78,38 @@ static int fixed_regulator_set_enable(struct udevice *dev, bool enable) return regulator_common_set_enable(dev, dev_get_plat(dev), enable); } +static int fixed_clock_regulator_get_enable(struct udevice *dev) +{ + struct fixed_clock_regulator_plat *priv = dev_get_priv(dev); + + return priv->clk_enable_counter > 0; +} + +static int fixed_clock_regulator_set_enable(struct udevice *dev, bool enable) +{ + struct fixed_clock_regulator_plat *priv = dev_get_priv(dev); + struct regulator_common_plat *dev_pdata = dev_get_plat(dev); + int ret = 0; + + if (enable) { + ret = clk_enable(priv->enable_clock); + priv->clk_enable_counter++; + } else { + ret = clk_disable(priv->enable_clock); + priv->clk_enable_counter--; + } + if (ret) + return ret; + + if (enable && dev_pdata->startup_delay_us) + udelay(dev_pdata->startup_delay_us); + + if (!enable && dev_pdata->off_on_delay_us) + udelay(dev_pdata->off_on_delay_us); + + return ret; +} + static const struct dm_regulator_ops fixed_regulator_ops = { .get_value = fixed_regulator_get_value, .get_current = fixed_regulator_get_current, @@ -78,16 +117,35 @@ static const struct dm_regulator_ops fixed_regulator_ops = { .set_enable = fixed_regulator_set_enable, }; +static const struct dm_regulator_ops fixed_clock_regulator_ops = { + .get_enable = fixed_clock_regulator_get_enable, + .set_enable = fixed_clock_regulator_set_enable, +}; + static const struct udevice_id fixed_regulator_ids[] = { { .compatible = "regulator-fixed" }, { }, }; +static const struct udevice_id fixed_clock_regulator_ids[] = { + { .compatible = "regulator-fixed-clock" }, + { }, +}; + U_BOOT_DRIVER(regulator_fixed) = { .name = "regulator_fixed", .id = UCLASS_REGULATOR, .ops = &fixed_regulator_ops, .of_match = fixed_regulator_ids, .of_to_plat = fixed_regulator_of_to_plat, - .plat_auto = sizeof(struct regulator_common_plat), + .plat_auto = sizeof(struct regulator_common_plat), +}; + +U_BOOT_DRIVER(regulator_fixed_clock) = { + .name = "regulator_fixed_clk", + .id = UCLASS_REGULATOR, + .ops = &fixed_clock_regulator_ops, + .of_match = fixed_clock_regulator_ids, + .of_to_plat = fixed_regulator_of_to_plat, + .plat_auto = sizeof(struct fixed_clock_regulator_plat), }; diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index bd119a666a9..e4d10c8dc3e 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_PWM_AT91) += pwm-at91.o obj-$(CONFIG_PWM_CADENCE_TTC) += pwm-cadence-ttc.o obj-$(CONFIG_PWM_CROS_EC) += cros_ec_pwm.o obj-$(CONFIG_PWM_EXYNOS) += exynos_pwm.o -obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o +obj-$(CONFIG_PWM_IMX) += pwm-imx.o obj-$(CONFIG_PWM_MESON) += pwm-meson.o obj-$(CONFIG_PWM_MTK) += pwm-mtk.o obj-$(CONFIG_PWM_ROCKCHIP) += rk_pwm.o diff --git a/drivers/pwm/pwm-imx-util.c b/drivers/pwm/pwm-imx-util.c deleted file mode 100644 index 823a9d2d6bf..00000000000 --- a/drivers/pwm/pwm-imx-util.c +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * (C) Copyright 2014 - * Heiko Schocher, DENX Software Engineering, hs@denx.de. - * - * Basic support for the pwm module on imx6. - * - * Based on linux:drivers/pwm/pwm-imx.c - * from - * Sascha Hauer <s.hauer@pengutronix.de> - */ - -#include <common.h> -#include <div64.h> -#include <asm/arch/imx-regs.h> - -/* pwm_id from 0..7 */ -struct pwm_regs *pwm_id_to_reg(int pwm_id) -{ - switch (pwm_id) { - case 0: - return (struct pwm_regs *)PWM1_BASE_ADDR; - case 1: - return (struct pwm_regs *)PWM2_BASE_ADDR; -#ifdef CONFIG_MX6 - case 2: - return (struct pwm_regs *)PWM3_BASE_ADDR; - case 3: - return (struct pwm_regs *)PWM4_BASE_ADDR; -#endif -#ifdef CONFIG_MX6SX - case 4: - return (struct pwm_regs *)PWM5_BASE_ADDR; - case 5: - return (struct pwm_regs *)PWM6_BASE_ADDR; - case 6: - return (struct pwm_regs *)PWM7_BASE_ADDR; - case 7: - return (struct pwm_regs *)PWM8_BASE_ADDR; -#endif - default: - printf("unknown pwm_id: %d\n", pwm_id); - break; - } - return NULL; -} - -int pwm_imx_get_parms(int period_ns, int duty_ns, unsigned long *period_c, - unsigned long *duty_c, unsigned long *prescale) -{ - unsigned long long c; - - /* - * we have not yet a clock framework for imx6, so add the clock - * value here as a define. Replace it when we have the clock - * framework. - */ - c = CONFIG_IMX6_PWM_PER_CLK; - c = c * period_ns; - do_div(c, 1000000000); - *period_c = c; - - *prescale = *period_c / 0x10000 + 1; - - *period_c /= *prescale; - c = *period_c * (unsigned long long)duty_ns; - do_div(c, period_ns); - *duty_c = c; - - /* - * according to imx pwm RM, the real period value should be - * PERIOD value in PWMPR plus 2. - */ - if (*period_c > 2) - *period_c -= 2; - else - *period_c = 0; - - return 0; -} diff --git a/drivers/pwm/pwm-imx-util.h b/drivers/pwm/pwm-imx-util.h deleted file mode 100644 index 82c61d774d3..00000000000 --- a/drivers/pwm/pwm-imx-util.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * (C) Copyright 2014 - * Heiko Schocher, DENX Software Engineering, hs@denx.de. - * - * Basic support for the pwm module on imx6. - */ - -#ifndef _pwm_imx_util_h_ -#define _pwm_imx_util_h_ - -struct pwm_regs *pwm_id_to_reg(int pwm_id); -int pwm_imx_get_parms(int period_ns, int duty_ns, unsigned long *period_c, - unsigned long *duty_c, unsigned long *prescale); -#endif diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 2008c1520e6..9b8a8c189d0 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -13,18 +13,7 @@ #include <pwm.h> #include <asm/arch/imx-regs.h> #include <asm/io.h> -#include "pwm-imx-util.h" - -int pwm_init(int pwm_id, int div, int invert) -{ - struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id); - - if (!pwm) - return -1; - - writel(0, &pwm->ir); - return 0; -} +#include <clk.h> int pwm_config_internal(struct pwm_regs *pwm, unsigned long period_cycles, unsigned long duty_cycles, unsigned long prescale) @@ -44,6 +33,84 @@ int pwm_config_internal(struct pwm_regs *pwm, unsigned long period_cycles, return 0; } +#ifndef CONFIG_DM_PWM +/* pwm_id from 0..7 */ +struct pwm_regs *pwm_id_to_reg(int pwm_id) +{ + + switch (pwm_id) { + case 0: + return (struct pwm_regs *)PWM1_BASE_ADDR; + case 1: + return (struct pwm_regs *)PWM2_BASE_ADDR; +#ifdef CONFIG_MX6 + case 2: + return (struct pwm_regs *)PWM3_BASE_ADDR; + case 3: + return (struct pwm_regs *)PWM4_BASE_ADDR; +#endif +#ifdef CONFIG_MX6SX + case 4: + return (struct pwm_regs *)PWM5_BASE_ADDR; + case 5: + return (struct pwm_regs *)PWM6_BASE_ADDR; + case 6: + return (struct pwm_regs *)PWM7_BASE_ADDR; + case 7: + return (struct pwm_regs *)PWM8_BASE_ADDR; +#endif + default: + printf("unknown pwm_id: %d\n", pwm_id); + break; + } + return NULL; +} + +int pwm_imx_get_parms(int period_ns, int duty_ns, unsigned long *period_c, + unsigned long *duty_c, unsigned long *prescale) +{ + unsigned long long c; + + /* + * we have not yet a clock framework for imx6, so add the clock + * value here as a define. Replace it when we have the clock + * framework. + */ + c = CONFIG_IMX6_PWM_PER_CLK; + c = c * period_ns; + do_div(c, 1000000000); + *period_c = c; + + *prescale = *period_c / 0x10000 + 1; + + *period_c /= *prescale; + c = *period_c * (unsigned long long)duty_ns; + do_div(c, period_ns); + *duty_c = c; + + /* + * according to imx pwm RM, the real period value should be + * PERIOD value in PWMPR plus 2. + */ + if (*period_c > 2) + *period_c -= 2; + else + *period_c = 0; + + return 0; +} + +int pwm_init(int pwm_id, int div, int invert) +{ + struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id); + + if (!pwm) + return -1; + + writel(0, &pwm->ir); + return 0; +} + int pwm_config(int pwm_id, int duty_ns, int period_ns) { struct pwm_regs *pwm = (struct pwm_regs *)pwm_id_to_reg(pwm_id); @@ -79,12 +146,44 @@ void pwm_disable(int pwm_id) clrbits_le32(&pwm->cr, PWMCR_EN); } -#if defined(CONFIG_DM_PWM) +#else struct imx_pwm_priv { struct pwm_regs *regs; bool invert; + struct clk per_clk; + struct clk ipg_clk; }; +int pwm_dm_imx_get_parms(struct imx_pwm_priv *priv, int period_ns, + int duty_ns, unsigned long *period_c, unsigned long *duty_c, + unsigned long *prescale) +{ + unsigned long long c; + + c = clk_get_rate(&priv->per_clk); + c = c * period_ns; + do_div(c, 1000000000); + *period_c = c; + + *prescale = *period_c / 0x10000 + 1; + + *period_c /= *prescale; + c = *period_c * (unsigned long long)duty_ns; + do_div(c, period_ns); + *duty_c = c; + + /* + * according to imx pwm RM, the real period value should be + * PERIOD value in PWMPR plus 2. + */ + if (*period_c > 2) + *period_c -= 2; + else + *period_c = 0; + + return 0; +} + static int imx_pwm_set_invert(struct udevice *dev, uint channel, bool polarity) { @@ -105,7 +204,7 @@ static int imx_pwm_set_config(struct udevice *dev, uint channel, debug("%s: Config '%s' channel: %d\n", __func__, dev->name, channel); - pwm_imx_get_parms(period_ns, duty_ns, &period_cycles, &duty_cycles, + pwm_dm_imx_get_parms(priv, period_ns, duty_ns, &period_cycles, &duty_cycles, &prescale); return pwm_config_internal(regs, period_cycles, duty_cycles, prescale); @@ -128,15 +227,43 @@ static int imx_pwm_set_enable(struct udevice *dev, uint channel, bool enable) static int imx_pwm_of_to_plat(struct udevice *dev) { + int ret; struct imx_pwm_priv *priv = dev_get_priv(dev); priv->regs = dev_read_addr_ptr(dev); + ret = clk_get_by_name(dev, "per", &priv->per_clk); + if (ret) { + printf("Failed to get per_clk\n"); + return ret; + } + + ret = clk_get_by_name(dev, "ipg", &priv->ipg_clk); + if (ret) { + printf("Failed to get ipg_clk\n"); + return ret; + } + return 0; } static int imx_pwm_probe(struct udevice *dev) { + int ret; + struct imx_pwm_priv *priv = dev_get_priv(dev); + + ret = clk_enable(&priv->per_clk); + if (ret) { + printf("Failed to enable per_clk\n"); + return ret; + } + + ret = clk_enable(&priv->ipg_clk); + if (ret) { + printf("Failed to enable ipg_clk\n"); + return ret; + } + return 0; } diff --git a/drivers/spi/nxp_fspi.c b/drivers/spi/nxp_fspi.c index b7c922b1dfd..607c953987b 100644 --- a/drivers/spi/nxp_fspi.c +++ b/drivers/spi/nxp_fspi.c @@ -1053,6 +1053,7 @@ static const struct dm_spi_ops nxp_fspi_ops = { static const struct udevice_id nxp_fspi_ids[] = { { .compatible = "nxp,lx2160a-fspi", .data = (ulong)&lx2160a_data, }, { .compatible = "nxp,imx8mm-fspi", .data = (ulong)&imx8mm_data, }, + { .compatible = "nxp,imx8mp-fspi", .data = (ulong)&imx8mm_data, }, { } }; |