On Monday 08 January 2018 07:47 AM, David Lechner wrote:
This adds a new driver for mach-davinci PLL clocks. This is porting the
code from arch/arm/mach-davinci/clock.c to the common clock framework.
Additionally, it adds device tree support for these clocks.
The ifeq ($(CONFIG_COMMON_CLK), y) in the Makefile is needed to prevent
compile errors until the clock code in arch/arm/mach-davinci is removed.
Note: although there are similar clocks for TI Keystone we are not able
to share the code for a few reasons. The keystone clocks are device tree
only and use legacy one-node-per-clock bindings. Also the register
layouts are a bit different, which would add even more if/else mess
to the keystone clocks. And the keystone PLL driver doesn't support
setting clock rates.
Signed-off-by: David Lechner <david@xxxxxxxxxxxxxx>
---
+
+#define PLLM_MASK 0x1f
+#define PREDIV_RATIO_MASK 0x1f
May be use the mode modern GENMASK()?
+static unsigned long davinci_pll_clk_recalc(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct davinci_pll_clk *pll = to_davinci_pll_clk(hw);
+ unsigned long rate = parent_rate;
+ u32 prediv, mult, postdiv;
+
+ prediv = readl(pll->base + PREDIV) & PREDIV_RATIO_MASK;
+ mult = readl(pll->base + PLLM) & PLLM_MASK;
+ postdiv = readl(pll->base + POSTDIV) & POSTDIV_RATIO_MASK;
Shouldn't we check if the pre and post dividers are enabled before using
them?
+
+ rate /= prediv + 1;
+ rate *= mult + 1;
+ rate /= postdiv + 1;
+
+ return rate;
+}
+
PLL output on DA850 must never be below 300MHz or above 600MHz (see
datasheet table "Allowed PLL Operating Conditions"). Does this take care
of that? Thats one of the main reasons I recall I went with some
specific values of prediv, pllm and post div in
arch/arm/mach-davinci/da850.c
+
+ divider->reg = base + OSCDIV;
+ divider->width = OSCDIV_RATIO_WIDTH;
can you write OD1EN of OSCDIV here? I guess the reset default is 1 so
you didnt need to do that. But not doing exposes us to settings that
bootloader left us in.
+
+ clk = clk_register_composite(NULL, name, parent_names, num_parents,
+ &mux->hw, &clk_mux_ops,
+ ÷r->hw, &clk_divider_ops,
+ &gate->hw, &clk_gate_ops, 0);
+ if (IS_ERR(clk)) {
+ kfree(divider);
+ kfree(gate);
+ kfree(mux);
+ }
+
+ return clk;
+}
+
+struct clk *
+davinci_pll_divclk_register(const struct davinci_pll_divclk_info *info,
+ void __iomem *base)
+{
+ const struct clk_ops *divider_ops = &clk_divider_ops;
setting the sysclk divider requires GOSTAT handling apart from setting
the divider value. So I think .set_rate ops above wont work. Other ops
can be used, I guess. So we need a private structure here.
Can you port over davinci_set_sysclk_rate() too? I understand you cannot
test it due to lack of cpufreq support in DT, but I can help testing there.
Or leave .set_rate NULL and it can be added later.
+
+ child = of_get_child_by_name(node, "auxclk");
+ if (child && of_device_is_available(child)) {
+ char child_name[MAX_NAME_SIZE];
+
+ snprintf(child_name, MAX_NAME_SIZE, "%s_aux_clk", name);
+
+ clk = davinci_pll_aux_clk_register(child_name, parent_name, base);
+ if (IS_ERR(clk))
+ pr_warn("%s: failed to register %s (%ld)\n", __func__,
+ child_name, PTR_ERR(clk));
+ else
+ of_clk_add_provider(child, of_clk_src_simple_get, clk);
+ }
davinci_pll_obs_clk_register() should also be handled here?