Lines Matching +full:parent +full:- +full:clk
1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2018 - Beniamino Galvani <b.galvani@gmail.com>
4 * (C) Copyright 2018 - BayLibre, SAS
9 #include <asm/arch/clock-gx.h>
11 #include <clk-uclass.h>
16 #include <dt-bindings/clock/gxbb-clkc.h>
20 * - Can calculate clock frequency on a limited tree
21 * - Can Read muxes and basic dividers (0-based only)
22 * - Can enable/disable gates with limited propagation
23 * - Can reparent without propagation, only on muxes
24 * - Can set rates without reparenting
25 * This driver is adapted to what is actually supported by U-Boot
73 static ulong meson_div_get_rate(struct clk *clk, unsigned long id);
74 static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate,
76 static ulong meson_mux_set_parent(struct clk *clk, unsigned long id,
78 static ulong meson_mux_get_rate(struct clk *clk, unsigned long id);
79 static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id,
81 static ulong meson_mux_get_parent(struct clk *clk, unsigned long id);
82 static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id);
195 static int meson_set_gate_by_id(struct clk *clk, unsigned long id, bool on) in meson_set_gate_by_id() argument
197 struct meson_clk *priv = dev_get_priv(clk->dev); in meson_set_gate_by_id()
205 return meson_set_gate_by_id(clk, in meson_set_gate_by_id()
206 meson_mux_get_parent(clk, CLKID_VPU), on); in meson_set_gate_by_id()
208 return meson_set_gate_by_id(clk, in meson_set_gate_by_id()
209 meson_mux_get_parent(clk, CLKID_VAPB_SEL), on); in meson_set_gate_by_id()
213 return -ENOENT; in meson_set_gate_by_id()
217 if (gate->reg == 0) in meson_set_gate_by_id()
222 regmap_update_bits(priv->map, gate->reg, in meson_set_gate_by_id()
223 BIT(gate->bit), on ? BIT(gate->bit) : 0); in meson_set_gate_by_id()
228 return meson_set_gate_by_id(clk, CLKID_VAPB_SEL, on); in meson_set_gate_by_id()
234 static int meson_clk_enable(struct clk *clk) in meson_clk_enable() argument
236 return meson_set_gate_by_id(clk, clk->id, true); in meson_clk_enable()
239 static int meson_clk_disable(struct clk *clk) in meson_clk_disable() argument
241 return meson_set_gate_by_id(clk, clk->id, false); in meson_clk_disable()
268 static ulong meson_div_get_rate(struct clk *clk, unsigned long id) in meson_div_get_rate() argument
270 struct meson_clk *priv = dev_get_priv(clk->dev); in meson_div_get_rate()
273 int parent; in meson_div_get_rate() local
279 parent = meson_vpu_0_div_parent; in meson_div_get_rate()
283 parent = meson_vpu_1_div_parent; in meson_div_get_rate()
287 parent = meson_vapb_0_div_parent; in meson_div_get_rate()
291 parent = meson_vapb_1_div_parent; in meson_div_get_rate()
294 return -ENOENT; in meson_div_get_rate()
297 regmap_read(priv->map, parm->reg_off, ®); in meson_div_get_rate()
298 reg = PARM_GET(parm->width, parm->shift, reg); in meson_div_get_rate()
302 parent_rate = meson_clk_get_rate_by_id(clk, parent); in meson_div_get_rate()
306 debug("%s: parent rate of %ld is %d\n", __func__, id, parent_rate); in meson_div_get_rate()
315 static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, in meson_div_set_rate() argument
318 struct meson_clk *priv = dev_get_priv(clk->dev); in meson_div_set_rate()
319 unsigned int new_div = -EINVAL; in meson_div_set_rate()
322 int parent; in meson_div_set_rate() local
334 parent = meson_vpu_0_div_parent; in meson_div_set_rate()
338 parent = meson_vpu_1_div_parent; in meson_div_set_rate()
342 parent = meson_vapb_0_div_parent; in meson_div_set_rate()
346 parent = meson_vapb_1_div_parent; in meson_div_set_rate()
349 return -ENOENT; in meson_div_set_rate()
352 parent_rate = meson_clk_get_rate_by_id(clk, parent); in meson_div_set_rate()
356 debug("%s: parent rate of %ld is %ld\n", __func__, id, parent_rate); in meson_div_set_rate()
358 /* If can't divide, set parent instead */ in meson_div_set_rate()
360 return meson_clk_set_rate_by_id(clk, parent, rate, in meson_div_set_rate()
367 /* If overflow, try to set parent rate and retry */ in meson_div_set_rate()
368 if (!new_div || new_div > (1 << parm->width)) { in meson_div_set_rate()
369 ret = meson_clk_set_rate_by_id(clk, parent, rate, current_rate); in meson_div_set_rate()
373 parent_rate = meson_clk_get_rate_by_id(clk, parent); in meson_div_set_rate()
381 if (!new_div || new_div > (1 << parm->width)) in meson_div_set_rate()
382 return -EINVAL; in meson_div_set_rate()
387 regmap_update_bits(priv->map, parm->reg_off, SETPMASK(parm->width, parm->shift), in meson_div_set_rate()
388 (new_div - 1) << parm->shift); in meson_div_set_rate()
391 __func__, id, meson_div_get_rate(clk, id)); in meson_div_set_rate()
444 static ulong meson_mux_get_parent(struct clk *clk, unsigned long id) in meson_mux_get_parent() argument
446 struct meson_clk *priv = dev_get_priv(clk->dev); in meson_mux_get_parent()
477 return -ENOENT; in meson_mux_get_parent()
480 regmap_read(priv->map, parm->reg_off, ®); in meson_mux_get_parent()
481 reg = PARM_GET(parm->width, parm->shift, reg); in meson_mux_get_parent()
483 debug("%s: parent of %ld is %d (%d)\n", in meson_mux_get_parent()
489 static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, in meson_mux_set_parent() argument
492 unsigned long cur_parent = meson_mux_get_parent(clk, id); in meson_mux_set_parent()
493 struct meson_clk *priv = dev_get_priv(clk->dev); in meson_mux_set_parent()
494 unsigned int new_index = -EINVAL; in meson_mux_set_parent()
502 debug("%s: setting parent of %ld from %ld to %ld\n", in meson_mux_set_parent()
535 return -ENOENT; in meson_mux_set_parent()
538 for (i = 0 ; i < (1 << parm->width) ; ++i) { in meson_mux_set_parent()
548 regmap_update_bits(priv->map, parm->reg_off, SETPMASK(parm->width, parm->shift), in meson_mux_set_parent()
549 new_index << parm->shift); in meson_mux_set_parent()
551 debug("%s: new parent of %ld is %ld\n", in meson_mux_set_parent()
552 __func__, id, meson_mux_get_parent(clk, id)); in meson_mux_set_parent()
557 static ulong meson_mux_get_rate(struct clk *clk, unsigned long id) in meson_mux_get_rate() argument
559 int parent = meson_mux_get_parent(clk, id); in meson_mux_get_rate() local
561 if (IS_ERR_VALUE(parent)) in meson_mux_get_rate()
562 return parent; in meson_mux_get_rate()
564 return meson_clk_get_rate_by_id(clk, parent); in meson_mux_get_rate()
567 static unsigned long meson_clk81_get_rate(struct clk *clk) in meson_clk81_get_rate() argument
569 struct meson_clk *priv = dev_get_priv(clk->dev); in meson_clk81_get_rate()
573 -1, in meson_clk81_get_rate()
574 -1, in meson_clk81_get_rate()
584 regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); in meson_clk81_get_rate()
592 return -ENOENT; in meson_clk81_get_rate()
594 parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]); in meson_clk81_get_rate()
598 regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); in meson_clk81_get_rate()
599 reg = reg & ((1 << 7) - 1); in meson_clk81_get_rate()
612 return -EINVAL; in mpll_rate_from_params()
638 static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id) in meson_mpll_get_rate() argument
640 struct meson_clk *priv = dev_get_priv(clk->dev); in meson_mpll_get_rate()
660 return -ENOENT; in meson_mpll_get_rate()
663 parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL); in meson_mpll_get_rate()
667 regmap_read(priv->map, psdm->reg_off, ®); in meson_mpll_get_rate()
668 sdm = PARM_GET(psdm->width, psdm->shift, reg); in meson_mpll_get_rate()
670 regmap_read(priv->map, pn2->reg_off, ®); in meson_mpll_get_rate()
671 n2 = PARM_GET(pn2->width, pn2->shift, reg); in meson_mpll_get_rate()
688 static ulong meson_pll_get_rate(struct clk *clk, unsigned long id) in meson_pll_get_rate() argument
690 struct meson_clk *priv = dev_get_priv(clk->dev); in meson_pll_get_rate()
708 return -ENOENT; in meson_pll_get_rate()
711 regmap_read(priv->map, pn->reg_off, ®); in meson_pll_get_rate()
712 n = PARM_GET(pn->width, pn->shift, reg); in meson_pll_get_rate()
714 regmap_read(priv->map, pm->reg_off, ®); in meson_pll_get_rate()
715 m = PARM_GET(pm->width, pm->shift, reg); in meson_pll_get_rate()
717 regmap_read(priv->map, pod->reg_off, ®); in meson_pll_get_rate()
718 od = PARM_GET(pod->width, pod->shift, reg); in meson_pll_get_rate()
723 static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) in meson_clk_get_rate_by_id() argument
730 rate = meson_pll_get_rate(clk, id); in meson_clk_get_rate_by_id()
733 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2; in meson_clk_get_rate_by_id()
736 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3; in meson_clk_get_rate_by_id()
739 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4; in meson_clk_get_rate_by_id()
742 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5; in meson_clk_get_rate_by_id()
745 rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7; in meson_clk_get_rate_by_id()
750 rate = meson_mpll_get_rate(clk, id); in meson_clk_get_rate_by_id()
753 rate = meson_clk81_get_rate(clk); in meson_clk_get_rate_by_id()
756 rate = meson_div_get_rate(clk, CLKID_VPU_0_DIV); in meson_clk_get_rate_by_id()
759 rate = meson_div_get_rate(clk, CLKID_VPU_1_DIV); in meson_clk_get_rate_by_id()
762 rate = meson_mux_get_rate(clk, CLKID_VAPB_SEL); in meson_clk_get_rate_by_id()
765 rate = meson_div_get_rate(clk, CLKID_VAPB_0_DIV); in meson_clk_get_rate_by_id()
768 rate = meson_div_get_rate(clk, CLKID_VAPB_1_DIV); in meson_clk_get_rate_by_id()
774 rate = meson_div_get_rate(clk, id); in meson_clk_get_rate_by_id()
782 rate = meson_mux_get_rate(clk, id); in meson_clk_get_rate_by_id()
787 rate = meson_clk81_get_rate(clk); in meson_clk_get_rate_by_id()
790 return -ENOENT; in meson_clk_get_rate_by_id()
797 static ulong meson_clk_get_rate(struct clk *clk) in meson_clk_get_rate() argument
799 return meson_clk_get_rate_by_id(clk, clk->id); in meson_clk_get_rate()
802 static int meson_clk_set_parent(struct clk *clk, struct clk *parent) in meson_clk_set_parent() argument
804 return meson_mux_set_parent(clk, clk->id, parent->id); in meson_clk_set_parent()
807 static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, in meson_clk_set_rate_by_id() argument
827 return -EINVAL; in meson_clk_set_rate_by_id()
831 return meson_clk_set_rate_by_id(clk, in meson_clk_set_rate_by_id()
832 meson_mux_get_parent(clk, CLKID_VPU), rate, in meson_clk_set_rate_by_id()
836 return meson_clk_set_rate_by_id(clk, in meson_clk_set_rate_by_id()
837 meson_mux_get_parent(clk, CLKID_VAPB_SEL), in meson_clk_set_rate_by_id()
840 return meson_div_set_rate(clk, CLKID_VPU_0_DIV, rate, in meson_clk_set_rate_by_id()
843 return meson_div_set_rate(clk, CLKID_VPU_1_DIV, rate, in meson_clk_set_rate_by_id()
846 return meson_div_set_rate(clk, CLKID_VAPB_0_DIV, rate, in meson_clk_set_rate_by_id()
849 return meson_div_set_rate(clk, CLKID_VAPB_1_DIV, rate, in meson_clk_set_rate_by_id()
855 return meson_div_set_rate(clk, id, rate, current_rate); in meson_clk_set_rate_by_id()
857 return -ENOENT; in meson_clk_set_rate_by_id()
860 return -EINVAL; in meson_clk_set_rate_by_id()
863 static ulong meson_clk_set_rate(struct clk *clk, ulong rate) in meson_clk_set_rate() argument
865 ulong current_rate = meson_clk_get_rate_by_id(clk, clk->id); in meson_clk_set_rate()
872 __func__, clk->id, current_rate, rate); in meson_clk_set_rate()
874 ret = meson_clk_set_rate_by_id(clk, clk->id, rate, current_rate); in meson_clk_set_rate()
878 debug("clock %lu has new rate %lu\n", clk->id, in meson_clk_set_rate()
879 meson_clk_get_rate_by_id(clk, clk->id)); in meson_clk_set_rate()
888 priv->map = syscon_node_to_regmap(dev_get_parent(dev)->node); in meson_clk_probe()
889 if (IS_ERR(priv->map)) in meson_clk_probe()
890 return PTR_ERR(priv->map); in meson_clk_probe()
892 debug("meson-clk: probed\n"); in meson_clk_probe()
906 { .compatible = "amlogic,gxbb-clkc" },
907 { .compatible = "amlogic,gxl-clkc" },