diff --git a/cmd/clk.c b/cmd/clk.c index 439736d072..e3c3d2f9bb 100644 --- a/cmd/clk.c +++ b/cmd/clk.c @@ -23,31 +23,32 @@ static void show_clks(struct udevice *dev, int depth, int last_flag) clkp = dev_get_clk_ptr(dev); if (device_get_uclass_id(dev) == UCLASS_CLK && clkp) { + depth++; rate = clk_get_rate(clkp); - printf(" %-12u %8d ", rate, clkp->enable_count); + printf(" %-12u %8d ", rate, clkp->enable_count); - for (i = depth; i >= 0; i--) { - is_last = (last_flag >> i) & 1; - if (i) { - if (is_last) - printf(" "); - else - printf("| "); - } else { - if (is_last) - printf("`-- "); - else - printf("|-- "); + for (i = depth; i >= 0; i--) { + is_last = (last_flag >> i) & 1; + if (i) { + if (is_last) + printf(" "); + else + printf("| "); + } else { + if (is_last) + printf("`-- "); + else + printf("|-- "); + } } - } - printf("%s\n", dev->name); + printf("%s\n", dev->name); } list_for_each_entry(child, &dev->child_head, sibling_node) { is_last = list_is_last(&child->sibling_node, &dev->child_head); - show_clks(child, depth + 1, (last_flag << 1) | is_last); + show_clks(child, depth, (last_flag << 1) | is_last); } } diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c index 819bfca2fc..7e99c5b910 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -145,6 +145,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name, } clk = &composite->clk; + clk->flags = flags; ret = clk_register(clk, UBOOT_DM_CLK_COMPOSITE, name, parent_names[clk_composite_get_parent(clk)]); if (ret) { diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 34658536c4..8f59d7fb72 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -212,6 +212,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, /* register the clock */ clk = &div->clk; + clk->flags = flags; ret = clk_register(clk, UBOOT_DM_CLK_CCF_DIVIDER, name, parent_name); if (ret) { diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c index 0eb24b87fc..8d9823bdab 100644 --- a/drivers/clk/clk-fixed-factor.c +++ b/drivers/clk/clk-fixed-factor.c @@ -49,6 +49,7 @@ struct clk *clk_hw_register_fixed_factor(struct device *dev, fix->mult = mult; fix->div = div; clk = &fix->clk; + clk->flags = flags; ret = clk_register(clk, UBOOT_DM_CLK_IMX_FIXED_FACTOR, name, parent_name); diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c index 98e4b80b32..006d3b6629 100644 --- a/drivers/clk/clk-gate.c +++ b/drivers/clk/clk-gate.c @@ -142,6 +142,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name, #endif clk = &gate->clk; + clk->flags = flags; ret = clk_register(clk, UBOOT_DM_CLK_GATE, name, parent_name); if (ret) { diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 26991a5bc8..7a5ee7a45f 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -22,16 +22,17 @@ */ #include -#include -#include +#include #include #include #include +#include #include +#include +#include #include -#include -#include "clk.h" #include +#include "clk.h" #define UBOOT_DM_CLK_CCF_MUX "ccf_clk_mux" @@ -131,18 +132,50 @@ static int clk_mux_set_parent(struct clk *clk, struct clk *parent) if (mux->flags & CLK_MUX_HIWORD_MASK) { reg = mux->mask << (mux->shift + 16); } else { +#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF) + reg = mux->io_mux_val; +#else reg = readl(mux->reg); +#endif reg &= ~(mux->mask << mux->shift); } val = val << mux->shift; reg |= val; +#if CONFIG_IS_ENABLED(SANDBOX_CLK_CCF) + mux->io_mux_val = reg; +#else writel(reg, mux->reg); +#endif return 0; } +static ulong clk_mux_get_rate(struct clk *clk) +{ + struct clk_mux *mux = to_clk_mux(clk_dev_binded(clk) ? + dev_get_clk_ptr(clk->dev) : clk); + struct udevice *parent; + struct clk *pclk; + int err, index; + + index = clk_mux_get_parent(clk); + if (index >= mux->num_parents) + return -EFAULT; + + err = uclass_get_device_by_name(UCLASS_CLK, mux->parent_names[index], + &parent); + if (err) + return err; + + pclk = dev_get_clk_ptr(parent); + if (!pclk) + return -ENODEV; + + return clk_get_rate(pclk); +} + const struct clk_ops clk_mux_ops = { - .get_rate = clk_generic_get_rate, + .get_rate = clk_mux_get_rate, .set_parent = clk_mux_set_parent, }; @@ -185,12 +218,13 @@ struct clk *clk_hw_register_mux_table(struct device *dev, const char *name, #endif clk = &mux->clk; + clk->flags = flags; /* * Read the current mux setup - so we assign correct parent. * * Changing parent would require changing internals of udevice struct - * for the corresponding clock (to do that define .set_parent() method. + * for the corresponding clock (to do that define .set_parent() method). */ ret = clk_register(clk, UBOOT_DM_CLK_CCF_MUX, name, parent_names[clk_mux_get_parent(clk)]); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0f55ba751c..786f4e887e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -22,13 +22,13 @@ int clk_register(struct clk *clk, const char *drv_name, ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent); if (ret) { - printf("%s: name: %s parent: %s [0x%p]\n", - __func__, name, parent->name, parent); + printf("%s: failed to get %s device (parent of %s)\n", + __func__, parent_name, name); + } else { + debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, + parent->name, parent); } - debug("%s: name: %s parent: %s [0x%p]\n", __func__, name, parent->name, - parent); - drv = lists_driver_lookup_name(drv_name); if (!drv) { printf("%s: %s is not a valid driver name\n", diff --git a/drivers/clk/clk_sandbox_ccf.c b/drivers/clk/clk_sandbox_ccf.c index 0619d04f0e..fedcdd4044 100644 --- a/drivers/clk/clk_sandbox_ccf.c +++ b/drivers/clk/clk_sandbox_ccf.c @@ -130,6 +130,7 @@ struct clk *sandbox_clk_register_gate2(struct device *dev, const char *name, gate->state = 0; clk = &gate->clk; + clk->flags = flags; ret = clk_register(clk, "sandbox_clk_gate2", name, parent_name); if (ret) { @@ -250,6 +251,10 @@ static int sandbox_clk_ccf_probe(struct udevice *dev) clk_dm(SANDBOX_CLK_ECSPI_ROOT, sandbox_clk_divider("ecspi_root", "pll3_60m", ®, 19, 6)); + reg = 0; + clk_dm(SANDBOX_CLK_ECSPI0, + sandbox_clk_gate("ecspi0", "ecspi_root", ®, 0, 0)); + clk_dm(SANDBOX_CLK_ECSPI1, sandbox_clk_gate2("ecspi1", "ecspi_root", base + 0x6c, 0)); @@ -268,7 +273,7 @@ static int sandbox_clk_ccf_probe(struct udevice *dev) reg = BIT(28) | BIT(24) | BIT(16); clk_dm(SANDBOX_CLK_I2C, sandbox_clk_composite("i2c", i2c_sels, ARRAY_SIZE(i2c_sels), - ®, 0)); + ®, CLK_SET_RATE_UNGATE)); clk_dm(SANDBOX_CLK_I2C_ROOT, sandbox_clk_gate2("i2c_root", "i2c", base + 0x7c, 0)); diff --git a/drivers/clk/ics8n3qv01.c b/drivers/clk/ics8n3qv01.c index 4f80bf6e52..76b27ad7fd 100644 --- a/drivers/clk/ics8n3qv01.c +++ b/drivers/clk/ics8n3qv01.c @@ -82,7 +82,6 @@ static int ics8n3qv01_calc_parameters(uint fout, uint *_mint, uint *_mfrac, uint n, foutiic, fvcoiic, mint; u64 mfrac; - n = (2215000000U + fout / 2) / fout; if (fout < 417000000U) n = 2 * ((2215000000U / 2 + fout / 2) / fout); else diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index 11d194363d..5343036bab 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -113,6 +113,10 @@ static int imx6q_clk_probe(struct udevice *dev) imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0)); clk_dm(IMX6QDL_CLK_PLL2_PFD2_396M, imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2)); + clk_dm(IMX6QDL_CLK_PLL6, + imx_clk_pllv3(IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, 0x3)); + clk_dm(IMX6QDL_CLK_PLL6_ENET, + imx_clk_gate("pll6_enet", "pll6", base + 0xe0, 13)); /* CCM clocks */ base = dev_read_addr_ptr(dev); @@ -183,6 +187,10 @@ static int imx6q_clk_probe(struct udevice *dev) clk_dm(IMX6QDL_CLK_I2C2, imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8)); + clk_dm(IMX6QDL_CLK_ENET, imx_clk_gate2("enet", "ipg", base + 0x6c, 10)); + clk_dm(IMX6QDL_CLK_ENET_REF, + imx_clk_fixed_factor("enet_ref", "pll6_enet", 1, 1)); + return 0; } diff --git a/drivers/clk/imx/clk-pllv3.c b/drivers/clk/imx/clk-pllv3.c index b4a9d587e1..feacaee1c4 100644 --- a/drivers/clk/imx/clk-pllv3.c +++ b/drivers/clk/imx/clk-pllv3.c @@ -20,6 +20,7 @@ #define UBOOT_DM_CLK_IMX_PLLV3_SYS "imx_clk_pllv3_sys" #define UBOOT_DM_CLK_IMX_PLLV3_USB "imx_clk_pllv3_usb" #define UBOOT_DM_CLK_IMX_PLLV3_AV "imx_clk_pllv3_av" +#define UBOOT_DM_CLK_IMX_PLLV3_ENET "imx_clk_pllv3_enet" #define PLL_NUM_OFFSET 0x10 #define PLL_DENOM_OFFSET 0x20 @@ -36,6 +37,7 @@ struct clk_pllv3 { u32 enable_bit; u32 div_mask; u32 div_shift; + unsigned long ref_clock; }; #define to_clk_pllv3(_clk) container_of(_clk, struct clk_pllv3, clk) @@ -232,6 +234,19 @@ static const struct clk_ops clk_pllv3_av_ops = { .set_rate = clk_pllv3_av_set_rate, }; +static ulong clk_pllv3_enet_get_rate(struct clk *clk) +{ + struct clk_pllv3 *pll = to_clk_pllv3(clk); + + return pll->ref_clock; +} + +static const struct clk_ops clk_pllv3_enet_ops = { + .enable = clk_pllv3_generic_enable, + .disable = clk_pllv3_generic_disable, + .get_rate = clk_pllv3_enet_get_rate, +}; + struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, const char *parent_name, void __iomem *base, u32 div_mask) @@ -269,6 +284,10 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name, pll->div_shift = 0; pll->powerup_set = false; break; + case IMX_PLLV3_ENET: + drv_name = UBOOT_DM_CLK_IMX_PLLV3_ENET; + pll->ref_clock = 500000000; + break; default: kfree(pll); return ERR_PTR(-ENOTSUPP); @@ -314,3 +333,9 @@ U_BOOT_DRIVER(clk_pllv3_av) = { .ops = &clk_pllv3_av_ops, .flags = DM_FLAG_PRE_RELOC, }; + +U_BOOT_DRIVER(clk_pllv3_enet) = { + .name = UBOOT_DM_CLK_IMX_PLLV3_ENET, + .id = UCLASS_CLK, + .ops = &clk_pllv3_enet_ops, +}; diff --git a/include/sandbox-clk.h b/include/sandbox-clk.h index 296cddfbb0..c2616c27a4 100644 --- a/include/sandbox-clk.h +++ b/include/sandbox-clk.h @@ -50,6 +50,14 @@ static inline struct clk *sandbox_clk_divider(const char *name, reg, shift, width, 0); } +static inline struct clk *sandbox_clk_gate(const char *name, const char *parent, + void __iomem *reg, u8 bit_idx, + u8 clk_gate_flags) +{ + return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, + reg, bit_idx, clk_gate_flags, NULL); +} + struct clk *sandbox_clk_register_gate2(struct device *dev, const char *name, const char *parent_name, unsigned long flags, diff --git a/test/dm/clk_ccf.c b/test/dm/clk_ccf.c index 050fa80453..32bc4d2b8a 100644 --- a/test/dm/clk_ccf.c +++ b/test/dm/clk_ccf.c @@ -30,11 +30,22 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) ret = clk_get_by_id(SANDBOX_CLK_ECSPI_ROOT, &clk); ut_assertok(ret); ut_asserteq_str("ecspi_root", clk->dev->name); + ut_asserteq(CLK_SET_RATE_PARENT, clk->flags); /* Test for clk_get_parent_rate() */ ret = clk_get_by_id(SANDBOX_CLK_ECSPI1, &clk); ut_assertok(ret); ut_asserteq_str("ecspi1", clk->dev->name); + ut_asserteq(CLK_SET_RATE_PARENT, clk->flags); + + rate = clk_get_parent_rate(clk); + ut_asserteq(rate, 20000000); + + /* test the gate of CCF */ + ret = clk_get_by_id(SANDBOX_CLK_ECSPI0, &clk); + ut_assertok(ret); + ut_asserteq_str("ecspi0", clk->dev->name); + ut_asserteq(CLK_SET_RATE_PARENT, clk->flags); rate = clk_get_parent_rate(clk); ut_asserteq(rate, 20000000); @@ -43,24 +54,52 @@ static int dm_test_clk_ccf(struct unit_test_state *uts) ret = clk_get_by_id(SANDBOX_CLK_USDHC1_SEL, &clk); ut_assertok(ret); ut_asserteq_str("usdhc1_sel", clk->dev->name); + ut_asserteq(CLK_SET_RATE_NO_REPARENT, clk->flags); rate = clk_get_parent_rate(clk); ut_asserteq(rate, 60000000); + rate = clk_get_rate(clk); + ut_asserteq(rate, 60000000); + + ret = clk_get_by_id(SANDBOX_CLK_PLL3_80M, &pclk); + ut_assertok(ret); + + ret = clk_set_parent(clk, pclk); + ut_assertok(ret); + + rate = clk_get_rate(clk); + ut_asserteq(rate, 80000000); + ret = clk_get_by_id(SANDBOX_CLK_USDHC2_SEL, &clk); ut_assertok(ret); ut_asserteq_str("usdhc2_sel", clk->dev->name); + ut_asserteq(CLK_SET_RATE_NO_REPARENT, clk->flags); rate = clk_get_parent_rate(clk); ut_asserteq(rate, 80000000); pclk = clk_get_parent(clk); ut_asserteq_str("pll3_80m", pclk->dev->name); + ut_asserteq(CLK_SET_RATE_PARENT, pclk->flags); + + rate = clk_get_rate(clk); + ut_asserteq(rate, 80000000); + + ret = clk_get_by_id(SANDBOX_CLK_PLL3_60M, &pclk); + ut_assertok(ret); + + ret = clk_set_parent(clk, pclk); + ut_assertok(ret); + + rate = clk_get_rate(clk); + ut_asserteq(rate, 60000000); /* Test the composite of CCF */ ret = clk_get_by_id(SANDBOX_CLK_I2C, &clk); ut_assertok(ret); ut_asserteq_str("i2c", clk->dev->name); + ut_asserteq(CLK_SET_RATE_UNGATE, clk->flags); rate = clk_get_rate(clk); ut_asserteq(rate, 60000000);