// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2022 * Author(s): Jesse Taube */ #include #include #include #include #include #include #include #include #include "clk.h" static ulong imxrt1170_clk_get_rate(struct clk *clk) { struct clk *c; int ret; debug("%s(#%lu)\n", __func__, clk->id); ret = clk_get_by_id(clk->id, &c); if (ret) return ret; return clk_get_rate(c); } static ulong imxrt1170_clk_set_rate(struct clk *clk, ulong rate) { struct clk *c; int ret; debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate); ret = clk_get_by_id(clk->id, &c); if (ret) return ret; return clk_set_rate(c, rate); } static int __imxrt1170_clk_enable(struct clk *clk, bool enable) { struct clk *c; int ret; debug("%s(#%lu) en: %d\n", __func__, clk->id, enable); ret = clk_get_by_id(clk->id, &c); if (ret) return ret; if (enable) ret = clk_enable(c); else ret = clk_disable(c); return ret; } static int imxrt1170_clk_disable(struct clk *clk) { return __imxrt1170_clk_enable(clk, 0); } static int imxrt1170_clk_enable(struct clk *clk) { return __imxrt1170_clk_enable(clk, 1); } static int imxrt1170_clk_set_parent(struct clk *clk, struct clk *parent) { struct clk *c, *cp; int ret; debug("%s(#%lu), parent: %lu\n", __func__, clk->id, parent->id); ret = clk_get_by_id(clk->id, &c); if (ret) return ret; ret = clk_get_by_id(parent->id, &cp); if (ret) return ret; return clk_set_parent(c, cp); } static struct clk_ops imxrt1170_clk_ops = { .set_rate = imxrt1170_clk_set_rate, .get_rate = imxrt1170_clk_get_rate, .enable = imxrt1170_clk_enable, .disable = imxrt1170_clk_disable, .set_parent = imxrt1170_clk_set_parent, }; static const char * const lpuart1_sels[] = {"rcosc48M_div2", "osc", "rcosc400M", "rcosc16M", "pll3_div2", "pll1_div5", "pll2_sys", "pll2_pfd3"}; static const char * const gpt1_sels[] = {"rcosc48M_div2", "osc", "rcosc400M", "rcosc16M", "pll3_div2", "pll1_div5", "pll3_pfd2", "pll3_pfd3"}; static const char * const usdhc1_sels[] = {"rcosc48M_div2", "osc", "rcosc400M", "rcosc16M", "pll2_pfd2", "pll2_pfd0", "pll1_div5", "pll_arm"}; static const char * const semc_sels[] = {"rcosc48M_div2", "osc", "rcosc400M", "rcosc16M", "pll1_div5", "pll2_sys", "pll2_pfd2", "pll3_pfd0"}; static int imxrt1170_clk_probe(struct udevice *dev) { void *base; /* Anatop clocks */ base = (void *)ofnode_get_addr(ofnode_by_compatible(ofnode_null(), "fsl,imxrt-anatop")); clk_dm(IMXRT1170_CLK_RCOSC_48M, imx_clk_fixed_factor("rcosc48M", "rcosc16M", 3, 1)); clk_dm(IMXRT1170_CLK_RCOSC_400M, imx_clk_fixed_factor("rcosc400M", "rcosc16M", 25, 1)); clk_dm(IMXRT1170_CLK_RCOSC_48M_DIV2, imx_clk_fixed_factor("rcosc48M_div2", "rcosc48M", 1, 2)); clk_dm(IMXRT1170_CLK_PLL_ARM, imx_clk_pllv3(IMX_PLLV3_SYS, "pll_arm", "osc", base + 0x200, 0xff)); clk_dm(IMXRT1170_CLK_PLL3, imx_clk_pllv3(IMX_PLLV3_GENERICV2, "pll3_sys", "osc", base + 0x210, 1)); clk_dm(IMXRT1170_CLK_PLL2, imx_clk_pllv3(IMX_PLLV3_GENERICV2, "pll2_sys", "osc", base + 0x240, 1)); clk_dm(IMXRT1170_CLK_PLL3_PFD0, imx_clk_pfd("pll3_pfd0", "pll3_sys", base + 0x230, 0)); clk_dm(IMXRT1170_CLK_PLL3_PFD1, imx_clk_pfd("pll3_pfd1", "pll3_sys", base + 0x230, 1)); clk_dm(IMXRT1170_CLK_PLL3_PFD2, imx_clk_pfd("pll3_pfd2", "pll3_sys", base + 0x230, 2)); clk_dm(IMXRT1170_CLK_PLL3_PFD3, imx_clk_pfd("pll3_pfd3", "pll3_sys", base + 0x230, 3)); clk_dm(IMXRT1170_CLK_PLL2_PFD0, imx_clk_pfd("pll2_pfd0", "pll2_sys", base + 0x270, 0)); clk_dm(IMXRT1170_CLK_PLL2_PFD1, imx_clk_pfd("pll2_pfd1", "pll2_sys", base + 0x270, 1)); clk_dm(IMXRT1170_CLK_PLL2_PFD2, imx_clk_pfd("pll2_pfd2", "pll2_sys", base + 0x270, 2)); clk_dm(IMXRT1170_CLK_PLL2_PFD3, imx_clk_pfd("pll2_pfd3", "pll2_sys", base + 0x270, 3)); clk_dm(IMXRT1170_CLK_PLL3_DIV2, imx_clk_fixed_factor("pll3_div2", "pll3_sys", 1, 2)); /* CCM clocks */ base = dev_read_addr_ptr(dev); if (base == (void *)FDT_ADDR_T_NONE) return -EINVAL; clk_dm(IMXRT1170_CLK_LPUART1_SEL, imx_clk_mux("lpuart1_sel", base + (25 * 0x80), 8, 3, lpuart1_sels, ARRAY_SIZE(lpuart1_sels))); clk_dm(IMXRT1170_CLK_LPUART1, imx_clk_divider("lpuart1", "lpuart1_sel", base + (25 * 0x80), 0, 8)); clk_dm(IMXRT1170_CLK_USDHC1_SEL, imx_clk_mux("usdhc1_sel", base + (58 * 0x80), 8, 3, usdhc1_sels, ARRAY_SIZE(usdhc1_sels))); clk_dm(IMXRT1170_CLK_USDHC1, imx_clk_divider("usdhc1", "usdhc1_sel", base + (58 * 0x80), 0, 8)); clk_dm(IMXRT1170_CLK_GPT1_SEL, imx_clk_mux("gpt1_sel", base + (14 * 0x80), 8, 3, gpt1_sels, ARRAY_SIZE(gpt1_sels))); clk_dm(IMXRT1170_CLK_GPT1, imx_clk_divider("gpt1", "gpt1_sel", base + (14 * 0x80), 0, 8)); clk_dm(IMXRT1170_CLK_SEMC_SEL, imx_clk_mux("semc_sel", base + (4 * 0x80), 8, 3, semc_sels, ARRAY_SIZE(semc_sels))); clk_dm(IMXRT1170_CLK_SEMC, imx_clk_divider("semc", "semc_sel", base + (4 * 0x80), 0, 8)); struct clk *clk, *clk1; clk_get_by_id(IMXRT1170_CLK_PLL2_PFD2, &clk); clk_get_by_id(IMXRT1170_CLK_SEMC_SEL, &clk1); clk_enable(clk1); clk_set_parent(clk1, clk); clk_get_by_id(IMXRT1170_CLK_SEMC, &clk); clk_enable(clk); clk_set_rate(clk, 132000000UL); clk_get_by_id(IMXRT1170_CLK_GPT1, &clk); clk_enable(clk); clk_set_rate(clk, 32000000UL); return 0; } static const struct udevice_id imxrt1170_clk_ids[] = { { .compatible = "fsl,imxrt1170-ccm" }, { }, }; U_BOOT_DRIVER(imxrt1170_clk) = { .name = "clk_imxrt1170", .id = UCLASS_CLK, .of_match = imxrt1170_clk_ids, .ops = &imxrt1170_clk_ops, .probe = imxrt1170_clk_probe, .flags = DM_FLAG_PRE_RELOC, };