Message ID | 20191204174439.69934-12-giulio.benetti@benettiengineering.com |
---|---|
State | Changes Requested |
Delegated to: | Stefano Babic |
Headers | show |
Series | Add i.MXRT family support | expand |
On Wed, 4 Dec 2019 18:44:30 +0100 Giulio Benetti <giulio.benetti@benettiengineering.com> wrote: > Add i.MXRT1050 clk driver support. > > Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com> > --- > drivers/clk/imx/Kconfig | 16 ++ > drivers/clk/imx/Makefile | 2 + > drivers/clk/imx/clk-imxrt1050.c | 292 > ++++++++++++++++++++ include/dt-bindings/clock/imxrt1050-clock.h | > 65 +++++ 4 files changed, 375 insertions(+) > create mode 100644 drivers/clk/imx/clk-imxrt1050.c > create mode 100644 include/dt-bindings/clock/imxrt1050-clock.h > > diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig > index 0ba8bc9f63..d5738b5211 100644 > --- a/drivers/clk/imx/Kconfig > +++ b/drivers/clk/imx/Kconfig > @@ -52,3 +52,19 @@ config CLK_IMX8MN > select CLK_CCF > help > This enables support clock driver for i.MX8MN platforms. > + > +config SPL_CLK_IMXRT1050 > + bool "SPL clock support for i.MXRT1050" > + depends on ARCH_IMXRT && SPL > + select SPL_CLK > + select SPL_CLK_CCF > + help > + This enables SPL DM/DTS support for clock driver in > i.MXRT1050 + > +config CLK_IMXRT1050 > + bool "Clock support for i.MXRT1050" > + depends on ARCH_IMXRT > + select CLK > + select CLK_CCF > + help > + This enables support clock driver for i.MXRT1050 platforms. > diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile > index 222c5a4e08..166cb7bb44 100644 > --- a/drivers/clk/imx/Makefile > +++ b/drivers/clk/imx/Makefile > @@ -14,3 +14,5 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += clk-imx8mm.o > clk-pll14xx.o \ clk-composite-8m.o > obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ > clk-composite-8m.o > + > +obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o > diff --git a/drivers/clk/imx/clk-imxrt1050.c > b/drivers/clk/imx/clk-imxrt1050.c new file mode 100644 > index 0000000000..44ca52c013 > --- /dev/null > +++ b/drivers/clk/imx/clk-imxrt1050.c > @@ -0,0 +1,292 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright(C) 2019 > + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com> > + */ > + > +#include <common.h> > +#include <clk.h> > +#include <clk-uclass.h> > +#include <dm.h> > +#include <asm/arch/clock.h> > +#include <asm/arch/imx-regs.h> > +#include <dt-bindings/clock/imxrt1050-clock.h> > + > +#include "clk.h" > + > +static ulong imxrt1050_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 imxrt1050_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 __imxrt1050_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 imxrt1050_clk_disable(struct clk *clk) > +{ > + return __imxrt1050_clk_enable(clk, 0); > +} > + > +static int imxrt1050_clk_enable(struct clk *clk) > +{ > + return __imxrt1050_clk_enable(clk, 1); > +} > + > +static struct clk_ops imxrt1050_clk_ops = { > + .set_rate = imxrt1050_clk_set_rate, > + .get_rate = imxrt1050_clk_get_rate, > + .enable = imxrt1050_clk_enable, > + .disable = imxrt1050_clk_disable, > +}; > + > +static const char * const pll_ref_sels[] = {"osc", "dummy", }; > +static const char * const pll1_bypass_sels[] = {"pll1_arm", > "pll1_arm_ref_sel", }; +static const char * const pll2_bypass_sels[] > = {"pll2_sys", "pll2_sys_ref_sel", }; +static const char * const > pll3_bypass_sels[] = {"pll3_usb_otg", "pll3_usb_otg_ref_sel", }; > +static const char * const pll5_bypass_sels[] = {"pll5_video", > "pll5_video_ref_sel", }; + +static const char *const > pre_periph_sels[] = { "pll2_sys", "pll2_pfd2_396m", "pll2_pfd0_352m", > "arm_podf", }; +static const char *const periph_sels[] = { > "pre_periph_sel", "todo", }; +static const char *const usdhc_sels[] = > { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *const > lpuart_sels[] = { "pll3_80m", "osc", }; +static const char *const > semc_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_664_62m", }; +static > const char *const semc_sels[] = { "periph_sel", "semc_alt_sel", }; > +static const char *const lcdif_sels[] = { "pll2_sys", > "pll3_pfd3_454_74m", "pll5_video:", "pll2_pfd0_352m", > "pll2_pfd1_594m", "pll3_pfd1_664_62m"}; + +static int > imxrt1050_clk_probe(struct udevice *dev) +{ > + void *base; > + > + /* Anatop clocks */ > + base = (void *)ANATOP_BASE_ADDR; > + > + clk_dm(IMXRT1050_CLK_PLL1_REF_SEL, > + imx_clk_mux("pll1_arm_ref_sel", base + 0x0, 14, 2, > + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); > + clk_dm(IMXRT1050_CLK_PLL2_REF_SEL, > + imx_clk_mux("pll2_sys_ref_sel", base + 0x30, 14, 2, > + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); > + clk_dm(IMXRT1050_CLK_PLL3_REF_SEL, > + imx_clk_mux("pll3_usb_otg_ref_sel", base + 0x10, 14, > 2, > + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); > + clk_dm(IMXRT1050_CLK_PLL5_REF_SEL, > + imx_clk_mux("pll5_video_ref_sel", base + 0xa0, 14, 2, > + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); > + > + clk_dm(IMXRT1050_CLK_PLL1_ARM, > + imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_arm", > "pll1_arm_ref_sel", > + base + 0x0, 0x7f)); > + clk_dm(IMXRT1050_CLK_PLL2_SYS, > + imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", > "pll2_sys_ref_sel", > + base + 0x30, 0x1)); > + clk_dm(IMXRT1050_CLK_PLL3_USB_OTG, > + imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", > + "pll3_usb_otg_ref_sel", > + base + 0x10, 0x1)); > + clk_dm(IMXRT1050_CLK_PLL5_VIDEO, > + imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", > "pll5_video_ref_sel", > + base + 0xa0, 0x7f)); > + > + /* PLL bypass out */ > + clk_dm(IMXRT1050_CLK_PLL1_BYPASS, > + imx_clk_mux_flags("pll1_bypass", base + 0x0, 16, 1, > + pll1_bypass_sels, > + ARRAY_SIZE(pll1_bypass_sels), > + CLK_SET_RATE_PARENT)); > + clk_dm(IMXRT1050_CLK_PLL2_BYPASS, > + imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, > + pll2_bypass_sels, > + ARRAY_SIZE(pll2_bypass_sels), > + CLK_SET_RATE_PARENT)); > + clk_dm(IMXRT1050_CLK_PLL3_BYPASS, > + imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, > + pll3_bypass_sels, > + ARRAY_SIZE(pll3_bypass_sels), > + CLK_SET_RATE_PARENT)); > + clk_dm(IMXRT1050_CLK_PLL5_BYPASS, > + imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, > + pll5_bypass_sels, > + ARRAY_SIZE(pll5_bypass_sels), > + CLK_SET_RATE_PARENT)); > + > + clk_dm(IMXRT1050_CLK_VIDEO_POST_DIV_SEL, > + imx_clk_divider("video_post_div_sel", "pll5_video", > + base + 0xa0, 19, 2)); > + clk_dm(IMXRT1050_CLK_VIDEO_DIV, > + imx_clk_divider("video_div", "video_post_div_sel", > + base + 0x170, 30, 2)); > + > + clk_dm(IMXRT1050_CLK_PLL3_80M, > + imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", > 1, 6)); + > + clk_dm(IMXRT1050_CLK_PLL2_PFD0_352M, > + imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + > 0x100, 0)); > + clk_dm(IMXRT1050_CLK_PLL2_PFD1_594M, > + imx_clk_pfd("pll2_pfd1_594m", "pll2_sys", base + > 0x100, 1)); > + clk_dm(IMXRT1050_CLK_PLL2_PFD2_396M, > + imx_clk_pfd("pll2_pfd2_396m", "pll2_sys", base + > 0x100, 2)); > + clk_dm(IMXRT1050_CLK_PLL3_PFD1_664_62M, > + imx_clk_pfd("pll3_pfd1_664_62m", "pll3_usb_otg", base > + 0xf0, > + 1)); > + clk_dm(IMXRT1050_CLK_PLL3_PFD3_454_74M, > + imx_clk_pfd("pll3_pfd3_454_74m", "pll3_usb_otg", base > + 0xf0, > + 3)); > + > + /* CCM clocks */ > + base = dev_read_addr_ptr(dev); > + if (base == (void *)FDT_ADDR_T_NONE) > + return -EINVAL; > + > + clk_dm(IMXRT1050_CLK_ARM_PODF, > + imx_clk_divider("arm_podf", "pll1_arm", > + base + 0x10, 0, 3)); > + > + clk_dm(IMXRT1050_CLK_PRE_PERIPH_SEL, > + imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, > + pre_periph_sels, > ARRAY_SIZE(pre_periph_sels))); > + clk_dm(IMXRT1050_CLK_PERIPH_SEL, > + imx_clk_mux("periph_sel", base + 0x14, 25, 1, > + periph_sels, ARRAY_SIZE(periph_sels))); > + clk_dm(IMXRT1050_CLK_USDHC1_SEL, > + imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, > + usdhc_sels, ARRAY_SIZE(usdhc_sels))); > + clk_dm(IMXRT1050_CLK_USDHC2_SEL, > + imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, > + usdhc_sels, ARRAY_SIZE(usdhc_sels))); > + clk_dm(IMXRT1050_CLK_LPUART_SEL, > + imx_clk_mux("lpuart_sel", base + 0x24, 6, 1, > + lpuart_sels, ARRAY_SIZE(lpuart_sels))); > + clk_dm(IMXRT1050_CLK_SEMC_ALT_SEL, > + imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1, > + semc_alt_sels, > ARRAY_SIZE(semc_alt_sels))); > + clk_dm(IMXRT1050_CLK_SEMC_SEL, > + imx_clk_mux("semc_sel", base + 0x14, 6, 1, > + semc_sels, ARRAY_SIZE(semc_sels))); > + clk_dm(IMXRT1050_CLK_LCDIF_SEL, > + imx_clk_mux("lcdif_sel", base + 0x38, 15, 3, > + lcdif_sels, ARRAY_SIZE(lcdif_sels))); > + > + clk_dm(IMXRT1050_CLK_AHB_PODF, > + imx_clk_divider("ahb_podf", "periph_sel", > + base + 0x14, 10, 3)); > + clk_dm(IMXRT1050_CLK_USDHC1_PODF, > + imx_clk_divider("usdhc1_podf", "usdhc1_sel", > + base + 0x24, 11, 3)); > + clk_dm(IMXRT1050_CLK_USDHC2_PODF, > + imx_clk_divider("usdhc2_podf", "usdhc2_sel", > + base + 0x24, 16, 3)); > + clk_dm(IMXRT1050_CLK_LPUART_PODF, > + imx_clk_divider("lpuart_podf", "lpuart_sel", > + base + 0x24, 0, 6)); > + clk_dm(IMXRT1050_CLK_SEMC_PODF, > + imx_clk_divider("semc_podf", "semc_sel", > + base + 0x14, 16, 3)); > + clk_dm(IMXRT1050_CLK_LCDIF_PRED, > + imx_clk_divider("lcdif_pred", "lcdif_sel", > + base + 0x38, 12, 3)); > + clk_dm(IMXRT1050_CLK_LCDIF_PODF, > + imx_clk_divider("lcdif_podf", "lcdif_pred", > + base + 0x18, 23, 3)); > + > + clk_dm(IMXRT1050_CLK_USDHC1, > + imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, > 2)); > + clk_dm(IMXRT1050_CLK_USDHC2, > + imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, > 4)); > + clk_dm(IMXRT1050_CLK_LPUART1, > + imx_clk_gate2("lpuart1", "lpuart_podf", base + 0x7c, > 24)); > + clk_dm(IMXRT1050_CLK_SEMC, > + imx_clk_gate2("semc", "semc_podf", base + 0x74, 4)); > + clk_dm(IMXRT1050_CLK_LCDIF, > + imx_clk_gate2("lcdif", "lcdif_podf", base + 0x70, > 28)); + > +#ifdef CONFIG_SPL_BUILD > + struct clk *clk, *clk1; > + > + /* bypass pll1 before setting its rate */ > + clk_get_by_id(IMXRT1050_CLK_PLL1_REF_SEL, &clk); > + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); > + clk_set_parent(clk1, clk); > + > + clk_get_by_id(IMXRT1050_CLK_PLL1_ARM, &clk); > + clk_enable(clk); > + clk_set_rate(clk, 1056000000UL); > + > + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); > + clk_set_parent(clk1, clk); > + > + clk_get_by_id(IMXRT1050_CLK_SEMC_SEL, &clk1); > + clk_get_by_id(IMXRT1050_CLK_SEMC_ALT_SEL, &clk); > + clk_set_parent(clk1, clk); > + > + clk_get_by_id(IMXRT1050_CLK_PLL2_SYS, &clk); > + clk_enable(clk); > + clk_set_rate(clk, 528000000UL); > + > + clk_get_by_id(IMXRT1050_CLK_PLL2_BYPASS, &clk1); > + clk_set_parent(clk1, clk); > + > + /* Configure PLL3_USB_OTG to 480MHz */ > + clk_get_by_id(IMXRT1050_CLK_PLL3_USB_OTG, &clk); > + clk_enable(clk); > + clk_set_rate(clk, 480000000UL); > + > + clk_get_by_id(IMXRT1050_CLK_PLL3_BYPASS, &clk1); > + clk_set_parent(clk1, clk); > + > +#endif > + > + return 0; > +} > + > +static const struct udevice_id imxrt1050_clk_ids[] = { > + { .compatible = "fsl,imxrt1050-ccm" }, > + { }, > +}; > + > +U_BOOT_DRIVER(imxrt1050_clk) = { > + .name = "clk_imxrt1050", > + .id = UCLASS_CLK, > + .of_match = imxrt1050_clk_ids, > + .ops = &imxrt1050_clk_ops, > + .probe = imxrt1050_clk_probe, > + .flags = DM_FLAG_PRE_RELOC, > +}; > diff --git a/include/dt-bindings/clock/imxrt1050-clock.h > b/include/dt-bindings/clock/imxrt1050-clock.h new file mode 100644 > index 0000000000..9f7f9be59f > --- /dev/null > +++ b/include/dt-bindings/clock/imxrt1050-clock.h > @@ -0,0 +1,65 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Copyright(C) 2019 > + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com> > + */ > + > +#ifndef __DT_BINDINGS_CLOCK_IMXRT1050_H > +#define __DT_BINDINGS_CLOCK_IMXRT1050_H > + > +#define IMXRT1050_CLK_DUMMY 0 > +#define IMXRT1050_CLK_CKIL 1 > +#define IMXRT1050_CLK_CKIH 2 > +#define IMXRT1050_CLK_OSC 3 > +#define IMXRT1050_CLK_PLL2_PFD0_352M 4 > +#define IMXRT1050_CLK_PLL2_PFD1_594M 5 > +#define IMXRT1050_CLK_PLL2_PFD2_396M 6 > +#define IMXRT1050_CLK_PLL3_PFD0_720M 7 > +#define IMXRT1050_CLK_PLL3_PFD1_664_62M 8 > +#define IMXRT1050_CLK_PLL3_PFD2_508_24M 9 > +#define IMXRT1050_CLK_PLL3_PFD3_454_74M 10 > +#define IMXRT1050_CLK_PLL2_198M 11 > +#define IMXRT1050_CLK_PLL3_120M 12 > +#define IMXRT1050_CLK_PLL3_80M 13 > +#define IMXRT1050_CLK_PLL3_60M 14 > +#define IMXRT1050_CLK_PLL1_BYPASS 15 > +#define IMXRT1050_CLK_PLL2_BYPASS 16 > +#define IMXRT1050_CLK_PLL3_BYPASS 17 > +#define IMXRT1050_CLK_PLL5_BYPASS 19 > +#define IMXRT1050_CLK_PLL1_REF_SEL 30 > +#define IMXRT1050_CLK_PLL2_REF_SEL 31 > +#define IMXRT1050_CLK_PLL3_REF_SEL 32 > +#define IMXRT1050_CLK_PLL5_REF_SEL 34 > +#define IMXRT1050_CLK_PRE_PERIPH_SEL 44 > +#define IMXRT1050_CLK_PERIPH_SEL 45 > +#define IMXRT1050_CLK_SEMC_ALT_SEL 46 > +#define IMXRT1050_CLK_SEMC_SEL 47 > +#define IMXRT1050_CLK_USDHC1_SEL 48 > +#define IMXRT1050_CLK_USDHC2_SEL 49 > +#define IMXRT1050_CLK_LPUART_SEL 50 > +#define IMXRT1050_CLK_LCDIF_SEL 51 > +#define IMXRT1050_CLK_VIDEO_POST_DIV_SEL 52 > +#define IMXRT1050_CLK_VIDEO_DIV 53 > +#define IMXRT1050_CLK_ARM_PODF 90 > +#define IMXRT1050_CLK_LPUART_PODF 91 > +#define IMXRT1050_CLK_USDHC1_PODF 92 > +#define IMXRT1050_CLK_USDHC2_PODF 93 > +#define IMXRT1050_CLK_SEMC_PODF 94 > +#define IMXRT1050_CLK_AHB_PODF 95 > +#define IMXRT1050_CLK_LCDIF_PRED 96 > +#define IMXRT1050_CLK_LCDIF_PODF 97 > +#define IMXRT1050_CLK_USDHC1 163 > +#define IMXRT1050_CLK_USDHC2 164 > +#define IMXRT1050_CLK_LPUART1 165 > +#define IMXRT1050_CLK_SEMC 166 > +#define IMXRT1050_CLK_LCDIF 167 > +#define IMXRT1050_CLK_PLL1_ARM 170 > +#define IMXRT1050_CLK_PLL2_SYS 171 > +#define IMXRT1050_CLK_PLL3_USB_OTG 172 > +#define IMXRT1050_CLK_PLL4_AUDIO 173 > +#define IMXRT1050_CLK_PLL5_VIDEO 174 > +#define IMXRT1050_CLK_PLL6_ENET 176 > +#define IMXRT1050_CLK_PLL7_USB_HOST 177 > +#define IMXRT1050_CLK_END 266 > + > +#endif /* __DT_BINDINGS_CLOCK_IMXRT1050_H */ Was this driver ported from Linux kernel? If yes - please add exact SHA1 and branch from which it was copied. This information shall be provided in the commit message. And thanks for providing this code to U-Boot :-) Best regards, Lukasz Majewski -- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
Hi Lukasz, On 12/8/19 3:40 PM, Lukasz Majewski wrote: > On Wed, 4 Dec 2019 18:44:30 +0100 > Giulio Benetti <giulio.benetti@benettiengineering.com> wrote: > >> Add i.MXRT1050 clk driver support. >> >> Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com> >> --- >> drivers/clk/imx/Kconfig | 16 ++ >> drivers/clk/imx/Makefile | 2 + >> drivers/clk/imx/clk-imxrt1050.c | 292 >> ++++++++++++++++++++ include/dt-bindings/clock/imxrt1050-clock.h | >> 65 +++++ 4 files changed, 375 insertions(+) >> create mode 100644 drivers/clk/imx/clk-imxrt1050.c >> create mode 100644 include/dt-bindings/clock/imxrt1050-clock.h >> >> diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig >> index 0ba8bc9f63..d5738b5211 100644 >> --- a/drivers/clk/imx/Kconfig >> +++ b/drivers/clk/imx/Kconfig >> @@ -52,3 +52,19 @@ config CLK_IMX8MN >> select CLK_CCF >> help >> This enables support clock driver for i.MX8MN platforms. >> + >> +config SPL_CLK_IMXRT1050 >> + bool "SPL clock support for i.MXRT1050" >> + depends on ARCH_IMXRT && SPL >> + select SPL_CLK >> + select SPL_CLK_CCF >> + help >> + This enables SPL DM/DTS support for clock driver in >> i.MXRT1050 + >> +config CLK_IMXRT1050 >> + bool "Clock support for i.MXRT1050" >> + depends on ARCH_IMXRT >> + select CLK >> + select CLK_CCF >> + help >> + This enables support clock driver for i.MXRT1050 platforms. >> diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile >> index 222c5a4e08..166cb7bb44 100644 >> --- a/drivers/clk/imx/Makefile >> +++ b/drivers/clk/imx/Makefile >> @@ -14,3 +14,5 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += clk-imx8mm.o >> clk-pll14xx.o \ clk-composite-8m.o >> obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ >> clk-composite-8m.o >> + >> +obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o >> diff --git a/drivers/clk/imx/clk-imxrt1050.c >> b/drivers/clk/imx/clk-imxrt1050.c new file mode 100644 >> index 0000000000..44ca52c013 >> --- /dev/null >> +++ b/drivers/clk/imx/clk-imxrt1050.c >> @@ -0,0 +1,292 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Copyright(C) 2019 >> + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com> >> + */ >> + >> +#include <common.h> >> +#include <clk.h> >> +#include <clk-uclass.h> >> +#include <dm.h> >> +#include <asm/arch/clock.h> >> +#include <asm/arch/imx-regs.h> >> +#include <dt-bindings/clock/imxrt1050-clock.h> >> + >> +#include "clk.h" >> + >> +static ulong imxrt1050_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 imxrt1050_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 __imxrt1050_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 imxrt1050_clk_disable(struct clk *clk) >> +{ >> + return __imxrt1050_clk_enable(clk, 0); >> +} >> + >> +static int imxrt1050_clk_enable(struct clk *clk) >> +{ >> + return __imxrt1050_clk_enable(clk, 1); >> +} >> + >> +static struct clk_ops imxrt1050_clk_ops = { >> + .set_rate = imxrt1050_clk_set_rate, >> + .get_rate = imxrt1050_clk_get_rate, >> + .enable = imxrt1050_clk_enable, >> + .disable = imxrt1050_clk_disable, >> +}; >> + >> +static const char * const pll_ref_sels[] = {"osc", "dummy", }; >> +static const char * const pll1_bypass_sels[] = {"pll1_arm", >> "pll1_arm_ref_sel", }; +static const char * const pll2_bypass_sels[] >> = {"pll2_sys", "pll2_sys_ref_sel", }; +static const char * const >> pll3_bypass_sels[] = {"pll3_usb_otg", "pll3_usb_otg_ref_sel", }; >> +static const char * const pll5_bypass_sels[] = {"pll5_video", >> "pll5_video_ref_sel", }; + +static const char *const >> pre_periph_sels[] = { "pll2_sys", "pll2_pfd2_396m", "pll2_pfd0_352m", >> "arm_podf", }; +static const char *const periph_sels[] = { >> "pre_periph_sel", "todo", }; +static const char *const usdhc_sels[] = >> { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *const >> lpuart_sels[] = { "pll3_80m", "osc", }; +static const char *const >> semc_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_664_62m", }; +static >> const char *const semc_sels[] = { "periph_sel", "semc_alt_sel", }; >> +static const char *const lcdif_sels[] = { "pll2_sys", >> "pll3_pfd3_454_74m", "pll5_video:", "pll2_pfd0_352m", >> "pll2_pfd1_594m", "pll3_pfd1_664_62m"}; + +static int >> imxrt1050_clk_probe(struct udevice *dev) +{ >> + void *base; >> + >> + /* Anatop clocks */ >> + base = (void *)ANATOP_BASE_ADDR; >> + >> + clk_dm(IMXRT1050_CLK_PLL1_REF_SEL, >> + imx_clk_mux("pll1_arm_ref_sel", base + 0x0, 14, 2, >> + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); >> + clk_dm(IMXRT1050_CLK_PLL2_REF_SEL, >> + imx_clk_mux("pll2_sys_ref_sel", base + 0x30, 14, 2, >> + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); >> + clk_dm(IMXRT1050_CLK_PLL3_REF_SEL, >> + imx_clk_mux("pll3_usb_otg_ref_sel", base + 0x10, 14, >> 2, >> + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); >> + clk_dm(IMXRT1050_CLK_PLL5_REF_SEL, >> + imx_clk_mux("pll5_video_ref_sel", base + 0xa0, 14, 2, >> + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); >> + >> + clk_dm(IMXRT1050_CLK_PLL1_ARM, >> + imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_arm", >> "pll1_arm_ref_sel", >> + base + 0x0, 0x7f)); >> + clk_dm(IMXRT1050_CLK_PLL2_SYS, >> + imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", >> "pll2_sys_ref_sel", >> + base + 0x30, 0x1)); >> + clk_dm(IMXRT1050_CLK_PLL3_USB_OTG, >> + imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", >> + "pll3_usb_otg_ref_sel", >> + base + 0x10, 0x1)); >> + clk_dm(IMXRT1050_CLK_PLL5_VIDEO, >> + imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", >> "pll5_video_ref_sel", >> + base + 0xa0, 0x7f)); >> + >> + /* PLL bypass out */ >> + clk_dm(IMXRT1050_CLK_PLL1_BYPASS, >> + imx_clk_mux_flags("pll1_bypass", base + 0x0, 16, 1, >> + pll1_bypass_sels, >> + ARRAY_SIZE(pll1_bypass_sels), >> + CLK_SET_RATE_PARENT)); >> + clk_dm(IMXRT1050_CLK_PLL2_BYPASS, >> + imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, >> + pll2_bypass_sels, >> + ARRAY_SIZE(pll2_bypass_sels), >> + CLK_SET_RATE_PARENT)); >> + clk_dm(IMXRT1050_CLK_PLL3_BYPASS, >> + imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, >> + pll3_bypass_sels, >> + ARRAY_SIZE(pll3_bypass_sels), >> + CLK_SET_RATE_PARENT)); >> + clk_dm(IMXRT1050_CLK_PLL5_BYPASS, >> + imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, >> + pll5_bypass_sels, >> + ARRAY_SIZE(pll5_bypass_sels), >> + CLK_SET_RATE_PARENT)); >> + >> + clk_dm(IMXRT1050_CLK_VIDEO_POST_DIV_SEL, >> + imx_clk_divider("video_post_div_sel", "pll5_video", >> + base + 0xa0, 19, 2)); >> + clk_dm(IMXRT1050_CLK_VIDEO_DIV, >> + imx_clk_divider("video_div", "video_post_div_sel", >> + base + 0x170, 30, 2)); >> + >> + clk_dm(IMXRT1050_CLK_PLL3_80M, >> + imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", >> 1, 6)); + >> + clk_dm(IMXRT1050_CLK_PLL2_PFD0_352M, >> + imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + >> 0x100, 0)); >> + clk_dm(IMXRT1050_CLK_PLL2_PFD1_594M, >> + imx_clk_pfd("pll2_pfd1_594m", "pll2_sys", base + >> 0x100, 1)); >> + clk_dm(IMXRT1050_CLK_PLL2_PFD2_396M, >> + imx_clk_pfd("pll2_pfd2_396m", "pll2_sys", base + >> 0x100, 2)); >> + clk_dm(IMXRT1050_CLK_PLL3_PFD1_664_62M, >> + imx_clk_pfd("pll3_pfd1_664_62m", "pll3_usb_otg", base >> + 0xf0, >> + 1)); >> + clk_dm(IMXRT1050_CLK_PLL3_PFD3_454_74M, >> + imx_clk_pfd("pll3_pfd3_454_74m", "pll3_usb_otg", base >> + 0xf0, >> + 3)); >> + >> + /* CCM clocks */ >> + base = dev_read_addr_ptr(dev); >> + if (base == (void *)FDT_ADDR_T_NONE) >> + return -EINVAL; >> + >> + clk_dm(IMXRT1050_CLK_ARM_PODF, >> + imx_clk_divider("arm_podf", "pll1_arm", >> + base + 0x10, 0, 3)); >> + >> + clk_dm(IMXRT1050_CLK_PRE_PERIPH_SEL, >> + imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, >> + pre_periph_sels, >> ARRAY_SIZE(pre_periph_sels))); >> + clk_dm(IMXRT1050_CLK_PERIPH_SEL, >> + imx_clk_mux("periph_sel", base + 0x14, 25, 1, >> + periph_sels, ARRAY_SIZE(periph_sels))); >> + clk_dm(IMXRT1050_CLK_USDHC1_SEL, >> + imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, >> + usdhc_sels, ARRAY_SIZE(usdhc_sels))); >> + clk_dm(IMXRT1050_CLK_USDHC2_SEL, >> + imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, >> + usdhc_sels, ARRAY_SIZE(usdhc_sels))); >> + clk_dm(IMXRT1050_CLK_LPUART_SEL, >> + imx_clk_mux("lpuart_sel", base + 0x24, 6, 1, >> + lpuart_sels, ARRAY_SIZE(lpuart_sels))); >> + clk_dm(IMXRT1050_CLK_SEMC_ALT_SEL, >> + imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1, >> + semc_alt_sels, >> ARRAY_SIZE(semc_alt_sels))); >> + clk_dm(IMXRT1050_CLK_SEMC_SEL, >> + imx_clk_mux("semc_sel", base + 0x14, 6, 1, >> + semc_sels, ARRAY_SIZE(semc_sels))); >> + clk_dm(IMXRT1050_CLK_LCDIF_SEL, >> + imx_clk_mux("lcdif_sel", base + 0x38, 15, 3, >> + lcdif_sels, ARRAY_SIZE(lcdif_sels))); >> + >> + clk_dm(IMXRT1050_CLK_AHB_PODF, >> + imx_clk_divider("ahb_podf", "periph_sel", >> + base + 0x14, 10, 3)); >> + clk_dm(IMXRT1050_CLK_USDHC1_PODF, >> + imx_clk_divider("usdhc1_podf", "usdhc1_sel", >> + base + 0x24, 11, 3)); >> + clk_dm(IMXRT1050_CLK_USDHC2_PODF, >> + imx_clk_divider("usdhc2_podf", "usdhc2_sel", >> + base + 0x24, 16, 3)); >> + clk_dm(IMXRT1050_CLK_LPUART_PODF, >> + imx_clk_divider("lpuart_podf", "lpuart_sel", >> + base + 0x24, 0, 6)); >> + clk_dm(IMXRT1050_CLK_SEMC_PODF, >> + imx_clk_divider("semc_podf", "semc_sel", >> + base + 0x14, 16, 3)); >> + clk_dm(IMXRT1050_CLK_LCDIF_PRED, >> + imx_clk_divider("lcdif_pred", "lcdif_sel", >> + base + 0x38, 12, 3)); >> + clk_dm(IMXRT1050_CLK_LCDIF_PODF, >> + imx_clk_divider("lcdif_podf", "lcdif_pred", >> + base + 0x18, 23, 3)); >> + >> + clk_dm(IMXRT1050_CLK_USDHC1, >> + imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, >> 2)); >> + clk_dm(IMXRT1050_CLK_USDHC2, >> + imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, >> 4)); >> + clk_dm(IMXRT1050_CLK_LPUART1, >> + imx_clk_gate2("lpuart1", "lpuart_podf", base + 0x7c, >> 24)); >> + clk_dm(IMXRT1050_CLK_SEMC, >> + imx_clk_gate2("semc", "semc_podf", base + 0x74, 4)); >> + clk_dm(IMXRT1050_CLK_LCDIF, >> + imx_clk_gate2("lcdif", "lcdif_podf", base + 0x70, >> 28)); + >> +#ifdef CONFIG_SPL_BUILD >> + struct clk *clk, *clk1; >> + >> + /* bypass pll1 before setting its rate */ >> + clk_get_by_id(IMXRT1050_CLK_PLL1_REF_SEL, &clk); >> + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); >> + clk_set_parent(clk1, clk); >> + >> + clk_get_by_id(IMXRT1050_CLK_PLL1_ARM, &clk); >> + clk_enable(clk); >> + clk_set_rate(clk, 1056000000UL); >> + >> + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); >> + clk_set_parent(clk1, clk); >> + >> + clk_get_by_id(IMXRT1050_CLK_SEMC_SEL, &clk1); >> + clk_get_by_id(IMXRT1050_CLK_SEMC_ALT_SEL, &clk); >> + clk_set_parent(clk1, clk); >> + >> + clk_get_by_id(IMXRT1050_CLK_PLL2_SYS, &clk); >> + clk_enable(clk); >> + clk_set_rate(clk, 528000000UL); >> + >> + clk_get_by_id(IMXRT1050_CLK_PLL2_BYPASS, &clk1); >> + clk_set_parent(clk1, clk); >> + >> + /* Configure PLL3_USB_OTG to 480MHz */ >> + clk_get_by_id(IMXRT1050_CLK_PLL3_USB_OTG, &clk); >> + clk_enable(clk); >> + clk_set_rate(clk, 480000000UL); >> + >> + clk_get_by_id(IMXRT1050_CLK_PLL3_BYPASS, &clk1); >> + clk_set_parent(clk1, clk); >> + >> +#endif >> + >> + return 0; >> +} >> + >> +static const struct udevice_id imxrt1050_clk_ids[] = { >> + { .compatible = "fsl,imxrt1050-ccm" }, >> + { }, >> +}; >> + >> +U_BOOT_DRIVER(imxrt1050_clk) = { >> + .name = "clk_imxrt1050", >> + .id = UCLASS_CLK, >> + .of_match = imxrt1050_clk_ids, >> + .ops = &imxrt1050_clk_ops, >> + .probe = imxrt1050_clk_probe, >> + .flags = DM_FLAG_PRE_RELOC, >> +}; >> diff --git a/include/dt-bindings/clock/imxrt1050-clock.h >> b/include/dt-bindings/clock/imxrt1050-clock.h new file mode 100644 >> index 0000000000..9f7f9be59f >> --- /dev/null >> +++ b/include/dt-bindings/clock/imxrt1050-clock.h >> @@ -0,0 +1,65 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* >> + * Copyright(C) 2019 >> + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com> >> + */ >> + >> +#ifndef __DT_BINDINGS_CLOCK_IMXRT1050_H >> +#define __DT_BINDINGS_CLOCK_IMXRT1050_H >> + >> +#define IMXRT1050_CLK_DUMMY 0 >> +#define IMXRT1050_CLK_CKIL 1 >> +#define IMXRT1050_CLK_CKIH 2 >> +#define IMXRT1050_CLK_OSC 3 >> +#define IMXRT1050_CLK_PLL2_PFD0_352M 4 >> +#define IMXRT1050_CLK_PLL2_PFD1_594M 5 >> +#define IMXRT1050_CLK_PLL2_PFD2_396M 6 >> +#define IMXRT1050_CLK_PLL3_PFD0_720M 7 >> +#define IMXRT1050_CLK_PLL3_PFD1_664_62M 8 >> +#define IMXRT1050_CLK_PLL3_PFD2_508_24M 9 >> +#define IMXRT1050_CLK_PLL3_PFD3_454_74M 10 >> +#define IMXRT1050_CLK_PLL2_198M 11 >> +#define IMXRT1050_CLK_PLL3_120M 12 >> +#define IMXRT1050_CLK_PLL3_80M 13 >> +#define IMXRT1050_CLK_PLL3_60M 14 >> +#define IMXRT1050_CLK_PLL1_BYPASS 15 >> +#define IMXRT1050_CLK_PLL2_BYPASS 16 >> +#define IMXRT1050_CLK_PLL3_BYPASS 17 >> +#define IMXRT1050_CLK_PLL5_BYPASS 19 >> +#define IMXRT1050_CLK_PLL1_REF_SEL 30 >> +#define IMXRT1050_CLK_PLL2_REF_SEL 31 >> +#define IMXRT1050_CLK_PLL3_REF_SEL 32 >> +#define IMXRT1050_CLK_PLL5_REF_SEL 34 >> +#define IMXRT1050_CLK_PRE_PERIPH_SEL 44 >> +#define IMXRT1050_CLK_PERIPH_SEL 45 >> +#define IMXRT1050_CLK_SEMC_ALT_SEL 46 >> +#define IMXRT1050_CLK_SEMC_SEL 47 >> +#define IMXRT1050_CLK_USDHC1_SEL 48 >> +#define IMXRT1050_CLK_USDHC2_SEL 49 >> +#define IMXRT1050_CLK_LPUART_SEL 50 >> +#define IMXRT1050_CLK_LCDIF_SEL 51 >> +#define IMXRT1050_CLK_VIDEO_POST_DIV_SEL 52 >> +#define IMXRT1050_CLK_VIDEO_DIV 53 >> +#define IMXRT1050_CLK_ARM_PODF 90 >> +#define IMXRT1050_CLK_LPUART_PODF 91 >> +#define IMXRT1050_CLK_USDHC1_PODF 92 >> +#define IMXRT1050_CLK_USDHC2_PODF 93 >> +#define IMXRT1050_CLK_SEMC_PODF 94 >> +#define IMXRT1050_CLK_AHB_PODF 95 >> +#define IMXRT1050_CLK_LCDIF_PRED 96 >> +#define IMXRT1050_CLK_LCDIF_PODF 97 >> +#define IMXRT1050_CLK_USDHC1 163 >> +#define IMXRT1050_CLK_USDHC2 164 >> +#define IMXRT1050_CLK_LPUART1 165 >> +#define IMXRT1050_CLK_SEMC 166 >> +#define IMXRT1050_CLK_LCDIF 167 >> +#define IMXRT1050_CLK_PLL1_ARM 170 >> +#define IMXRT1050_CLK_PLL2_SYS 171 >> +#define IMXRT1050_CLK_PLL3_USB_OTG 172 >> +#define IMXRT1050_CLK_PLL4_AUDIO 173 >> +#define IMXRT1050_CLK_PLL5_VIDEO 174 >> +#define IMXRT1050_CLK_PLL6_ENET 176 >> +#define IMXRT1050_CLK_PLL7_USB_HOST 177 >> +#define IMXRT1050_CLK_END 266 >> + >> +#endif /* __DT_BINDINGS_CLOCK_IMXRT1050_H */ > > Was this driver ported from Linux kernel? If yes - please add exact > SHA1 and branch from which it was copied. No, I've written it from scratch and only after I will add it to Linux. > This information shall be > provided in the commit message. I keep it in mind eventually for next patches, thank for pointing me that. > > And thanks for providing this code to U-Boot :-) It's a pleasure and a good training for me :-) Best regards
Forgotten to ask you... On 12/9/19 11:49 AM, Giulio Benetti wrote: > Hi Lukasz, > > On 12/8/19 3:40 PM, Lukasz Majewski wrote: >> On Wed, 4 Dec 2019 18:44:30 +0100 >> Giulio Benetti <giulio.benetti@benettiengineering.com> wrote: >> >>> Add i.MXRT1050 clk driver support. >>> >>> Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com> >>> --- >>> drivers/clk/imx/Kconfig | 16 ++ >>> drivers/clk/imx/Makefile | 2 + >>> drivers/clk/imx/clk-imxrt1050.c | 292 >>> ++++++++++++++++++++ include/dt-bindings/clock/imxrt1050-clock.h | >>> 65 +++++ 4 files changed, 375 insertions(+) >>> create mode 100644 drivers/clk/imx/clk-imxrt1050.c >>> create mode 100644 include/dt-bindings/clock/imxrt1050-clock.h >>> >>> diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig >>> index 0ba8bc9f63..d5738b5211 100644 >>> --- a/drivers/clk/imx/Kconfig >>> +++ b/drivers/clk/imx/Kconfig >>> @@ -52,3 +52,19 @@ config CLK_IMX8MN >>> select CLK_CCF >>> help >>> This enables support clock driver for i.MX8MN platforms. >>> + >>> +config SPL_CLK_IMXRT1050 >>> + bool "SPL clock support for i.MXRT1050" >>> + depends on ARCH_IMXRT && SPL >>> + select SPL_CLK >>> + select SPL_CLK_CCF >>> + help >>> + This enables SPL DM/DTS support for clock driver in >>> i.MXRT1050 + >>> +config CLK_IMXRT1050 >>> + bool "Clock support for i.MXRT1050" >>> + depends on ARCH_IMXRT >>> + select CLK >>> + select CLK_CCF >>> + help >>> + This enables support clock driver for i.MXRT1050 platforms. >>> diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile >>> index 222c5a4e08..166cb7bb44 100644 >>> --- a/drivers/clk/imx/Makefile >>> +++ b/drivers/clk/imx/Makefile >>> @@ -14,3 +14,5 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += clk-imx8mm.o >>> clk-pll14xx.o \ clk-composite-8m.o >>> obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ >>> clk-composite-8m.o >>> + >>> +obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o >>> diff --git a/drivers/clk/imx/clk-imxrt1050.c >>> b/drivers/clk/imx/clk-imxrt1050.c new file mode 100644 >>> index 0000000000..44ca52c013 >>> --- /dev/null >>> +++ b/drivers/clk/imx/clk-imxrt1050.c >>> @@ -0,0 +1,292 @@ >>> +// SPDX-License-Identifier: GPL-2.0+ >>> +/* >>> + * Copyright(C) 2019 >>> + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com> >>> + */ >>> + >>> +#include <common.h> >>> +#include <clk.h> >>> +#include <clk-uclass.h> >>> +#include <dm.h> >>> +#include <asm/arch/clock.h> >>> +#include <asm/arch/imx-regs.h> >>> +#include <dt-bindings/clock/imxrt1050-clock.h> >>> + >>> +#include "clk.h" >>> + >>> +static ulong imxrt1050_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 imxrt1050_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 __imxrt1050_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 imxrt1050_clk_disable(struct clk *clk) >>> +{ >>> + return __imxrt1050_clk_enable(clk, 0); >>> +} >>> + >>> +static int imxrt1050_clk_enable(struct clk *clk) >>> +{ >>> + return __imxrt1050_clk_enable(clk, 1); >>> +} >>> + >>> +static struct clk_ops imxrt1050_clk_ops = { >>> + .set_rate = imxrt1050_clk_set_rate, >>> + .get_rate = imxrt1050_clk_get_rate, >>> + .enable = imxrt1050_clk_enable, >>> + .disable = imxrt1050_clk_disable, >>> +}; >>> + >>> +static const char * const pll_ref_sels[] = {"osc", "dummy", }; >>> +static const char * const pll1_bypass_sels[] = {"pll1_arm", >>> "pll1_arm_ref_sel", }; +static const char * const pll2_bypass_sels[] >>> = {"pll2_sys", "pll2_sys_ref_sel", }; +static const char * const >>> pll3_bypass_sels[] = {"pll3_usb_otg", "pll3_usb_otg_ref_sel", }; >>> +static const char * const pll5_bypass_sels[] = {"pll5_video", >>> "pll5_video_ref_sel", }; + +static const char *const >>> pre_periph_sels[] = { "pll2_sys", "pll2_pfd2_396m", "pll2_pfd0_352m", >>> "arm_podf", }; +static const char *const periph_sels[] = { >>> "pre_periph_sel", "todo", }; +static const char *const usdhc_sels[] = >>> { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *const >>> lpuart_sels[] = { "pll3_80m", "osc", }; +static const char *const >>> semc_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_664_62m", }; +static >>> const char *const semc_sels[] = { "periph_sel", "semc_alt_sel", }; >>> +static const char *const lcdif_sels[] = { "pll2_sys", >>> "pll3_pfd3_454_74m", "pll5_video:", "pll2_pfd0_352m", >>> "pll2_pfd1_594m", "pll3_pfd1_664_62m"}; + +static int >>> imxrt1050_clk_probe(struct udevice *dev) +{ >>> + void *base; >>> + >>> + /* Anatop clocks */ >>> + base = (void *)ANATOP_BASE_ADDR; >>> + >>> + clk_dm(IMXRT1050_CLK_PLL1_REF_SEL, >>> + imx_clk_mux("pll1_arm_ref_sel", base + 0x0, 14, 2, >>> + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); >>> + clk_dm(IMXRT1050_CLK_PLL2_REF_SEL, >>> + imx_clk_mux("pll2_sys_ref_sel", base + 0x30, 14, 2, >>> + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); >>> + clk_dm(IMXRT1050_CLK_PLL3_REF_SEL, >>> + imx_clk_mux("pll3_usb_otg_ref_sel", base + 0x10, 14, >>> 2, >>> + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); >>> + clk_dm(IMXRT1050_CLK_PLL5_REF_SEL, >>> + imx_clk_mux("pll5_video_ref_sel", base + 0xa0, 14, 2, >>> + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); >>> + >>> + clk_dm(IMXRT1050_CLK_PLL1_ARM, >>> + imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_arm", >>> "pll1_arm_ref_sel", >>> + base + 0x0, 0x7f)); >>> + clk_dm(IMXRT1050_CLK_PLL2_SYS, >>> + imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", >>> "pll2_sys_ref_sel", >>> + base + 0x30, 0x1)); >>> + clk_dm(IMXRT1050_CLK_PLL3_USB_OTG, >>> + imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", >>> + "pll3_usb_otg_ref_sel", >>> + base + 0x10, 0x1)); >>> + clk_dm(IMXRT1050_CLK_PLL5_VIDEO, >>> + imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", >>> "pll5_video_ref_sel", >>> + base + 0xa0, 0x7f)); >>> + >>> + /* PLL bypass out */ >>> + clk_dm(IMXRT1050_CLK_PLL1_BYPASS, >>> + imx_clk_mux_flags("pll1_bypass", base + 0x0, 16, 1, >>> + pll1_bypass_sels, >>> + ARRAY_SIZE(pll1_bypass_sels), >>> + CLK_SET_RATE_PARENT)); >>> + clk_dm(IMXRT1050_CLK_PLL2_BYPASS, >>> + imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, >>> + pll2_bypass_sels, >>> + ARRAY_SIZE(pll2_bypass_sels), >>> + CLK_SET_RATE_PARENT)); >>> + clk_dm(IMXRT1050_CLK_PLL3_BYPASS, >>> + imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, >>> + pll3_bypass_sels, >>> + ARRAY_SIZE(pll3_bypass_sels), >>> + CLK_SET_RATE_PARENT)); >>> + clk_dm(IMXRT1050_CLK_PLL5_BYPASS, >>> + imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, >>> + pll5_bypass_sels, >>> + ARRAY_SIZE(pll5_bypass_sels), >>> + CLK_SET_RATE_PARENT)); >>> + >>> + clk_dm(IMXRT1050_CLK_VIDEO_POST_DIV_SEL, >>> + imx_clk_divider("video_post_div_sel", "pll5_video", >>> + base + 0xa0, 19, 2)); >>> + clk_dm(IMXRT1050_CLK_VIDEO_DIV, >>> + imx_clk_divider("video_div", "video_post_div_sel", >>> + base + 0x170, 30, 2)); >>> + >>> + clk_dm(IMXRT1050_CLK_PLL3_80M, >>> + imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", >>> 1, 6)); + >>> + clk_dm(IMXRT1050_CLK_PLL2_PFD0_352M, >>> + imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + >>> 0x100, 0)); >>> + clk_dm(IMXRT1050_CLK_PLL2_PFD1_594M, >>> + imx_clk_pfd("pll2_pfd1_594m", "pll2_sys", base + >>> 0x100, 1)); >>> + clk_dm(IMXRT1050_CLK_PLL2_PFD2_396M, >>> + imx_clk_pfd("pll2_pfd2_396m", "pll2_sys", base + >>> 0x100, 2)); >>> + clk_dm(IMXRT1050_CLK_PLL3_PFD1_664_62M, >>> + imx_clk_pfd("pll3_pfd1_664_62m", "pll3_usb_otg", base >>> + 0xf0, >>> + 1)); >>> + clk_dm(IMXRT1050_CLK_PLL3_PFD3_454_74M, >>> + imx_clk_pfd("pll3_pfd3_454_74m", "pll3_usb_otg", base >>> + 0xf0, >>> + 3)); >>> + >>> + /* CCM clocks */ >>> + base = dev_read_addr_ptr(dev); >>> + if (base == (void *)FDT_ADDR_T_NONE) >>> + return -EINVAL; >>> + >>> + clk_dm(IMXRT1050_CLK_ARM_PODF, >>> + imx_clk_divider("arm_podf", "pll1_arm", >>> + base + 0x10, 0, 3)); >>> + >>> + clk_dm(IMXRT1050_CLK_PRE_PERIPH_SEL, >>> + imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, >>> + pre_periph_sels, >>> ARRAY_SIZE(pre_periph_sels))); >>> + clk_dm(IMXRT1050_CLK_PERIPH_SEL, >>> + imx_clk_mux("periph_sel", base + 0x14, 25, 1, >>> + periph_sels, ARRAY_SIZE(periph_sels))); >>> + clk_dm(IMXRT1050_CLK_USDHC1_SEL, >>> + imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, >>> + usdhc_sels, ARRAY_SIZE(usdhc_sels))); >>> + clk_dm(IMXRT1050_CLK_USDHC2_SEL, >>> + imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, >>> + usdhc_sels, ARRAY_SIZE(usdhc_sels))); >>> + clk_dm(IMXRT1050_CLK_LPUART_SEL, >>> + imx_clk_mux("lpuart_sel", base + 0x24, 6, 1, >>> + lpuart_sels, ARRAY_SIZE(lpuart_sels))); >>> + clk_dm(IMXRT1050_CLK_SEMC_ALT_SEL, >>> + imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1, >>> + semc_alt_sels, >>> ARRAY_SIZE(semc_alt_sels))); >>> + clk_dm(IMXRT1050_CLK_SEMC_SEL, >>> + imx_clk_mux("semc_sel", base + 0x14, 6, 1, >>> + semc_sels, ARRAY_SIZE(semc_sels))); >>> + clk_dm(IMXRT1050_CLK_LCDIF_SEL, >>> + imx_clk_mux("lcdif_sel", base + 0x38, 15, 3, >>> + lcdif_sels, ARRAY_SIZE(lcdif_sels))); >>> + >>> + clk_dm(IMXRT1050_CLK_AHB_PODF, >>> + imx_clk_divider("ahb_podf", "periph_sel", >>> + base + 0x14, 10, 3)); >>> + clk_dm(IMXRT1050_CLK_USDHC1_PODF, >>> + imx_clk_divider("usdhc1_podf", "usdhc1_sel", >>> + base + 0x24, 11, 3)); >>> + clk_dm(IMXRT1050_CLK_USDHC2_PODF, >>> + imx_clk_divider("usdhc2_podf", "usdhc2_sel", >>> + base + 0x24, 16, 3)); >>> + clk_dm(IMXRT1050_CLK_LPUART_PODF, >>> + imx_clk_divider("lpuart_podf", "lpuart_sel", >>> + base + 0x24, 0, 6)); >>> + clk_dm(IMXRT1050_CLK_SEMC_PODF, >>> + imx_clk_divider("semc_podf", "semc_sel", >>> + base + 0x14, 16, 3)); >>> + clk_dm(IMXRT1050_CLK_LCDIF_PRED, >>> + imx_clk_divider("lcdif_pred", "lcdif_sel", >>> + base + 0x38, 12, 3)); >>> + clk_dm(IMXRT1050_CLK_LCDIF_PODF, >>> + imx_clk_divider("lcdif_podf", "lcdif_pred", >>> + base + 0x18, 23, 3)); >>> + >>> + clk_dm(IMXRT1050_CLK_USDHC1, >>> + imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, >>> 2)); >>> + clk_dm(IMXRT1050_CLK_USDHC2, >>> + imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, >>> 4)); >>> + clk_dm(IMXRT1050_CLK_LPUART1, >>> + imx_clk_gate2("lpuart1", "lpuart_podf", base + 0x7c, >>> 24)); >>> + clk_dm(IMXRT1050_CLK_SEMC, >>> + imx_clk_gate2("semc", "semc_podf", base + 0x74, 4)); >>> + clk_dm(IMXRT1050_CLK_LCDIF, >>> + imx_clk_gate2("lcdif", "lcdif_podf", base + 0x70, >>> 28)); + >>> +#ifdef CONFIG_SPL_BUILD >>> + struct clk *clk, *clk1; >>> + >>> + /* bypass pll1 before setting its rate */ >>> + clk_get_by_id(IMXRT1050_CLK_PLL1_REF_SEL, &clk); >>> + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); >>> + clk_set_parent(clk1, clk); >>> + >>> + clk_get_by_id(IMXRT1050_CLK_PLL1_ARM, &clk); >>> + clk_enable(clk); >>> + clk_set_rate(clk, 1056000000UL); >>> + >>> + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); >>> + clk_set_parent(clk1, clk); >>> + >>> + clk_get_by_id(IMXRT1050_CLK_SEMC_SEL, &clk1); >>> + clk_get_by_id(IMXRT1050_CLK_SEMC_ALT_SEL, &clk); >>> + clk_set_parent(clk1, clk); >>> + >>> + clk_get_by_id(IMXRT1050_CLK_PLL2_SYS, &clk); >>> + clk_enable(clk); >>> + clk_set_rate(clk, 528000000UL); >>> + >>> + clk_get_by_id(IMXRT1050_CLK_PLL2_BYPASS, &clk1); >>> + clk_set_parent(clk1, clk); >>> + >>> + /* Configure PLL3_USB_OTG to 480MHz */ >>> + clk_get_by_id(IMXRT1050_CLK_PLL3_USB_OTG, &clk); >>> + clk_enable(clk); >>> + clk_set_rate(clk, 480000000UL); >>> + >>> + clk_get_by_id(IMXRT1050_CLK_PLL3_BYPASS, &clk1); >>> + clk_set_parent(clk1, clk); >>> + >>> +#endif >>> + >>> + return 0; >>> +} >>> + >>> +static const struct udevice_id imxrt1050_clk_ids[] = { >>> + { .compatible = "fsl,imxrt1050-ccm" }, >>> + { }, >>> +}; >>> + >>> +U_BOOT_DRIVER(imxrt1050_clk) = { >>> + .name = "clk_imxrt1050", >>> + .id = UCLASS_CLK, >>> + .of_match = imxrt1050_clk_ids, >>> + .ops = &imxrt1050_clk_ops, >>> + .probe = imxrt1050_clk_probe, >>> + .flags = DM_FLAG_PRE_RELOC, >>> +}; >>> diff --git a/include/dt-bindings/clock/imxrt1050-clock.h >>> b/include/dt-bindings/clock/imxrt1050-clock.h new file mode 100644 >>> index 0000000000..9f7f9be59f >>> --- /dev/null >>> +++ b/include/dt-bindings/clock/imxrt1050-clock.h >>> @@ -0,0 +1,65 @@ >>> +/* SPDX-License-Identifier: GPL-2.0+ */ >>> +/* >>> + * Copyright(C) 2019 >>> + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com> >>> + */ >>> + >>> +#ifndef __DT_BINDINGS_CLOCK_IMXRT1050_H >>> +#define __DT_BINDINGS_CLOCK_IMXRT1050_H >>> + >>> +#define IMXRT1050_CLK_DUMMY 0 >>> +#define IMXRT1050_CLK_CKIL 1 >>> +#define IMXRT1050_CLK_CKIH 2 >>> +#define IMXRT1050_CLK_OSC 3 >>> +#define IMXRT1050_CLK_PLL2_PFD0_352M 4 >>> +#define IMXRT1050_CLK_PLL2_PFD1_594M 5 >>> +#define IMXRT1050_CLK_PLL2_PFD2_396M 6 >>> +#define IMXRT1050_CLK_PLL3_PFD0_720M 7 >>> +#define IMXRT1050_CLK_PLL3_PFD1_664_62M 8 >>> +#define IMXRT1050_CLK_PLL3_PFD2_508_24M 9 >>> +#define IMXRT1050_CLK_PLL3_PFD3_454_74M 10 >>> +#define IMXRT1050_CLK_PLL2_198M 11 >>> +#define IMXRT1050_CLK_PLL3_120M 12 >>> +#define IMXRT1050_CLK_PLL3_80M 13 >>> +#define IMXRT1050_CLK_PLL3_60M 14 >>> +#define IMXRT1050_CLK_PLL1_BYPASS 15 >>> +#define IMXRT1050_CLK_PLL2_BYPASS 16 >>> +#define IMXRT1050_CLK_PLL3_BYPASS 17 >>> +#define IMXRT1050_CLK_PLL5_BYPASS 19 >>> +#define IMXRT1050_CLK_PLL1_REF_SEL 30 >>> +#define IMXRT1050_CLK_PLL2_REF_SEL 31 >>> +#define IMXRT1050_CLK_PLL3_REF_SEL 32 >>> +#define IMXRT1050_CLK_PLL5_REF_SEL 34 >>> +#define IMXRT1050_CLK_PRE_PERIPH_SEL 44 >>> +#define IMXRT1050_CLK_PERIPH_SEL 45 >>> +#define IMXRT1050_CLK_SEMC_ALT_SEL 46 >>> +#define IMXRT1050_CLK_SEMC_SEL 47 >>> +#define IMXRT1050_CLK_USDHC1_SEL 48 >>> +#define IMXRT1050_CLK_USDHC2_SEL 49 >>> +#define IMXRT1050_CLK_LPUART_SEL 50 >>> +#define IMXRT1050_CLK_LCDIF_SEL 51 >>> +#define IMXRT1050_CLK_VIDEO_POST_DIV_SEL 52 >>> +#define IMXRT1050_CLK_VIDEO_DIV 53 >>> +#define IMXRT1050_CLK_ARM_PODF 90 >>> +#define IMXRT1050_CLK_LPUART_PODF 91 >>> +#define IMXRT1050_CLK_USDHC1_PODF 92 >>> +#define IMXRT1050_CLK_USDHC2_PODF 93 >>> +#define IMXRT1050_CLK_SEMC_PODF 94 >>> +#define IMXRT1050_CLK_AHB_PODF 95 >>> +#define IMXRT1050_CLK_LCDIF_PRED 96 >>> +#define IMXRT1050_CLK_LCDIF_PODF 97 >>> +#define IMXRT1050_CLK_USDHC1 163 >>> +#define IMXRT1050_CLK_USDHC2 164 >>> +#define IMXRT1050_CLK_LPUART1 165 >>> +#define IMXRT1050_CLK_SEMC 166 >>> +#define IMXRT1050_CLK_LCDIF 167 >>> +#define IMXRT1050_CLK_PLL1_ARM 170 >>> +#define IMXRT1050_CLK_PLL2_SYS 171 >>> +#define IMXRT1050_CLK_PLL3_USB_OTG 172 >>> +#define IMXRT1050_CLK_PLL4_AUDIO 173 >>> +#define IMXRT1050_CLK_PLL5_VIDEO 174 >>> +#define IMXRT1050_CLK_PLL6_ENET 176 >>> +#define IMXRT1050_CLK_PLL7_USB_HOST 177 >>> +#define IMXRT1050_CLK_END 266 Here all the clocks have number "holes", since it's probable I'll have to add other clocks in the middle, but this breaks *_CLK_END count. Would it be better if I compact all the indexes and move them when I will add new clocks? Best regards
On Mon, 9 Dec 2019 11:53:05 +0100 Giulio Benetti <giulio.benetti@benettiengineering.com> wrote: > Forgotten to ask you... > > On 12/9/19 11:49 AM, Giulio Benetti wrote: > > Hi Lukasz, > > > > On 12/8/19 3:40 PM, Lukasz Majewski wrote: > >> On Wed, 4 Dec 2019 18:44:30 +0100 > >> Giulio Benetti <giulio.benetti@benettiengineering.com> wrote: > >> > >>> Add i.MXRT1050 clk driver support. > >>> > >>> Signed-off-by: Giulio Benetti > >>> <giulio.benetti@benettiengineering.com> --- > >>> drivers/clk/imx/Kconfig | 16 ++ > >>> drivers/clk/imx/Makefile | 2 + > >>> drivers/clk/imx/clk-imxrt1050.c | 292 > >>> ++++++++++++++++++++ include/dt-bindings/clock/imxrt1050-clock.h | > >>> 65 +++++ 4 files changed, 375 insertions(+) > >>> create mode 100644 drivers/clk/imx/clk-imxrt1050.c > >>> create mode 100644 include/dt-bindings/clock/imxrt1050-clock.h > >>> > >>> diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig > >>> index 0ba8bc9f63..d5738b5211 100644 > >>> --- a/drivers/clk/imx/Kconfig > >>> +++ b/drivers/clk/imx/Kconfig > >>> @@ -52,3 +52,19 @@ config CLK_IMX8MN > >>> select CLK_CCF > >>> help > >>> This enables support clock driver for i.MX8MN > >>> platforms. + > >>> +config SPL_CLK_IMXRT1050 > >>> + bool "SPL clock support for i.MXRT1050" > >>> + depends on ARCH_IMXRT && SPL > >>> + select SPL_CLK > >>> + select SPL_CLK_CCF > >>> + help > >>> + This enables SPL DM/DTS support for clock driver in > >>> i.MXRT1050 + > >>> +config CLK_IMXRT1050 > >>> + bool "Clock support for i.MXRT1050" > >>> + depends on ARCH_IMXRT > >>> + select CLK > >>> + select CLK_CCF > >>> + help > >>> + This enables support clock driver for i.MXRT1050 > >>> platforms. diff --git a/drivers/clk/imx/Makefile > >>> b/drivers/clk/imx/Makefile index 222c5a4e08..166cb7bb44 100644 > >>> --- a/drivers/clk/imx/Makefile > >>> +++ b/drivers/clk/imx/Makefile > >>> @@ -14,3 +14,5 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += > >>> clk-imx8mm.o clk-pll14xx.o \ clk-composite-8m.o > >>> obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o > >>> clk-pll14xx.o \ clk-composite-8m.o > >>> + > >>> +obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o > >>> diff --git a/drivers/clk/imx/clk-imxrt1050.c > >>> b/drivers/clk/imx/clk-imxrt1050.c new file mode 100644 > >>> index 0000000000..44ca52c013 > >>> --- /dev/null > >>> +++ b/drivers/clk/imx/clk-imxrt1050.c > >>> @@ -0,0 +1,292 @@ > >>> +// SPDX-License-Identifier: GPL-2.0+ > >>> +/* > >>> + * Copyright(C) 2019 > >>> + * Author(s): Giulio Benetti > >>> <giulio.benetti@benettiengineering.com> > >>> + */ > >>> + > >>> +#include <common.h> > >>> +#include <clk.h> > >>> +#include <clk-uclass.h> > >>> +#include <dm.h> > >>> +#include <asm/arch/clock.h> > >>> +#include <asm/arch/imx-regs.h> > >>> +#include <dt-bindings/clock/imxrt1050-clock.h> > >>> + > >>> +#include "clk.h" > >>> + > >>> +static ulong imxrt1050_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 imxrt1050_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 __imxrt1050_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 imxrt1050_clk_disable(struct clk *clk) > >>> +{ > >>> + return __imxrt1050_clk_enable(clk, 0); > >>> +} > >>> + > >>> +static int imxrt1050_clk_enable(struct clk *clk) > >>> +{ > >>> + return __imxrt1050_clk_enable(clk, 1); > >>> +} > >>> + > >>> +static struct clk_ops imxrt1050_clk_ops = { > >>> + .set_rate = imxrt1050_clk_set_rate, > >>> + .get_rate = imxrt1050_clk_get_rate, > >>> + .enable = imxrt1050_clk_enable, > >>> + .disable = imxrt1050_clk_disable, > >>> +}; > >>> + > >>> +static const char * const pll_ref_sels[] = {"osc", "dummy", }; > >>> +static const char * const pll1_bypass_sels[] = {"pll1_arm", > >>> "pll1_arm_ref_sel", }; +static const char * const > >>> pll2_bypass_sels[] = {"pll2_sys", "pll2_sys_ref_sel", }; +static > >>> const char * const pll3_bypass_sels[] = {"pll3_usb_otg", > >>> "pll3_usb_otg_ref_sel", }; +static const char * const > >>> pll5_bypass_sels[] = {"pll5_video", "pll5_video_ref_sel", }; + > >>> +static const char *const pre_periph_sels[] = { "pll2_sys", > >>> "pll2_pfd2_396m", "pll2_pfd0_352m", "arm_podf", }; +static const > >>> char *const periph_sels[] = { "pre_periph_sel", "todo", }; > >>> +static const char *const usdhc_sels[] = { "pll2_pfd2_396m", > >>> "pll2_pfd0_352m", }; +static const char *const lpuart_sels[] = { > >>> "pll3_80m", "osc", }; +static const char *const semc_alt_sels[] = > >>> { "pll2_pfd2_396m", "pll3_pfd1_664_62m", }; +static const char > >>> *const semc_sels[] = { "periph_sel", "semc_alt_sel", }; +static > >>> const char *const lcdif_sels[] = { "pll2_sys", > >>> "pll3_pfd3_454_74m", "pll5_video:", "pll2_pfd0_352m", > >>> "pll2_pfd1_594m", "pll3_pfd1_664_62m"}; + +static int > >>> imxrt1050_clk_probe(struct udevice *dev) +{ > >>> + void *base; > >>> + > >>> + /* Anatop clocks */ > >>> + base = (void *)ANATOP_BASE_ADDR; > >>> + > >>> + clk_dm(IMXRT1050_CLK_PLL1_REF_SEL, > >>> + imx_clk_mux("pll1_arm_ref_sel", base + 0x0, 14, 2, > >>> + pll_ref_sels, > >>> ARRAY_SIZE(pll_ref_sels))); > >>> + clk_dm(IMXRT1050_CLK_PLL2_REF_SEL, > >>> + imx_clk_mux("pll2_sys_ref_sel", base + 0x30, 14, > >>> 2, > >>> + pll_ref_sels, > >>> ARRAY_SIZE(pll_ref_sels))); > >>> + clk_dm(IMXRT1050_CLK_PLL3_REF_SEL, > >>> + imx_clk_mux("pll3_usb_otg_ref_sel", base + 0x10, > >>> 14, 2, > >>> + pll_ref_sels, > >>> ARRAY_SIZE(pll_ref_sels))); > >>> + clk_dm(IMXRT1050_CLK_PLL5_REF_SEL, > >>> + imx_clk_mux("pll5_video_ref_sel", base + 0xa0, > >>> 14, 2, > >>> + pll_ref_sels, > >>> ARRAY_SIZE(pll_ref_sels))); + > >>> + clk_dm(IMXRT1050_CLK_PLL1_ARM, > >>> + imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_arm", > >>> "pll1_arm_ref_sel", > >>> + base + 0x0, 0x7f)); > >>> + clk_dm(IMXRT1050_CLK_PLL2_SYS, > >>> + imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", > >>> "pll2_sys_ref_sel", > >>> + base + 0x30, 0x1)); > >>> + clk_dm(IMXRT1050_CLK_PLL3_USB_OTG, > >>> + imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", > >>> + "pll3_usb_otg_ref_sel", > >>> + base + 0x10, 0x1)); > >>> + clk_dm(IMXRT1050_CLK_PLL5_VIDEO, > >>> + imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", > >>> "pll5_video_ref_sel", > >>> + base + 0xa0, 0x7f)); > >>> + > >>> + /* PLL bypass out */ > >>> + clk_dm(IMXRT1050_CLK_PLL1_BYPASS, > >>> + imx_clk_mux_flags("pll1_bypass", base + 0x0, 16, > >>> 1, > >>> + pll1_bypass_sels, > >>> + ARRAY_SIZE(pll1_bypass_sels), > >>> + CLK_SET_RATE_PARENT)); > >>> + clk_dm(IMXRT1050_CLK_PLL2_BYPASS, > >>> + imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, > >>> 1, > >>> + pll2_bypass_sels, > >>> + ARRAY_SIZE(pll2_bypass_sels), > >>> + CLK_SET_RATE_PARENT)); > >>> + clk_dm(IMXRT1050_CLK_PLL3_BYPASS, > >>> + imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, > >>> 1, > >>> + pll3_bypass_sels, > >>> + ARRAY_SIZE(pll3_bypass_sels), > >>> + CLK_SET_RATE_PARENT)); > >>> + clk_dm(IMXRT1050_CLK_PLL5_BYPASS, > >>> + imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, > >>> 1, > >>> + pll5_bypass_sels, > >>> + ARRAY_SIZE(pll5_bypass_sels), > >>> + CLK_SET_RATE_PARENT)); > >>> + > >>> + clk_dm(IMXRT1050_CLK_VIDEO_POST_DIV_SEL, > >>> + imx_clk_divider("video_post_div_sel", > >>> "pll5_video", > >>> + base + 0xa0, 19, 2)); > >>> + clk_dm(IMXRT1050_CLK_VIDEO_DIV, > >>> + imx_clk_divider("video_div", "video_post_div_sel", > >>> + base + 0x170, 30, 2)); > >>> + > >>> + clk_dm(IMXRT1050_CLK_PLL3_80M, > >>> + imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", > >>> 1, 6)); + > >>> + clk_dm(IMXRT1050_CLK_PLL2_PFD0_352M, > >>> + imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + > >>> 0x100, 0)); > >>> + clk_dm(IMXRT1050_CLK_PLL2_PFD1_594M, > >>> + imx_clk_pfd("pll2_pfd1_594m", "pll2_sys", base + > >>> 0x100, 1)); > >>> + clk_dm(IMXRT1050_CLK_PLL2_PFD2_396M, > >>> + imx_clk_pfd("pll2_pfd2_396m", "pll2_sys", base + > >>> 0x100, 2)); > >>> + clk_dm(IMXRT1050_CLK_PLL3_PFD1_664_62M, > >>> + imx_clk_pfd("pll3_pfd1_664_62m", "pll3_usb_otg", > >>> base > >>> + 0xf0, > >>> + 1)); > >>> + clk_dm(IMXRT1050_CLK_PLL3_PFD3_454_74M, > >>> + imx_clk_pfd("pll3_pfd3_454_74m", "pll3_usb_otg", > >>> base > >>> + 0xf0, > >>> + 3)); > >>> + > >>> + /* CCM clocks */ > >>> + base = dev_read_addr_ptr(dev); > >>> + if (base == (void *)FDT_ADDR_T_NONE) > >>> + return -EINVAL; > >>> + > >>> + clk_dm(IMXRT1050_CLK_ARM_PODF, > >>> + imx_clk_divider("arm_podf", "pll1_arm", > >>> + base + 0x10, 0, 3)); > >>> + > >>> + clk_dm(IMXRT1050_CLK_PRE_PERIPH_SEL, > >>> + imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, > >>> + pre_periph_sels, > >>> ARRAY_SIZE(pre_periph_sels))); > >>> + clk_dm(IMXRT1050_CLK_PERIPH_SEL, > >>> + imx_clk_mux("periph_sel", base + 0x14, 25, 1, > >>> + periph_sels, > >>> ARRAY_SIZE(periph_sels))); > >>> + clk_dm(IMXRT1050_CLK_USDHC1_SEL, > >>> + imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, > >>> + usdhc_sels, ARRAY_SIZE(usdhc_sels))); > >>> + clk_dm(IMXRT1050_CLK_USDHC2_SEL, > >>> + imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, > >>> + usdhc_sels, ARRAY_SIZE(usdhc_sels))); > >>> + clk_dm(IMXRT1050_CLK_LPUART_SEL, > >>> + imx_clk_mux("lpuart_sel", base + 0x24, 6, 1, > >>> + lpuart_sels, > >>> ARRAY_SIZE(lpuart_sels))); > >>> + clk_dm(IMXRT1050_CLK_SEMC_ALT_SEL, > >>> + imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1, > >>> + semc_alt_sels, > >>> ARRAY_SIZE(semc_alt_sels))); > >>> + clk_dm(IMXRT1050_CLK_SEMC_SEL, > >>> + imx_clk_mux("semc_sel", base + 0x14, 6, 1, > >>> + semc_sels, ARRAY_SIZE(semc_sels))); > >>> + clk_dm(IMXRT1050_CLK_LCDIF_SEL, > >>> + imx_clk_mux("lcdif_sel", base + 0x38, 15, 3, > >>> + lcdif_sels, ARRAY_SIZE(lcdif_sels))); > >>> + > >>> + clk_dm(IMXRT1050_CLK_AHB_PODF, > >>> + imx_clk_divider("ahb_podf", "periph_sel", > >>> + base + 0x14, 10, 3)); > >>> + clk_dm(IMXRT1050_CLK_USDHC1_PODF, > >>> + imx_clk_divider("usdhc1_podf", "usdhc1_sel", > >>> + base + 0x24, 11, 3)); > >>> + clk_dm(IMXRT1050_CLK_USDHC2_PODF, > >>> + imx_clk_divider("usdhc2_podf", "usdhc2_sel", > >>> + base + 0x24, 16, 3)); > >>> + clk_dm(IMXRT1050_CLK_LPUART_PODF, > >>> + imx_clk_divider("lpuart_podf", "lpuart_sel", > >>> + base + 0x24, 0, 6)); > >>> + clk_dm(IMXRT1050_CLK_SEMC_PODF, > >>> + imx_clk_divider("semc_podf", "semc_sel", > >>> + base + 0x14, 16, 3)); > >>> + clk_dm(IMXRT1050_CLK_LCDIF_PRED, > >>> + imx_clk_divider("lcdif_pred", "lcdif_sel", > >>> + base + 0x38, 12, 3)); > >>> + clk_dm(IMXRT1050_CLK_LCDIF_PODF, > >>> + imx_clk_divider("lcdif_podf", "lcdif_pred", > >>> + base + 0x18, 23, 3)); > >>> + > >>> + clk_dm(IMXRT1050_CLK_USDHC1, > >>> + imx_clk_gate2("usdhc1", "usdhc1_podf", base + > >>> 0x80, 2)); > >>> + clk_dm(IMXRT1050_CLK_USDHC2, > >>> + imx_clk_gate2("usdhc2", "usdhc2_podf", base + > >>> 0x80, 4)); > >>> + clk_dm(IMXRT1050_CLK_LPUART1, > >>> + imx_clk_gate2("lpuart1", "lpuart_podf", base + > >>> 0x7c, 24)); > >>> + clk_dm(IMXRT1050_CLK_SEMC, > >>> + imx_clk_gate2("semc", "semc_podf", base + 0x74, > >>> 4)); > >>> + clk_dm(IMXRT1050_CLK_LCDIF, > >>> + imx_clk_gate2("lcdif", "lcdif_podf", base + 0x70, > >>> 28)); + > >>> +#ifdef CONFIG_SPL_BUILD > >>> + struct clk *clk, *clk1; > >>> + > >>> + /* bypass pll1 before setting its rate */ > >>> + clk_get_by_id(IMXRT1050_CLK_PLL1_REF_SEL, &clk); > >>> + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); > >>> + clk_set_parent(clk1, clk); > >>> + > >>> + clk_get_by_id(IMXRT1050_CLK_PLL1_ARM, &clk); > >>> + clk_enable(clk); > >>> + clk_set_rate(clk, 1056000000UL); > >>> + > >>> + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); > >>> + clk_set_parent(clk1, clk); > >>> + > >>> + clk_get_by_id(IMXRT1050_CLK_SEMC_SEL, &clk1); > >>> + clk_get_by_id(IMXRT1050_CLK_SEMC_ALT_SEL, &clk); > >>> + clk_set_parent(clk1, clk); > >>> + > >>> + clk_get_by_id(IMXRT1050_CLK_PLL2_SYS, &clk); > >>> + clk_enable(clk); > >>> + clk_set_rate(clk, 528000000UL); > >>> + > >>> + clk_get_by_id(IMXRT1050_CLK_PLL2_BYPASS, &clk1); > >>> + clk_set_parent(clk1, clk); > >>> + > >>> + /* Configure PLL3_USB_OTG to 480MHz */ > >>> + clk_get_by_id(IMXRT1050_CLK_PLL3_USB_OTG, &clk); > >>> + clk_enable(clk); > >>> + clk_set_rate(clk, 480000000UL); > >>> + > >>> + clk_get_by_id(IMXRT1050_CLK_PLL3_BYPASS, &clk1); > >>> + clk_set_parent(clk1, clk); > >>> + > >>> +#endif > >>> + > >>> + return 0; > >>> +} > >>> + > >>> +static const struct udevice_id imxrt1050_clk_ids[] = { > >>> + { .compatible = "fsl,imxrt1050-ccm" }, > >>> + { }, > >>> +}; > >>> + > >>> +U_BOOT_DRIVER(imxrt1050_clk) = { > >>> + .name = "clk_imxrt1050", > >>> + .id = UCLASS_CLK, > >>> + .of_match = imxrt1050_clk_ids, > >>> + .ops = &imxrt1050_clk_ops, > >>> + .probe = imxrt1050_clk_probe, > >>> + .flags = DM_FLAG_PRE_RELOC, > >>> +}; > >>> diff --git a/include/dt-bindings/clock/imxrt1050-clock.h > >>> b/include/dt-bindings/clock/imxrt1050-clock.h new file mode 100644 > >>> index 0000000000..9f7f9be59f > >>> --- /dev/null > >>> +++ b/include/dt-bindings/clock/imxrt1050-clock.h > >>> @@ -0,0 +1,65 @@ > >>> +/* SPDX-License-Identifier: GPL-2.0+ */ > >>> +/* > >>> + * Copyright(C) 2019 > >>> + * Author(s): Giulio Benetti > >>> <giulio.benetti@benettiengineering.com> > >>> + */ > >>> + > >>> +#ifndef __DT_BINDINGS_CLOCK_IMXRT1050_H > >>> +#define __DT_BINDINGS_CLOCK_IMXRT1050_H > >>> + > >>> +#define IMXRT1050_CLK_DUMMY 0 > >>> +#define IMXRT1050_CLK_CKIL 1 > >>> +#define IMXRT1050_CLK_CKIH 2 > >>> +#define IMXRT1050_CLK_OSC 3 > >>> +#define IMXRT1050_CLK_PLL2_PFD0_352M 4 > >>> +#define IMXRT1050_CLK_PLL2_PFD1_594M 5 > >>> +#define IMXRT1050_CLK_PLL2_PFD2_396M 6 > >>> +#define IMXRT1050_CLK_PLL3_PFD0_720M 7 > >>> +#define IMXRT1050_CLK_PLL3_PFD1_664_62M 8 > >>> +#define IMXRT1050_CLK_PLL3_PFD2_508_24M 9 > >>> +#define IMXRT1050_CLK_PLL3_PFD3_454_74M 10 > >>> +#define IMXRT1050_CLK_PLL2_198M 11 > >>> +#define IMXRT1050_CLK_PLL3_120M 12 > >>> +#define IMXRT1050_CLK_PLL3_80M 13 > >>> +#define IMXRT1050_CLK_PLL3_60M 14 > >>> +#define IMXRT1050_CLK_PLL1_BYPASS 15 > >>> +#define IMXRT1050_CLK_PLL2_BYPASS 16 > >>> +#define IMXRT1050_CLK_PLL3_BYPASS 17 > >>> +#define IMXRT1050_CLK_PLL5_BYPASS 19 > >>> +#define IMXRT1050_CLK_PLL1_REF_SEL 30 > >>> +#define IMXRT1050_CLK_PLL2_REF_SEL 31 > >>> +#define IMXRT1050_CLK_PLL3_REF_SEL 32 > >>> +#define IMXRT1050_CLK_PLL5_REF_SEL 34 > >>> +#define IMXRT1050_CLK_PRE_PERIPH_SEL 44 > >>> +#define IMXRT1050_CLK_PERIPH_SEL 45 > >>> +#define IMXRT1050_CLK_SEMC_ALT_SEL 46 > >>> +#define IMXRT1050_CLK_SEMC_SEL 47 > >>> +#define IMXRT1050_CLK_USDHC1_SEL 48 > >>> +#define IMXRT1050_CLK_USDHC2_SEL 49 > >>> +#define IMXRT1050_CLK_LPUART_SEL 50 > >>> +#define IMXRT1050_CLK_LCDIF_SEL 51 > >>> +#define IMXRT1050_CLK_VIDEO_POST_DIV_SEL 52 > >>> +#define IMXRT1050_CLK_VIDEO_DIV 53 > >>> +#define IMXRT1050_CLK_ARM_PODF 90 > >>> +#define IMXRT1050_CLK_LPUART_PODF 91 > >>> +#define IMXRT1050_CLK_USDHC1_PODF 92 > >>> +#define IMXRT1050_CLK_USDHC2_PODF 93 > >>> +#define IMXRT1050_CLK_SEMC_PODF 94 > >>> +#define IMXRT1050_CLK_AHB_PODF 95 > >>> +#define IMXRT1050_CLK_LCDIF_PRED 96 > >>> +#define IMXRT1050_CLK_LCDIF_PODF 97 > >>> +#define IMXRT1050_CLK_USDHC1 163 > >>> +#define IMXRT1050_CLK_USDHC2 164 > >>> +#define IMXRT1050_CLK_LPUART1 165 > >>> +#define IMXRT1050_CLK_SEMC 166 > >>> +#define IMXRT1050_CLK_LCDIF 167 > >>> +#define IMXRT1050_CLK_PLL1_ARM 170 > >>> +#define IMXRT1050_CLK_PLL2_SYS 171 > >>> +#define IMXRT1050_CLK_PLL3_USB_OTG 172 > >>> +#define IMXRT1050_CLK_PLL4_AUDIO 173 > >>> +#define IMXRT1050_CLK_PLL5_VIDEO 174 > >>> +#define IMXRT1050_CLK_PLL6_ENET 176 > >>> +#define IMXRT1050_CLK_PLL7_USB_HOST 177 > >>> +#define IMXRT1050_CLK_END 266 > > Here all the clocks have number "holes", since it's probable I'll > have to add other clocks in the middle, but this breaks *_CLK_END > count. Would it be better if I compact all the indexes and move them > when I will add new clocks? Please be in sync with the Linux kernel CCF driver for i.MX SoC. When I was porting the driver from Linux to U-Boot I've realized that one would need at least +1KiB of RAM/OCRAM to accommodate the original driver's clock structures. For that reason I've put those clocks in U-Boot in linked-list, which is less memory hungry (and with the assumption that we just set clocks once during boot it seems to be good enough). > > Best regards Best regards, Lukasz Majewski -- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
Hi Lukasz, On 12/10/19 12:36 AM, Lukasz Majewski wrote: > On Mon, 9 Dec 2019 11:53:05 +0100 > Giulio Benetti <giulio.benetti@benettiengineering.com> wrote: > >> Forgotten to ask you... >> >> On 12/9/19 11:49 AM, Giulio Benetti wrote: >>> Hi Lukasz, >>> >>> On 12/8/19 3:40 PM, Lukasz Majewski wrote: >>>> On Wed, 4 Dec 2019 18:44:30 +0100 >>>> Giulio Benetti <giulio.benetti@benettiengineering.com> wrote: >>>> >>>>> Add i.MXRT1050 clk driver support. >>>>> >>>>> Signed-off-by: Giulio Benetti >>>>> <giulio.benetti@benettiengineering.com> --- >>>>> drivers/clk/imx/Kconfig | 16 ++ >>>>> drivers/clk/imx/Makefile | 2 + >>>>> drivers/clk/imx/clk-imxrt1050.c | 292 >>>>> ++++++++++++++++++++ include/dt-bindings/clock/imxrt1050-clock.h | >>>>> 65 +++++ 4 files changed, 375 insertions(+) >>>>> create mode 100644 drivers/clk/imx/clk-imxrt1050.c >>>>> create mode 100644 include/dt-bindings/clock/imxrt1050-clock.h >>>>> >>>>> diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig >>>>> index 0ba8bc9f63..d5738b5211 100644 >>>>> --- a/drivers/clk/imx/Kconfig >>>>> +++ b/drivers/clk/imx/Kconfig >>>>> @@ -52,3 +52,19 @@ config CLK_IMX8MN >>>>> select CLK_CCF >>>>> help >>>>> This enables support clock driver for i.MX8MN >>>>> platforms. + >>>>> +config SPL_CLK_IMXRT1050 >>>>> + bool "SPL clock support for i.MXRT1050" >>>>> + depends on ARCH_IMXRT && SPL >>>>> + select SPL_CLK >>>>> + select SPL_CLK_CCF >>>>> + help >>>>> + This enables SPL DM/DTS support for clock driver in >>>>> i.MXRT1050 + >>>>> +config CLK_IMXRT1050 >>>>> + bool "Clock support for i.MXRT1050" >>>>> + depends on ARCH_IMXRT >>>>> + select CLK >>>>> + select CLK_CCF >>>>> + help >>>>> + This enables support clock driver for i.MXRT1050 >>>>> platforms. diff --git a/drivers/clk/imx/Makefile >>>>> b/drivers/clk/imx/Makefile index 222c5a4e08..166cb7bb44 100644 >>>>> --- a/drivers/clk/imx/Makefile >>>>> +++ b/drivers/clk/imx/Makefile >>>>> @@ -14,3 +14,5 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += >>>>> clk-imx8mm.o clk-pll14xx.o \ clk-composite-8m.o >>>>> obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o >>>>> clk-pll14xx.o \ clk-composite-8m.o >>>>> + >>>>> +obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o >>>>> diff --git a/drivers/clk/imx/clk-imxrt1050.c >>>>> b/drivers/clk/imx/clk-imxrt1050.c new file mode 100644 >>>>> index 0000000000..44ca52c013 >>>>> --- /dev/null >>>>> +++ b/drivers/clk/imx/clk-imxrt1050.c >>>>> @@ -0,0 +1,292 @@ >>>>> +// SPDX-License-Identifier: GPL-2.0+ >>>>> +/* >>>>> + * Copyright(C) 2019 >>>>> + * Author(s): Giulio Benetti >>>>> <giulio.benetti@benettiengineering.com> >>>>> + */ >>>>> + >>>>> +#include <common.h> >>>>> +#include <clk.h> >>>>> +#include <clk-uclass.h> >>>>> +#include <dm.h> >>>>> +#include <asm/arch/clock.h> >>>>> +#include <asm/arch/imx-regs.h> >>>>> +#include <dt-bindings/clock/imxrt1050-clock.h> >>>>> + >>>>> +#include "clk.h" >>>>> + >>>>> +static ulong imxrt1050_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 imxrt1050_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 __imxrt1050_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 imxrt1050_clk_disable(struct clk *clk) >>>>> +{ >>>>> + return __imxrt1050_clk_enable(clk, 0); >>>>> +} >>>>> + >>>>> +static int imxrt1050_clk_enable(struct clk *clk) >>>>> +{ >>>>> + return __imxrt1050_clk_enable(clk, 1); >>>>> +} >>>>> + >>>>> +static struct clk_ops imxrt1050_clk_ops = { >>>>> + .set_rate = imxrt1050_clk_set_rate, >>>>> + .get_rate = imxrt1050_clk_get_rate, >>>>> + .enable = imxrt1050_clk_enable, >>>>> + .disable = imxrt1050_clk_disable, >>>>> +}; >>>>> + >>>>> +static const char * const pll_ref_sels[] = {"osc", "dummy", }; >>>>> +static const char * const pll1_bypass_sels[] = {"pll1_arm", >>>>> "pll1_arm_ref_sel", }; +static const char * const >>>>> pll2_bypass_sels[] = {"pll2_sys", "pll2_sys_ref_sel", }; +static >>>>> const char * const pll3_bypass_sels[] = {"pll3_usb_otg", >>>>> "pll3_usb_otg_ref_sel", }; +static const char * const >>>>> pll5_bypass_sels[] = {"pll5_video", "pll5_video_ref_sel", }; + >>>>> +static const char *const pre_periph_sels[] = { "pll2_sys", >>>>> "pll2_pfd2_396m", "pll2_pfd0_352m", "arm_podf", }; +static const >>>>> char *const periph_sels[] = { "pre_periph_sel", "todo", }; >>>>> +static const char *const usdhc_sels[] = { "pll2_pfd2_396m", >>>>> "pll2_pfd0_352m", }; +static const char *const lpuart_sels[] = { >>>>> "pll3_80m", "osc", }; +static const char *const semc_alt_sels[] = >>>>> { "pll2_pfd2_396m", "pll3_pfd1_664_62m", }; +static const char >>>>> *const semc_sels[] = { "periph_sel", "semc_alt_sel", }; +static >>>>> const char *const lcdif_sels[] = { "pll2_sys", >>>>> "pll3_pfd3_454_74m", "pll5_video:", "pll2_pfd0_352m", >>>>> "pll2_pfd1_594m", "pll3_pfd1_664_62m"}; + +static int >>>>> imxrt1050_clk_probe(struct udevice *dev) +{ >>>>> + void *base; >>>>> + >>>>> + /* Anatop clocks */ >>>>> + base = (void *)ANATOP_BASE_ADDR; >>>>> + >>>>> + clk_dm(IMXRT1050_CLK_PLL1_REF_SEL, >>>>> + imx_clk_mux("pll1_arm_ref_sel", base + 0x0, 14, 2, >>>>> + pll_ref_sels, >>>>> ARRAY_SIZE(pll_ref_sels))); >>>>> + clk_dm(IMXRT1050_CLK_PLL2_REF_SEL, >>>>> + imx_clk_mux("pll2_sys_ref_sel", base + 0x30, 14, >>>>> 2, >>>>> + pll_ref_sels, >>>>> ARRAY_SIZE(pll_ref_sels))); >>>>> + clk_dm(IMXRT1050_CLK_PLL3_REF_SEL, >>>>> + imx_clk_mux("pll3_usb_otg_ref_sel", base + 0x10, >>>>> 14, 2, >>>>> + pll_ref_sels, >>>>> ARRAY_SIZE(pll_ref_sels))); >>>>> + clk_dm(IMXRT1050_CLK_PLL5_REF_SEL, >>>>> + imx_clk_mux("pll5_video_ref_sel", base + 0xa0, >>>>> 14, 2, >>>>> + pll_ref_sels, >>>>> ARRAY_SIZE(pll_ref_sels))); + >>>>> + clk_dm(IMXRT1050_CLK_PLL1_ARM, >>>>> + imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_arm", >>>>> "pll1_arm_ref_sel", >>>>> + base + 0x0, 0x7f)); >>>>> + clk_dm(IMXRT1050_CLK_PLL2_SYS, >>>>> + imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", >>>>> "pll2_sys_ref_sel", >>>>> + base + 0x30, 0x1)); >>>>> + clk_dm(IMXRT1050_CLK_PLL3_USB_OTG, >>>>> + imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", >>>>> + "pll3_usb_otg_ref_sel", >>>>> + base + 0x10, 0x1)); >>>>> + clk_dm(IMXRT1050_CLK_PLL5_VIDEO, >>>>> + imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", >>>>> "pll5_video_ref_sel", >>>>> + base + 0xa0, 0x7f)); >>>>> + >>>>> + /* PLL bypass out */ >>>>> + clk_dm(IMXRT1050_CLK_PLL1_BYPASS, >>>>> + imx_clk_mux_flags("pll1_bypass", base + 0x0, 16, >>>>> 1, >>>>> + pll1_bypass_sels, >>>>> + ARRAY_SIZE(pll1_bypass_sels), >>>>> + CLK_SET_RATE_PARENT)); >>>>> + clk_dm(IMXRT1050_CLK_PLL2_BYPASS, >>>>> + imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, >>>>> 1, >>>>> + pll2_bypass_sels, >>>>> + ARRAY_SIZE(pll2_bypass_sels), >>>>> + CLK_SET_RATE_PARENT)); >>>>> + clk_dm(IMXRT1050_CLK_PLL3_BYPASS, >>>>> + imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, >>>>> 1, >>>>> + pll3_bypass_sels, >>>>> + ARRAY_SIZE(pll3_bypass_sels), >>>>> + CLK_SET_RATE_PARENT)); >>>>> + clk_dm(IMXRT1050_CLK_PLL5_BYPASS, >>>>> + imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, >>>>> 1, >>>>> + pll5_bypass_sels, >>>>> + ARRAY_SIZE(pll5_bypass_sels), >>>>> + CLK_SET_RATE_PARENT)); >>>>> + >>>>> + clk_dm(IMXRT1050_CLK_VIDEO_POST_DIV_SEL, >>>>> + imx_clk_divider("video_post_div_sel", >>>>> "pll5_video", >>>>> + base + 0xa0, 19, 2)); >>>>> + clk_dm(IMXRT1050_CLK_VIDEO_DIV, >>>>> + imx_clk_divider("video_div", "video_post_div_sel", >>>>> + base + 0x170, 30, 2)); >>>>> + >>>>> + clk_dm(IMXRT1050_CLK_PLL3_80M, >>>>> + imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", >>>>> 1, 6)); + >>>>> + clk_dm(IMXRT1050_CLK_PLL2_PFD0_352M, >>>>> + imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + >>>>> 0x100, 0)); >>>>> + clk_dm(IMXRT1050_CLK_PLL2_PFD1_594M, >>>>> + imx_clk_pfd("pll2_pfd1_594m", "pll2_sys", base + >>>>> 0x100, 1)); >>>>> + clk_dm(IMXRT1050_CLK_PLL2_PFD2_396M, >>>>> + imx_clk_pfd("pll2_pfd2_396m", "pll2_sys", base + >>>>> 0x100, 2)); >>>>> + clk_dm(IMXRT1050_CLK_PLL3_PFD1_664_62M, >>>>> + imx_clk_pfd("pll3_pfd1_664_62m", "pll3_usb_otg", >>>>> base >>>>> + 0xf0, >>>>> + 1)); >>>>> + clk_dm(IMXRT1050_CLK_PLL3_PFD3_454_74M, >>>>> + imx_clk_pfd("pll3_pfd3_454_74m", "pll3_usb_otg", >>>>> base >>>>> + 0xf0, >>>>> + 3)); >>>>> + >>>>> + /* CCM clocks */ >>>>> + base = dev_read_addr_ptr(dev); >>>>> + if (base == (void *)FDT_ADDR_T_NONE) >>>>> + return -EINVAL; >>>>> + >>>>> + clk_dm(IMXRT1050_CLK_ARM_PODF, >>>>> + imx_clk_divider("arm_podf", "pll1_arm", >>>>> + base + 0x10, 0, 3)); >>>>> + >>>>> + clk_dm(IMXRT1050_CLK_PRE_PERIPH_SEL, >>>>> + imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, >>>>> + pre_periph_sels, >>>>> ARRAY_SIZE(pre_periph_sels))); >>>>> + clk_dm(IMXRT1050_CLK_PERIPH_SEL, >>>>> + imx_clk_mux("periph_sel", base + 0x14, 25, 1, >>>>> + periph_sels, >>>>> ARRAY_SIZE(periph_sels))); >>>>> + clk_dm(IMXRT1050_CLK_USDHC1_SEL, >>>>> + imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, >>>>> + usdhc_sels, ARRAY_SIZE(usdhc_sels))); >>>>> + clk_dm(IMXRT1050_CLK_USDHC2_SEL, >>>>> + imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, >>>>> + usdhc_sels, ARRAY_SIZE(usdhc_sels))); >>>>> + clk_dm(IMXRT1050_CLK_LPUART_SEL, >>>>> + imx_clk_mux("lpuart_sel", base + 0x24, 6, 1, >>>>> + lpuart_sels, >>>>> ARRAY_SIZE(lpuart_sels))); >>>>> + clk_dm(IMXRT1050_CLK_SEMC_ALT_SEL, >>>>> + imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1, >>>>> + semc_alt_sels, >>>>> ARRAY_SIZE(semc_alt_sels))); >>>>> + clk_dm(IMXRT1050_CLK_SEMC_SEL, >>>>> + imx_clk_mux("semc_sel", base + 0x14, 6, 1, >>>>> + semc_sels, ARRAY_SIZE(semc_sels))); >>>>> + clk_dm(IMXRT1050_CLK_LCDIF_SEL, >>>>> + imx_clk_mux("lcdif_sel", base + 0x38, 15, 3, >>>>> + lcdif_sels, ARRAY_SIZE(lcdif_sels))); >>>>> + >>>>> + clk_dm(IMXRT1050_CLK_AHB_PODF, >>>>> + imx_clk_divider("ahb_podf", "periph_sel", >>>>> + base + 0x14, 10, 3)); >>>>> + clk_dm(IMXRT1050_CLK_USDHC1_PODF, >>>>> + imx_clk_divider("usdhc1_podf", "usdhc1_sel", >>>>> + base + 0x24, 11, 3)); >>>>> + clk_dm(IMXRT1050_CLK_USDHC2_PODF, >>>>> + imx_clk_divider("usdhc2_podf", "usdhc2_sel", >>>>> + base + 0x24, 16, 3)); >>>>> + clk_dm(IMXRT1050_CLK_LPUART_PODF, >>>>> + imx_clk_divider("lpuart_podf", "lpuart_sel", >>>>> + base + 0x24, 0, 6)); >>>>> + clk_dm(IMXRT1050_CLK_SEMC_PODF, >>>>> + imx_clk_divider("semc_podf", "semc_sel", >>>>> + base + 0x14, 16, 3)); >>>>> + clk_dm(IMXRT1050_CLK_LCDIF_PRED, >>>>> + imx_clk_divider("lcdif_pred", "lcdif_sel", >>>>> + base + 0x38, 12, 3)); >>>>> + clk_dm(IMXRT1050_CLK_LCDIF_PODF, >>>>> + imx_clk_divider("lcdif_podf", "lcdif_pred", >>>>> + base + 0x18, 23, 3)); >>>>> + >>>>> + clk_dm(IMXRT1050_CLK_USDHC1, >>>>> + imx_clk_gate2("usdhc1", "usdhc1_podf", base + >>>>> 0x80, 2)); >>>>> + clk_dm(IMXRT1050_CLK_USDHC2, >>>>> + imx_clk_gate2("usdhc2", "usdhc2_podf", base + >>>>> 0x80, 4)); >>>>> + clk_dm(IMXRT1050_CLK_LPUART1, >>>>> + imx_clk_gate2("lpuart1", "lpuart_podf", base + >>>>> 0x7c, 24)); >>>>> + clk_dm(IMXRT1050_CLK_SEMC, >>>>> + imx_clk_gate2("semc", "semc_podf", base + 0x74, >>>>> 4)); >>>>> + clk_dm(IMXRT1050_CLK_LCDIF, >>>>> + imx_clk_gate2("lcdif", "lcdif_podf", base + 0x70, >>>>> 28)); + >>>>> +#ifdef CONFIG_SPL_BUILD >>>>> + struct clk *clk, *clk1; >>>>> + >>>>> + /* bypass pll1 before setting its rate */ >>>>> + clk_get_by_id(IMXRT1050_CLK_PLL1_REF_SEL, &clk); >>>>> + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); >>>>> + clk_set_parent(clk1, clk); >>>>> + >>>>> + clk_get_by_id(IMXRT1050_CLK_PLL1_ARM, &clk); >>>>> + clk_enable(clk); >>>>> + clk_set_rate(clk, 1056000000UL); >>>>> + >>>>> + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); >>>>> + clk_set_parent(clk1, clk); >>>>> + >>>>> + clk_get_by_id(IMXRT1050_CLK_SEMC_SEL, &clk1); >>>>> + clk_get_by_id(IMXRT1050_CLK_SEMC_ALT_SEL, &clk); >>>>> + clk_set_parent(clk1, clk); >>>>> + >>>>> + clk_get_by_id(IMXRT1050_CLK_PLL2_SYS, &clk); >>>>> + clk_enable(clk); >>>>> + clk_set_rate(clk, 528000000UL); >>>>> + >>>>> + clk_get_by_id(IMXRT1050_CLK_PLL2_BYPASS, &clk1); >>>>> + clk_set_parent(clk1, clk); >>>>> + >>>>> + /* Configure PLL3_USB_OTG to 480MHz */ >>>>> + clk_get_by_id(IMXRT1050_CLK_PLL3_USB_OTG, &clk); >>>>> + clk_enable(clk); >>>>> + clk_set_rate(clk, 480000000UL); >>>>> + >>>>> + clk_get_by_id(IMXRT1050_CLK_PLL3_BYPASS, &clk1); >>>>> + clk_set_parent(clk1, clk); >>>>> + >>>>> +#endif >>>>> + >>>>> + return 0; >>>>> +} >>>>> + >>>>> +static const struct udevice_id imxrt1050_clk_ids[] = { >>>>> + { .compatible = "fsl,imxrt1050-ccm" }, >>>>> + { }, >>>>> +}; >>>>> + >>>>> +U_BOOT_DRIVER(imxrt1050_clk) = { >>>>> + .name = "clk_imxrt1050", >>>>> + .id = UCLASS_CLK, >>>>> + .of_match = imxrt1050_clk_ids, >>>>> + .ops = &imxrt1050_clk_ops, >>>>> + .probe = imxrt1050_clk_probe, >>>>> + .flags = DM_FLAG_PRE_RELOC, >>>>> +}; >>>>> diff --git a/include/dt-bindings/clock/imxrt1050-clock.h >>>>> b/include/dt-bindings/clock/imxrt1050-clock.h new file mode 100644 >>>>> index 0000000000..9f7f9be59f >>>>> --- /dev/null >>>>> +++ b/include/dt-bindings/clock/imxrt1050-clock.h >>>>> @@ -0,0 +1,65 @@ >>>>> +/* SPDX-License-Identifier: GPL-2.0+ */ >>>>> +/* >>>>> + * Copyright(C) 2019 >>>>> + * Author(s): Giulio Benetti >>>>> <giulio.benetti@benettiengineering.com> >>>>> + */ >>>>> + >>>>> +#ifndef __DT_BINDINGS_CLOCK_IMXRT1050_H >>>>> +#define __DT_BINDINGS_CLOCK_IMXRT1050_H >>>>> + >>>>> +#define IMXRT1050_CLK_DUMMY 0 >>>>> +#define IMXRT1050_CLK_CKIL 1 >>>>> +#define IMXRT1050_CLK_CKIH 2 >>>>> +#define IMXRT1050_CLK_OSC 3 >>>>> +#define IMXRT1050_CLK_PLL2_PFD0_352M 4 >>>>> +#define IMXRT1050_CLK_PLL2_PFD1_594M 5 >>>>> +#define IMXRT1050_CLK_PLL2_PFD2_396M 6 >>>>> +#define IMXRT1050_CLK_PLL3_PFD0_720M 7 >>>>> +#define IMXRT1050_CLK_PLL3_PFD1_664_62M 8 >>>>> +#define IMXRT1050_CLK_PLL3_PFD2_508_24M 9 >>>>> +#define IMXRT1050_CLK_PLL3_PFD3_454_74M 10 >>>>> +#define IMXRT1050_CLK_PLL2_198M 11 >>>>> +#define IMXRT1050_CLK_PLL3_120M 12 >>>>> +#define IMXRT1050_CLK_PLL3_80M 13 >>>>> +#define IMXRT1050_CLK_PLL3_60M 14 >>>>> +#define IMXRT1050_CLK_PLL1_BYPASS 15 >>>>> +#define IMXRT1050_CLK_PLL2_BYPASS 16 >>>>> +#define IMXRT1050_CLK_PLL3_BYPASS 17 >>>>> +#define IMXRT1050_CLK_PLL5_BYPASS 19 >>>>> +#define IMXRT1050_CLK_PLL1_REF_SEL 30 >>>>> +#define IMXRT1050_CLK_PLL2_REF_SEL 31 >>>>> +#define IMXRT1050_CLK_PLL3_REF_SEL 32 >>>>> +#define IMXRT1050_CLK_PLL5_REF_SEL 34 >>>>> +#define IMXRT1050_CLK_PRE_PERIPH_SEL 44 >>>>> +#define IMXRT1050_CLK_PERIPH_SEL 45 >>>>> +#define IMXRT1050_CLK_SEMC_ALT_SEL 46 >>>>> +#define IMXRT1050_CLK_SEMC_SEL 47 >>>>> +#define IMXRT1050_CLK_USDHC1_SEL 48 >>>>> +#define IMXRT1050_CLK_USDHC2_SEL 49 >>>>> +#define IMXRT1050_CLK_LPUART_SEL 50 >>>>> +#define IMXRT1050_CLK_LCDIF_SEL 51 >>>>> +#define IMXRT1050_CLK_VIDEO_POST_DIV_SEL 52 >>>>> +#define IMXRT1050_CLK_VIDEO_DIV 53 >>>>> +#define IMXRT1050_CLK_ARM_PODF 90 >>>>> +#define IMXRT1050_CLK_LPUART_PODF 91 >>>>> +#define IMXRT1050_CLK_USDHC1_PODF 92 >>>>> +#define IMXRT1050_CLK_USDHC2_PODF 93 >>>>> +#define IMXRT1050_CLK_SEMC_PODF 94 >>>>> +#define IMXRT1050_CLK_AHB_PODF 95 >>>>> +#define IMXRT1050_CLK_LCDIF_PRED 96 >>>>> +#define IMXRT1050_CLK_LCDIF_PODF 97 >>>>> +#define IMXRT1050_CLK_USDHC1 163 >>>>> +#define IMXRT1050_CLK_USDHC2 164 >>>>> +#define IMXRT1050_CLK_LPUART1 165 >>>>> +#define IMXRT1050_CLK_SEMC 166 >>>>> +#define IMXRT1050_CLK_LCDIF 167 >>>>> +#define IMXRT1050_CLK_PLL1_ARM 170 >>>>> +#define IMXRT1050_CLK_PLL2_SYS 171 >>>>> +#define IMXRT1050_CLK_PLL3_USB_OTG 172 >>>>> +#define IMXRT1050_CLK_PLL4_AUDIO 173 >>>>> +#define IMXRT1050_CLK_PLL5_VIDEO 174 >>>>> +#define IMXRT1050_CLK_PLL6_ENET 176 >>>>> +#define IMXRT1050_CLK_PLL7_USB_HOST 177 >>>>> +#define IMXRT1050_CLK_END 266 >> >> Here all the clocks have number "holes", since it's probable I'll >> have to add other clocks in the middle, but this breaks *_CLK_END >> count. Would it be better if I compact all the indexes and move them >> when I will add new clocks? > > Please be in sync with the Linux kernel CCF driver for i.MX SoC. Unfortunately there is still no porting to Linux, I should do and upstream it. This is why I ask here. > When I was porting the driver from Linux to U-Boot I've realized that > one would need at least +1KiB of RAM/OCRAM to accommodate the original > driver's clock structures. For that reason I've put those clocks in > U-Boot in linked-list, which is less memory hungry (and with the > assumption that we just set clocks once during boot it seems to be good > enough). Yes, that was a good idea, I've seen Linux clock pointer array where those ids are useful for. For the moment I renumber this file filling those holes until I will upstream it to Linux, then later I will sync it. Those ids in u-boot must only be different from each other, but they can have the number they want.
diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index 0ba8bc9f63..d5738b5211 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -52,3 +52,19 @@ config CLK_IMX8MN select CLK_CCF help This enables support clock driver for i.MX8MN platforms. + +config SPL_CLK_IMXRT1050 + bool "SPL clock support for i.MXRT1050" + depends on ARCH_IMXRT && SPL + select SPL_CLK + select SPL_CLK_CCF + help + This enables SPL DM/DTS support for clock driver in i.MXRT1050 + +config CLK_IMXRT1050 + bool "Clock support for i.MXRT1050" + depends on ARCH_IMXRT + select CLK + select CLK_CCF + help + This enables support clock driver for i.MXRT1050 platforms. diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index 222c5a4e08..166cb7bb44 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -14,3 +14,5 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MM) += clk-imx8mm.o clk-pll14xx.o \ clk-composite-8m.o obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \ clk-composite-8m.o + +obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o diff --git a/drivers/clk/imx/clk-imxrt1050.c b/drivers/clk/imx/clk-imxrt1050.c new file mode 100644 index 0000000000..44ca52c013 --- /dev/null +++ b/drivers/clk/imx/clk-imxrt1050.c @@ -0,0 +1,292 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright(C) 2019 + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com> + */ + +#include <common.h> +#include <clk.h> +#include <clk-uclass.h> +#include <dm.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> +#include <dt-bindings/clock/imxrt1050-clock.h> + +#include "clk.h" + +static ulong imxrt1050_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 imxrt1050_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 __imxrt1050_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 imxrt1050_clk_disable(struct clk *clk) +{ + return __imxrt1050_clk_enable(clk, 0); +} + +static int imxrt1050_clk_enable(struct clk *clk) +{ + return __imxrt1050_clk_enable(clk, 1); +} + +static struct clk_ops imxrt1050_clk_ops = { + .set_rate = imxrt1050_clk_set_rate, + .get_rate = imxrt1050_clk_get_rate, + .enable = imxrt1050_clk_enable, + .disable = imxrt1050_clk_disable, +}; + +static const char * const pll_ref_sels[] = {"osc", "dummy", }; +static const char * const pll1_bypass_sels[] = {"pll1_arm", "pll1_arm_ref_sel", }; +static const char * const pll2_bypass_sels[] = {"pll2_sys", "pll2_sys_ref_sel", }; +static const char * const pll3_bypass_sels[] = {"pll3_usb_otg", "pll3_usb_otg_ref_sel", }; +static const char * const pll5_bypass_sels[] = {"pll5_video", "pll5_video_ref_sel", }; + +static const char *const pre_periph_sels[] = { "pll2_sys", "pll2_pfd2_396m", "pll2_pfd0_352m", "arm_podf", }; +static const char *const periph_sels[] = { "pre_periph_sel", "todo", }; +static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *const lpuart_sels[] = { "pll3_80m", "osc", }; +static const char *const semc_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_664_62m", }; +static const char *const semc_sels[] = { "periph_sel", "semc_alt_sel", }; +static const char *const lcdif_sels[] = { "pll2_sys", "pll3_pfd3_454_74m", "pll5_video:", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_664_62m"}; + +static int imxrt1050_clk_probe(struct udevice *dev) +{ + void *base; + + /* Anatop clocks */ + base = (void *)ANATOP_BASE_ADDR; + + clk_dm(IMXRT1050_CLK_PLL1_REF_SEL, + imx_clk_mux("pll1_arm_ref_sel", base + 0x0, 14, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMXRT1050_CLK_PLL2_REF_SEL, + imx_clk_mux("pll2_sys_ref_sel", base + 0x30, 14, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMXRT1050_CLK_PLL3_REF_SEL, + imx_clk_mux("pll3_usb_otg_ref_sel", base + 0x10, 14, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + clk_dm(IMXRT1050_CLK_PLL5_REF_SEL, + imx_clk_mux("pll5_video_ref_sel", base + 0xa0, 14, 2, + pll_ref_sels, ARRAY_SIZE(pll_ref_sels))); + + clk_dm(IMXRT1050_CLK_PLL1_ARM, + imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_arm", "pll1_arm_ref_sel", + base + 0x0, 0x7f)); + clk_dm(IMXRT1050_CLK_PLL2_SYS, + imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", "pll2_sys_ref_sel", + base + 0x30, 0x1)); + clk_dm(IMXRT1050_CLK_PLL3_USB_OTG, + imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", + "pll3_usb_otg_ref_sel", + base + 0x10, 0x1)); + clk_dm(IMXRT1050_CLK_PLL5_VIDEO, + imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "pll5_video_ref_sel", + base + 0xa0, 0x7f)); + + /* PLL bypass out */ + clk_dm(IMXRT1050_CLK_PLL1_BYPASS, + imx_clk_mux_flags("pll1_bypass", base + 0x0, 16, 1, + pll1_bypass_sels, + ARRAY_SIZE(pll1_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMXRT1050_CLK_PLL2_BYPASS, + imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1, + pll2_bypass_sels, + ARRAY_SIZE(pll2_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMXRT1050_CLK_PLL3_BYPASS, + imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1, + pll3_bypass_sels, + ARRAY_SIZE(pll3_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMXRT1050_CLK_PLL5_BYPASS, + imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1, + pll5_bypass_sels, + ARRAY_SIZE(pll5_bypass_sels), + CLK_SET_RATE_PARENT)); + + clk_dm(IMXRT1050_CLK_VIDEO_POST_DIV_SEL, + imx_clk_divider("video_post_div_sel", "pll5_video", + base + 0xa0, 19, 2)); + clk_dm(IMXRT1050_CLK_VIDEO_DIV, + imx_clk_divider("video_div", "video_post_div_sel", + base + 0x170, 30, 2)); + + clk_dm(IMXRT1050_CLK_PLL3_80M, + imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6)); + + clk_dm(IMXRT1050_CLK_PLL2_PFD0_352M, + imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + 0x100, 0)); + clk_dm(IMXRT1050_CLK_PLL2_PFD1_594M, + imx_clk_pfd("pll2_pfd1_594m", "pll2_sys", base + 0x100, 1)); + clk_dm(IMXRT1050_CLK_PLL2_PFD2_396M, + imx_clk_pfd("pll2_pfd2_396m", "pll2_sys", base + 0x100, 2)); + clk_dm(IMXRT1050_CLK_PLL3_PFD1_664_62M, + imx_clk_pfd("pll3_pfd1_664_62m", "pll3_usb_otg", base + 0xf0, + 1)); + clk_dm(IMXRT1050_CLK_PLL3_PFD3_454_74M, + imx_clk_pfd("pll3_pfd3_454_74m", "pll3_usb_otg", base + 0xf0, + 3)); + + /* CCM clocks */ + base = dev_read_addr_ptr(dev); + if (base == (void *)FDT_ADDR_T_NONE) + return -EINVAL; + + clk_dm(IMXRT1050_CLK_ARM_PODF, + imx_clk_divider("arm_podf", "pll1_arm", + base + 0x10, 0, 3)); + + clk_dm(IMXRT1050_CLK_PRE_PERIPH_SEL, + imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2, + pre_periph_sels, ARRAY_SIZE(pre_periph_sels))); + clk_dm(IMXRT1050_CLK_PERIPH_SEL, + imx_clk_mux("periph_sel", base + 0x14, 25, 1, + periph_sels, ARRAY_SIZE(periph_sels))); + clk_dm(IMXRT1050_CLK_USDHC1_SEL, + imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1, + usdhc_sels, ARRAY_SIZE(usdhc_sels))); + clk_dm(IMXRT1050_CLK_USDHC2_SEL, + imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1, + usdhc_sels, ARRAY_SIZE(usdhc_sels))); + clk_dm(IMXRT1050_CLK_LPUART_SEL, + imx_clk_mux("lpuart_sel", base + 0x24, 6, 1, + lpuart_sels, ARRAY_SIZE(lpuart_sels))); + clk_dm(IMXRT1050_CLK_SEMC_ALT_SEL, + imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1, + semc_alt_sels, ARRAY_SIZE(semc_alt_sels))); + clk_dm(IMXRT1050_CLK_SEMC_SEL, + imx_clk_mux("semc_sel", base + 0x14, 6, 1, + semc_sels, ARRAY_SIZE(semc_sels))); + clk_dm(IMXRT1050_CLK_LCDIF_SEL, + imx_clk_mux("lcdif_sel", base + 0x38, 15, 3, + lcdif_sels, ARRAY_SIZE(lcdif_sels))); + + clk_dm(IMXRT1050_CLK_AHB_PODF, + imx_clk_divider("ahb_podf", "periph_sel", + base + 0x14, 10, 3)); + clk_dm(IMXRT1050_CLK_USDHC1_PODF, + imx_clk_divider("usdhc1_podf", "usdhc1_sel", + base + 0x24, 11, 3)); + clk_dm(IMXRT1050_CLK_USDHC2_PODF, + imx_clk_divider("usdhc2_podf", "usdhc2_sel", + base + 0x24, 16, 3)); + clk_dm(IMXRT1050_CLK_LPUART_PODF, + imx_clk_divider("lpuart_podf", "lpuart_sel", + base + 0x24, 0, 6)); + clk_dm(IMXRT1050_CLK_SEMC_PODF, + imx_clk_divider("semc_podf", "semc_sel", + base + 0x14, 16, 3)); + clk_dm(IMXRT1050_CLK_LCDIF_PRED, + imx_clk_divider("lcdif_pred", "lcdif_sel", + base + 0x38, 12, 3)); + clk_dm(IMXRT1050_CLK_LCDIF_PODF, + imx_clk_divider("lcdif_podf", "lcdif_pred", + base + 0x18, 23, 3)); + + clk_dm(IMXRT1050_CLK_USDHC1, + imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2)); + clk_dm(IMXRT1050_CLK_USDHC2, + imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4)); + clk_dm(IMXRT1050_CLK_LPUART1, + imx_clk_gate2("lpuart1", "lpuart_podf", base + 0x7c, 24)); + clk_dm(IMXRT1050_CLK_SEMC, + imx_clk_gate2("semc", "semc_podf", base + 0x74, 4)); + clk_dm(IMXRT1050_CLK_LCDIF, + imx_clk_gate2("lcdif", "lcdif_podf", base + 0x70, 28)); + +#ifdef CONFIG_SPL_BUILD + struct clk *clk, *clk1; + + /* bypass pll1 before setting its rate */ + clk_get_by_id(IMXRT1050_CLK_PLL1_REF_SEL, &clk); + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); + clk_set_parent(clk1, clk); + + clk_get_by_id(IMXRT1050_CLK_PLL1_ARM, &clk); + clk_enable(clk); + clk_set_rate(clk, 1056000000UL); + + clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1); + clk_set_parent(clk1, clk); + + clk_get_by_id(IMXRT1050_CLK_SEMC_SEL, &clk1); + clk_get_by_id(IMXRT1050_CLK_SEMC_ALT_SEL, &clk); + clk_set_parent(clk1, clk); + + clk_get_by_id(IMXRT1050_CLK_PLL2_SYS, &clk); + clk_enable(clk); + clk_set_rate(clk, 528000000UL); + + clk_get_by_id(IMXRT1050_CLK_PLL2_BYPASS, &clk1); + clk_set_parent(clk1, clk); + + /* Configure PLL3_USB_OTG to 480MHz */ + clk_get_by_id(IMXRT1050_CLK_PLL3_USB_OTG, &clk); + clk_enable(clk); + clk_set_rate(clk, 480000000UL); + + clk_get_by_id(IMXRT1050_CLK_PLL3_BYPASS, &clk1); + clk_set_parent(clk1, clk); + +#endif + + return 0; +} + +static const struct udevice_id imxrt1050_clk_ids[] = { + { .compatible = "fsl,imxrt1050-ccm" }, + { }, +}; + +U_BOOT_DRIVER(imxrt1050_clk) = { + .name = "clk_imxrt1050", + .id = UCLASS_CLK, + .of_match = imxrt1050_clk_ids, + .ops = &imxrt1050_clk_ops, + .probe = imxrt1050_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/include/dt-bindings/clock/imxrt1050-clock.h b/include/dt-bindings/clock/imxrt1050-clock.h new file mode 100644 index 0000000000..9f7f9be59f --- /dev/null +++ b/include/dt-bindings/clock/imxrt1050-clock.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright(C) 2019 + * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com> + */ + +#ifndef __DT_BINDINGS_CLOCK_IMXRT1050_H +#define __DT_BINDINGS_CLOCK_IMXRT1050_H + +#define IMXRT1050_CLK_DUMMY 0 +#define IMXRT1050_CLK_CKIL 1 +#define IMXRT1050_CLK_CKIH 2 +#define IMXRT1050_CLK_OSC 3 +#define IMXRT1050_CLK_PLL2_PFD0_352M 4 +#define IMXRT1050_CLK_PLL2_PFD1_594M 5 +#define IMXRT1050_CLK_PLL2_PFD2_396M 6 +#define IMXRT1050_CLK_PLL3_PFD0_720M 7 +#define IMXRT1050_CLK_PLL3_PFD1_664_62M 8 +#define IMXRT1050_CLK_PLL3_PFD2_508_24M 9 +#define IMXRT1050_CLK_PLL3_PFD3_454_74M 10 +#define IMXRT1050_CLK_PLL2_198M 11 +#define IMXRT1050_CLK_PLL3_120M 12 +#define IMXRT1050_CLK_PLL3_80M 13 +#define IMXRT1050_CLK_PLL3_60M 14 +#define IMXRT1050_CLK_PLL1_BYPASS 15 +#define IMXRT1050_CLK_PLL2_BYPASS 16 +#define IMXRT1050_CLK_PLL3_BYPASS 17 +#define IMXRT1050_CLK_PLL5_BYPASS 19 +#define IMXRT1050_CLK_PLL1_REF_SEL 30 +#define IMXRT1050_CLK_PLL2_REF_SEL 31 +#define IMXRT1050_CLK_PLL3_REF_SEL 32 +#define IMXRT1050_CLK_PLL5_REF_SEL 34 +#define IMXRT1050_CLK_PRE_PERIPH_SEL 44 +#define IMXRT1050_CLK_PERIPH_SEL 45 +#define IMXRT1050_CLK_SEMC_ALT_SEL 46 +#define IMXRT1050_CLK_SEMC_SEL 47 +#define IMXRT1050_CLK_USDHC1_SEL 48 +#define IMXRT1050_CLK_USDHC2_SEL 49 +#define IMXRT1050_CLK_LPUART_SEL 50 +#define IMXRT1050_CLK_LCDIF_SEL 51 +#define IMXRT1050_CLK_VIDEO_POST_DIV_SEL 52 +#define IMXRT1050_CLK_VIDEO_DIV 53 +#define IMXRT1050_CLK_ARM_PODF 90 +#define IMXRT1050_CLK_LPUART_PODF 91 +#define IMXRT1050_CLK_USDHC1_PODF 92 +#define IMXRT1050_CLK_USDHC2_PODF 93 +#define IMXRT1050_CLK_SEMC_PODF 94 +#define IMXRT1050_CLK_AHB_PODF 95 +#define IMXRT1050_CLK_LCDIF_PRED 96 +#define IMXRT1050_CLK_LCDIF_PODF 97 +#define IMXRT1050_CLK_USDHC1 163 +#define IMXRT1050_CLK_USDHC2 164 +#define IMXRT1050_CLK_LPUART1 165 +#define IMXRT1050_CLK_SEMC 166 +#define IMXRT1050_CLK_LCDIF 167 +#define IMXRT1050_CLK_PLL1_ARM 170 +#define IMXRT1050_CLK_PLL2_SYS 171 +#define IMXRT1050_CLK_PLL3_USB_OTG 172 +#define IMXRT1050_CLK_PLL4_AUDIO 173 +#define IMXRT1050_CLK_PLL5_VIDEO 174 +#define IMXRT1050_CLK_PLL6_ENET 176 +#define IMXRT1050_CLK_PLL7_USB_HOST 177 +#define IMXRT1050_CLK_END 266 + +#endif /* __DT_BINDINGS_CLOCK_IMXRT1050_H */
Add i.MXRT1050 clk driver support. Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com> --- drivers/clk/imx/Kconfig | 16 ++ drivers/clk/imx/Makefile | 2 + drivers/clk/imx/clk-imxrt1050.c | 292 ++++++++++++++++++++ include/dt-bindings/clock/imxrt1050-clock.h | 65 +++++ 4 files changed, 375 insertions(+) create mode 100644 drivers/clk/imx/clk-imxrt1050.c create mode 100644 include/dt-bindings/clock/imxrt1050-clock.h