[U-Boot] [PATCH V2 28/51] clk: imx: add i.MX8MM clk driver
Schrempf Frieder
frieder.schrempf at kontron.de
Wed Jul 10 14:22:46 UTC 2019
Hi Peng,
On 08.07.19 03:39, Peng Fan wrote:
> Add i.MX8MM clk driver support.
>
> Signed-off-by: Peng Fan <peng.fan at nxp.com>
> ---
> arch/arm/mach-imx/imx8m/clock_imx8mm.c | 203 +++++++++++++++++----------------
> drivers/clk/imx/Makefile | 1 +
> drivers/clk/imx/clk-imx8mm.c | 106 +++++++++++++++++
> 3 files changed, 211 insertions(+), 99 deletions(-)
> create mode 100644 drivers/clk/imx/clk-imx8mm.c
>
> diff --git a/arch/arm/mach-imx/imx8m/clock_imx8mm.c b/arch/arm/mach-imx/imx8m/clock_imx8mm.c
> index 07399023d5..541561f276 100644
> --- a/arch/arm/mach-imx/imx8m/clock_imx8mm.c
> +++ b/arch/arm/mach-imx/imx8m/clock_imx8mm.c
> @@ -119,6 +119,110 @@ void init_wdog_clk(void)
> clock_enable(CCGR_WDOG3, 1);
> }
>
> +static int intpll_configure(enum pll_clocks pll, ulong freq)
> +{
> + void __iomem *pll_gnrl_ctl, __iomem *pll_div_ctl;
> + u32 pll_div_ctl_val, pll_clke_masks;
> +
> + switch (pll) {
> + case ANATOP_SYSTEM_PLL1:
> + pll_gnrl_ctl = &ana_pll->sys_pll1_gnrl_ctl;
> + pll_div_ctl = &ana_pll->sys_pll1_div_ctl;
> + pll_clke_masks = INTPLL_DIV20_CLKE_MASK |
> + INTPLL_DIV10_CLKE_MASK | INTPLL_DIV8_CLKE_MASK |
> + INTPLL_DIV6_CLKE_MASK | INTPLL_DIV5_CLKE_MASK |
> + INTPLL_DIV4_CLKE_MASK | INTPLL_DIV3_CLKE_MASK |
> + INTPLL_DIV2_CLKE_MASK | INTPLL_CLKE_MASK;
> + break;
> + case ANATOP_SYSTEM_PLL2:
> + pll_gnrl_ctl = &ana_pll->sys_pll2_gnrl_ctl;
> + pll_div_ctl = &ana_pll->sys_pll2_div_ctl;
> + pll_clke_masks = INTPLL_DIV20_CLKE_MASK |
> + INTPLL_DIV10_CLKE_MASK | INTPLL_DIV8_CLKE_MASK |
> + INTPLL_DIV6_CLKE_MASK | INTPLL_DIV5_CLKE_MASK |
> + INTPLL_DIV4_CLKE_MASK | INTPLL_DIV3_CLKE_MASK |
> + INTPLL_DIV2_CLKE_MASK | INTPLL_CLKE_MASK;
> + break;
> + case ANATOP_SYSTEM_PLL3:
> + pll_gnrl_ctl = &ana_pll->sys_pll3_gnrl_ctl;
> + pll_div_ctl = &ana_pll->sys_pll3_div_ctl;
> + pll_clke_masks = INTPLL_CLKE_MASK;
> + break;
> + case ANATOP_ARM_PLL:
> + pll_gnrl_ctl = &ana_pll->arm_pll_gnrl_ctl;
> + pll_div_ctl = &ana_pll->arm_pll_div_ctl;
> + pll_clke_masks = INTPLL_CLKE_MASK;
> + break;
> + case ANATOP_GPU_PLL:
> + pll_gnrl_ctl = &ana_pll->gpu_pll_gnrl_ctl;
> + pll_div_ctl = &ana_pll->gpu_pll_div_ctl;
> + pll_clke_masks = INTPLL_CLKE_MASK;
> + break;
> + case ANATOP_VPU_PLL:
> + pll_gnrl_ctl = &ana_pll->vpu_pll_gnrl_ctl;
> + pll_div_ctl = &ana_pll->vpu_pll_div_ctl;
> + pll_clke_masks = INTPLL_CLKE_MASK;
> + break;
> + default:
> + return -EINVAL;
> + };
> +
> + switch (freq) {
> + case MHZ(600):
> + /* 24 * 0x12c / 3 / 2 ^ 2 */
> + pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x12c) |
> + INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(2);
> + break;
> + case MHZ(750):
> + /* 24 * 0xfa / 2 / 2 ^ 2 */
> + pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
> + INTPLL_PRE_DIV_VAL(2) | INTPLL_POST_DIV_VAL(2);
> + break;
> + case MHZ(800):
> + /* 24 * 0x190 / 3 / 2 ^ 2 */
> + pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x190) |
> + INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(2);
> + break;
> + case MHZ(1000):
> + /* 24 * 0xfa / 3 / 2 ^ 1 */
> + pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
> + INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1);
> + break;
> + case MHZ(1200):
> + /* 24 * 0xc8 / 2 / 2 ^ 1 */
> + pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xc8) |
> + INTPLL_PRE_DIV_VAL(2) | INTPLL_POST_DIV_VAL(1);
> + break;
> + case MHZ(2000):
> + /* 24 * 0xfa / 3 / 2 ^ 0 */
> + pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
> + INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(0);
> + break;
> + default:
> + return -EINVAL;
> + };
> + /* Bypass clock and set lock to pll output lock */
> + setbits_le32(pll_gnrl_ctl, INTPLL_BYPASS_MASK |
> + INTPLL_LOCK_SEL_MASK);
> + /* Enable reset */
> + clrbits_le32(pll_gnrl_ctl, INTPLL_RST_MASK);
> + /* Configure */
> + writel(pll_div_ctl_val, pll_div_ctl);
> +
> + __udelay(100);
> +
> + /* Disable reset */
> + setbits_le32(pll_gnrl_ctl, INTPLL_RST_MASK);
> + /* Wait Lock */
> + while (!(readl(pll_gnrl_ctl) & INTPLL_LOCK_MASK))
> + ;
> + /* Clear bypass */
> + clrbits_le32(pll_gnrl_ctl, INTPLL_BYPASS_MASK);
> + setbits_le32(pll_gnrl_ctl, pll_clke_masks);
> +
> + return 0;
> +}
> +
> int clock_init(void)
> {
> u32 val_cfg0;
> @@ -467,105 +571,6 @@ int fracpll_configure(enum pll_clocks pll, u32 freq)
> return 0;
> }
>
> -int intpll_configure(enum pll_clocks pll, ulong freq)
> -{
> - void __iomem *pll_gnrl_ctl, __iomem *pll_div_ctl;
> - u32 pll_div_ctl_val, pll_clke_masks;
> -
> - switch (pll) {
> - case ANATOP_SYSTEM_PLL1:
> - pll_gnrl_ctl = &ana_pll->sys_pll1_gnrl_ctl;
> - pll_div_ctl = &ana_pll->sys_pll1_div_ctl;
> - pll_clke_masks = INTPLL_DIV20_CLKE_MASK |
> - INTPLL_DIV10_CLKE_MASK | INTPLL_DIV8_CLKE_MASK |
> - INTPLL_DIV6_CLKE_MASK | INTPLL_DIV5_CLKE_MASK |
> - INTPLL_DIV4_CLKE_MASK | INTPLL_DIV3_CLKE_MASK |
> - INTPLL_DIV2_CLKE_MASK | INTPLL_CLKE_MASK;
> - break;
> - case ANATOP_SYSTEM_PLL2:
> - pll_gnrl_ctl = &ana_pll->sys_pll2_gnrl_ctl;
> - pll_div_ctl = &ana_pll->sys_pll2_div_ctl;
> - pll_clke_masks = INTPLL_DIV20_CLKE_MASK |
> - INTPLL_DIV10_CLKE_MASK | INTPLL_DIV8_CLKE_MASK |
> - INTPLL_DIV6_CLKE_MASK | INTPLL_DIV5_CLKE_MASK |
> - INTPLL_DIV4_CLKE_MASK | INTPLL_DIV3_CLKE_MASK |
> - INTPLL_DIV2_CLKE_MASK | INTPLL_CLKE_MASK;
> - break;
> - case ANATOP_SYSTEM_PLL3:
> - pll_gnrl_ctl = &ana_pll->sys_pll3_gnrl_ctl;
> - pll_div_ctl = &ana_pll->sys_pll3_div_ctl;
> - pll_clke_masks = INTPLL_CLKE_MASK;
> - break;
> - case ANATOP_ARM_PLL:
> - pll_gnrl_ctl = &ana_pll->arm_pll_gnrl_ctl;
> - pll_div_ctl = &ana_pll->arm_pll_div_ctl;
> - pll_clke_masks = INTPLL_CLKE_MASK;
> - break;
> - case ANATOP_GPU_PLL:
> - pll_gnrl_ctl = &ana_pll->gpu_pll_gnrl_ctl;
> - pll_div_ctl = &ana_pll->gpu_pll_div_ctl;
> - pll_clke_masks = INTPLL_CLKE_MASK;
> - break;
> - case ANATOP_VPU_PLL:
> - pll_gnrl_ctl = &ana_pll->vpu_pll_gnrl_ctl;
> - pll_div_ctl = &ana_pll->vpu_pll_div_ctl;
> - pll_clke_masks = INTPLL_CLKE_MASK;
> - break;
> - default:
> - return -EINVAL;
> - };
> -
> - switch (freq) {
> - case MHZ(750):
> - /* 24 * 0xfa / 2 / 2 ^ 2 */
> - pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
> - INTPLL_PRE_DIV_VAL(2) | INTPLL_POST_DIV_VAL(2);
> - break;
> - case MHZ(800):
> - /* 24 * 0x190 / 3 / 2 ^ 2 */
> - pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0x190) |
> - INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(2);
> - break;
> - case MHZ(1000):
> - /* 24 * 0xfa / 3 / 2 ^ 1 */
> - pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
> - INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(1);
> - break;
> - case MHZ(1200):
> - /* 24 * 0xc8 / 2 / 2 ^ 1 */
> - pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xc8) |
> - INTPLL_PRE_DIV_VAL(2) | INTPLL_POST_DIV_VAL(1);
> - break;
> - case MHZ(2000):
> - /* 24 * 0xfa / 3 / 2 ^ 0 */
> - pll_div_ctl_val = INTPLL_MAIN_DIV_VAL(0xfa) |
> - INTPLL_PRE_DIV_VAL(3) | INTPLL_POST_DIV_VAL(0);
> - break;
> - default:
> - return -EINVAL;
> - };
> - /* Bypass clock and set lock to pll output lock */
> - setbits_le32(pll_gnrl_ctl, INTPLL_BYPASS_MASK |
> - INTPLL_LOCK_SEL_MASK);
> - /* Enable reset */
> - clrbits_le32(pll_gnrl_ctl, INTPLL_RST_MASK);
> - /* Configure */
> - writel(pll_div_ctl_val, pll_div_ctl);
> -
> - __udelay(100);
> -
> - /* Disable reset */
> - setbits_le32(pll_gnrl_ctl, INTPLL_RST_MASK);
> - /* Wait Lock */
> - while (!(readl(pll_gnrl_ctl) & INTPLL_LOCK_MASK))
> - ;
> - /* Clear bypass */
> - clrbits_le32(pll_gnrl_ctl, INTPLL_BYPASS_MASK);
> - setbits_le32(pll_gnrl_ctl, pll_clke_masks);
> -
> - return 0;
> -}
> -
> u32 get_root_src_clk(enum clk_root_src root_src)
> {
> switch (root_src) {
> diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile
> index eb379c188a..b55566f2e9 100644
> --- a/drivers/clk/imx/Makefile
> +++ b/drivers/clk/imx/Makefile
> @@ -8,3 +8,4 @@ ifdef CONFIG_CLK_IMX8
> obj-$(CONFIG_IMX8QXP) += clk-imx8qxp.o
> obj-$(CONFIG_IMX8QM) += clk-imx8qm.o
> endif
> +obj-$(CONFIG_CLK_IMX8MM) += clk-imx8mm.o
> diff --git a/drivers/clk/imx/clk-imx8mm.c b/drivers/clk/imx/clk-imx8mm.c
> new file mode 100644
> index 0000000000..1e0669494f
> --- /dev/null
> +++ b/drivers/clk/imx/clk-imx8mm.c
> @@ -0,0 +1,106 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2019 NXP
> + * Peng Fan <peng.fan at nxp.com>
> + */
> +
> +#include <common.h>
> +#include <clk-uclass.h>
> +#include <dm.h>
> +#include <asm/arch/clock.h>
> +#include <dt-bindings/clock/imx8mm-clock.h>
> +
> +static ulong imx8mm_clk_get_rate(struct clk *clk)
> +{
> + debug("%s(#%lu)\n", __func__, clk->id);
> +
> + switch (clk->id) {
> + case IMX8MM_CLK_USDHC1_ROOT:
> + return get_root_clk(USDHC1_CLK_ROOT);
> + case IMX8MM_CLK_USDHC2_ROOT:
> + return get_root_clk(USDHC2_CLK_ROOT);
> + case IMX8MM_CLK_USDHC3_ROOT:
> + return get_root_clk(USDHC3_CLK_ROOT);
> + case IMX8MM_CLK_I2C1:
I tested I2C on my i.MX8MM board and it doesn't work (it did work with
the CCF-based patches). It seems like IMX8MM_CLK_I2CX should be
IMX8MM_CLK_I2CX_ROOT here and also for all the other occurrences below.
Changing this makes I2C work again.
And by the way: I'm not sure which side to take in the CCF or non-CCF
discussion for i.MX8MM. I can understand both points of view and
whichever decision is made I will support it, but it would be nice if we
could settle for something soon.
Thanks,
Frieder
> + return get_root_clk(I2C1_CLK_ROOT);
> + case IMX8MM_CLK_I2C2:
> + return get_root_clk(I2C2_CLK_ROOT);
> + case IMX8MM_CLK_I2C3:
> + return get_root_clk(I2C3_CLK_ROOT);
> + case IMX8MM_CLK_I2C4:
> + return get_root_clk(I2C4_CLK_ROOT);
> + }
> +
> + return 0;
> +}
> +
> +static int __imx8mm_clk_enable(struct clk *clk, bool enable)
> +{
> + switch (clk->id) {
> + case IMX8MM_CLK_USDHC1_ROOT:
> + return clock_enable(CCGR_USDHC1, enable);
> + case IMX8MM_CLK_USDHC2_ROOT:
> + return clock_enable(CCGR_USDHC2, enable);
> + case IMX8MM_CLK_USDHC3_ROOT:
> + return clock_enable(CCGR_USDHC3, enable);
> + case IMX8MM_CLK_I2C1:
> + return clock_enable(CCGR_I2C1, enable);
> + case IMX8MM_CLK_I2C2:
> + return clock_enable(CCGR_I2C2, enable);
> + case IMX8MM_CLK_I2C3:
> + return clock_enable(CCGR_I2C3, enable);
> + case IMX8MM_CLK_I2C4:
> + return clock_enable(CCGR_I2C4, enable);
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int imx8mm_clk_disable(struct clk *clk)
> +{
> + debug("%s(#%lu)\n", __func__, clk->id);
> +
> + return __imx8mm_clk_enable(clk, false);
> +}
> +
> +static int imx8mm_clk_enable(struct clk *clk)
> +{
> + debug("%s(#%lu)\n", __func__, clk->id);
> +
> + return __imx8mm_clk_enable(clk, true);
> +}
> +
> +static ulong imx8mm_clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> + debug("%s(#%lu)\n", __func__, clk->id);
> +
> + /* TODO: */
> +
> + return imx8mm_clk_get_rate(clk);
> +}
> +
> +static struct clk_ops imx8mm_clk_ops = {
> + .set_rate = imx8mm_clk_set_rate,
> + .get_rate = imx8mm_clk_get_rate,
> + .enable = imx8mm_clk_enable,
> + .disable = imx8mm_clk_disable,
> +};
> +
> +static int imx8mm_clk_probe(struct udevice *dev)
> +{
> + return 0;
> +}
> +
> +static const struct udevice_id imx8mm_clk_ids[] = {
> + { .compatible = "fsl,imx8mm-ccm" },
> + { },
> +};
> +
> +U_BOOT_DRIVER(imx8mm_clk) = {
> + .name = "clk_imx8mm",
> + .id = UCLASS_CLK,
> + .of_match = imx8mm_clk_ids,
> + .ops = &imx8mm_clk_ops,
> + .probe = imx8mm_clk_probe,
> + .flags = DM_FLAG_PRE_RELOC,
> +};
>
More information about the U-Boot
mailing list