diff options
author | Jerome Brunet <jbrunet@baylibre.com> | 2018-02-12 09:58:42 -0500 |
---|---|---|
committer | Neil Armstrong <narmstrong@baylibre.com> | 2018-03-13 05:04:03 -0400 |
commit | 722825dcd54b2e427c1aee54a7992eb4ab04a49d (patch) | |
tree | 5abe9c46643a0681d86e24f214816a8ffb911fa3 | |
parent | 88a4e1283681e0f07048b2bd867cc81fbbae57cc (diff) |
clk: meson: migrate plls clocks to clk_regmap
Rework meson pll driver to use clk_regmap and move meson8b, gxbb and
axg's clock using meson_clk_pll to clk_regmap.
This rework is not just about clk_regmap, there a serious clean-up of
the driver code:
* Add lock and reset field: Previously inferred from the n field.
* Simplify the reset logic: Code seemed to apply reset differently but
in fact it was always the same -> assert reset, apply params,
de-assert reset. The 2 lock checking loops have been kept for now, as
they seem to be necessary.
* Do the sequence of init register pokes only at .init() instead of in
.set_rate(). Redoing the init on every set_rate() is not necessary
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
-rw-r--r-- | drivers/clk/meson/axg.c | 213 | ||||
-rw-r--r-- | drivers/clk/meson/clk-pll.c | 243 | ||||
-rw-r--r-- | drivers/clk/meson/clkc.h | 36 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb.c | 424 | ||||
-rw-r--r-- | drivers/clk/meson/meson8b.c | 149 |
5 files changed, 535 insertions, 530 deletions
diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 85f9466ce006..8c27ceffda4a 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c | |||
@@ -22,28 +22,39 @@ | |||
22 | 22 | ||
23 | static DEFINE_SPINLOCK(meson_clk_lock); | 23 | static DEFINE_SPINLOCK(meson_clk_lock); |
24 | 24 | ||
25 | static struct meson_clk_pll axg_fixed_pll = { | 25 | static struct clk_regmap axg_fixed_pll = { |
26 | .m = { | 26 | .data = &(struct meson_clk_pll_data){ |
27 | .reg_off = HHI_MPLL_CNTL, | 27 | .m = { |
28 | .shift = 0, | 28 | .reg_off = HHI_MPLL_CNTL, |
29 | .width = 9, | 29 | .shift = 0, |
30 | }, | 30 | .width = 9, |
31 | .n = { | 31 | }, |
32 | .reg_off = HHI_MPLL_CNTL, | 32 | .n = { |
33 | .shift = 9, | 33 | .reg_off = HHI_MPLL_CNTL, |
34 | .width = 5, | 34 | .shift = 9, |
35 | }, | 35 | .width = 5, |
36 | .od = { | 36 | }, |
37 | .reg_off = HHI_MPLL_CNTL, | 37 | .od = { |
38 | .shift = 16, | 38 | .reg_off = HHI_MPLL_CNTL, |
39 | .width = 2, | 39 | .shift = 16, |
40 | }, | 40 | .width = 2, |
41 | .frac = { | 41 | }, |
42 | .reg_off = HHI_MPLL_CNTL2, | 42 | .frac = { |
43 | .shift = 0, | 43 | .reg_off = HHI_MPLL_CNTL2, |
44 | .width = 12, | 44 | .shift = 0, |
45 | }, | 45 | .width = 12, |
46 | .lock = &meson_clk_lock, | 46 | }, |
47 | .l = { | ||
48 | .reg_off = HHI_MPLL_CNTL, | ||
49 | .shift = 31, | ||
50 | .width = 1, | ||
51 | }, | ||
52 | .rst = { | ||
53 | .reg_off = HHI_MPLL_CNTL, | ||
54 | .shift = 29, | ||
55 | .width = 1, | ||
56 | }, | ||
57 | }, | ||
47 | .hw.init = &(struct clk_init_data){ | 58 | .hw.init = &(struct clk_init_data){ |
48 | .name = "fixed_pll", | 59 | .name = "fixed_pll", |
49 | .ops = &meson_clk_pll_ro_ops, | 60 | .ops = &meson_clk_pll_ro_ops, |
@@ -52,23 +63,34 @@ static struct meson_clk_pll axg_fixed_pll = { | |||
52 | }, | 63 | }, |
53 | }; | 64 | }; |
54 | 65 | ||
55 | static struct meson_clk_pll axg_sys_pll = { | 66 | static struct clk_regmap axg_sys_pll = { |
56 | .m = { | 67 | .data = &(struct meson_clk_pll_data){ |
57 | .reg_off = HHI_SYS_PLL_CNTL, | 68 | .m = { |
58 | .shift = 0, | 69 | .reg_off = HHI_SYS_PLL_CNTL, |
59 | .width = 9, | 70 | .shift = 0, |
60 | }, | 71 | .width = 9, |
61 | .n = { | 72 | }, |
62 | .reg_off = HHI_SYS_PLL_CNTL, | 73 | .n = { |
63 | .shift = 9, | 74 | .reg_off = HHI_SYS_PLL_CNTL, |
64 | .width = 5, | 75 | .shift = 9, |
65 | }, | 76 | .width = 5, |
66 | .od = { | 77 | }, |
67 | .reg_off = HHI_SYS_PLL_CNTL, | 78 | .od = { |
68 | .shift = 16, | 79 | .reg_off = HHI_SYS_PLL_CNTL, |
69 | .width = 2, | 80 | .shift = 16, |
81 | .width = 2, | ||
82 | }, | ||
83 | .l = { | ||
84 | .reg_off = HHI_SYS_PLL_CNTL, | ||
85 | .shift = 31, | ||
86 | .width = 1, | ||
87 | }, | ||
88 | .rst = { | ||
89 | .reg_off = HHI_SYS_PLL_CNTL, | ||
90 | .shift = 29, | ||
91 | .width = 1, | ||
92 | }, | ||
70 | }, | 93 | }, |
71 | .lock = &meson_clk_lock, | ||
72 | .hw.init = &(struct clk_init_data){ | 94 | .hw.init = &(struct clk_init_data){ |
73 | .name = "sys_pll", | 95 | .name = "sys_pll", |
74 | .ops = &meson_clk_pll_ro_ops, | 96 | .ops = &meson_clk_pll_ro_ops, |
@@ -169,40 +191,47 @@ static const struct pll_rate_table axg_gp0_pll_rate_table[] = { | |||
169 | { /* sentinel */ }, | 191 | { /* sentinel */ }, |
170 | }; | 192 | }; |
171 | 193 | ||
172 | static struct pll_params_table axg_gp0_params_table[] = { | 194 | const struct reg_sequence axg_gp0_init_regs[] = { |
173 | PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), | 195 | { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, |
174 | PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), | 196 | { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084a000 }, |
175 | PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), | 197 | { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, |
176 | PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), | 198 | { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, |
177 | PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), | 199 | { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, |
178 | PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), | 200 | { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, |
179 | }; | 201 | }; |
180 | 202 | ||
181 | static struct meson_clk_pll axg_gp0_pll = { | 203 | static struct clk_regmap axg_gp0_pll = { |
182 | .m = { | 204 | .data = &(struct meson_clk_pll_data){ |
183 | .reg_off = HHI_GP0_PLL_CNTL, | 205 | .m = { |
184 | .shift = 0, | 206 | .reg_off = HHI_GP0_PLL_CNTL, |
185 | .width = 9, | 207 | .shift = 0, |
186 | }, | 208 | .width = 9, |
187 | .n = { | 209 | }, |
188 | .reg_off = HHI_GP0_PLL_CNTL, | 210 | .n = { |
189 | .shift = 9, | 211 | .reg_off = HHI_GP0_PLL_CNTL, |
190 | .width = 5, | 212 | .shift = 9, |
191 | }, | 213 | .width = 5, |
192 | .od = { | 214 | }, |
193 | .reg_off = HHI_GP0_PLL_CNTL, | 215 | .od = { |
194 | .shift = 16, | 216 | .reg_off = HHI_GP0_PLL_CNTL, |
195 | .width = 2, | 217 | .shift = 16, |
196 | }, | 218 | .width = 2, |
197 | .params = { | 219 | }, |
198 | .params_table = axg_gp0_params_table, | 220 | .l = { |
199 | .params_count = ARRAY_SIZE(axg_gp0_params_table), | 221 | .reg_off = HHI_GP0_PLL_CNTL, |
200 | .no_init_reset = true, | 222 | .shift = 31, |
201 | .reset_lock_loop = true, | 223 | .width = 1, |
202 | }, | 224 | }, |
203 | .rate_table = axg_gp0_pll_rate_table, | 225 | .rst = { |
204 | .rate_count = ARRAY_SIZE(axg_gp0_pll_rate_table), | 226 | .reg_off = HHI_GP0_PLL_CNTL, |
205 | .lock = &meson_clk_lock, | 227 | .shift = 29, |
228 | .width = 1, | ||
229 | }, | ||
230 | .table = axg_gp0_pll_rate_table, | ||
231 | .init_regs = axg_gp0_init_regs, | ||
232 | .init_count = ARRAY_SIZE(axg_gp0_init_regs), | ||
233 | .flags = CLK_MESON_PLL_LOCK_LOOP_RST, | ||
234 | }, | ||
206 | .hw.init = &(struct clk_init_data){ | 235 | .hw.init = &(struct clk_init_data){ |
207 | .name = "gp0_pll", | 236 | .name = "gp0_pll", |
208 | .ops = &meson_clk_pll_ops, | 237 | .ops = &meson_clk_pll_ops, |
@@ -698,14 +727,7 @@ static struct clk_hw_onecell_data axg_hw_onecell_data = { | |||
698 | .num = NR_CLKS, | 727 | .num = NR_CLKS, |
699 | }; | 728 | }; |
700 | 729 | ||
701 | /* Convenience tables to populate base addresses in .probe */ | 730 | /* Convenience table to populate regmap in .probe */ |
702 | |||
703 | static struct meson_clk_pll *const axg_clk_plls[] = { | ||
704 | &axg_fixed_pll, | ||
705 | &axg_sys_pll, | ||
706 | &axg_gp0_pll, | ||
707 | }; | ||
708 | |||
709 | static struct clk_regmap *const axg_clk_regmaps[] = { | 731 | static struct clk_regmap *const axg_clk_regmaps[] = { |
710 | &axg_clk81, | 732 | &axg_clk81, |
711 | &axg_ddr, | 733 | &axg_ddr, |
@@ -764,22 +786,13 @@ static struct clk_regmap *const axg_clk_regmaps[] = { | |||
764 | &axg_mpll1, | 786 | &axg_mpll1, |
765 | &axg_mpll2, | 787 | &axg_mpll2, |
766 | &axg_mpll3, | 788 | &axg_mpll3, |
767 | }; | 789 | &axg_fixed_pll, |
768 | 790 | &axg_sys_pll, | |
769 | struct clkc_data { | 791 | &axg_gp0_pll, |
770 | struct meson_clk_pll *const *clk_plls; | ||
771 | unsigned int clk_plls_count; | ||
772 | struct clk_hw_onecell_data *hw_onecell_data; | ||
773 | }; | ||
774 | |||
775 | static const struct clkc_data axg_clkc_data = { | ||
776 | .clk_plls = axg_clk_plls, | ||
777 | .clk_plls_count = ARRAY_SIZE(axg_clk_plls), | ||
778 | .hw_onecell_data = &axg_hw_onecell_data, | ||
779 | }; | 792 | }; |
780 | 793 | ||
781 | static const struct of_device_id clkc_match_table[] = { | 794 | static const struct of_device_id clkc_match_table[] = { |
782 | { .compatible = "amlogic,axg-clkc", .data = &axg_clkc_data }, | 795 | { .compatible = "amlogic,axg-clkc" }, |
783 | {} | 796 | {} |
784 | }; | 797 | }; |
785 | 798 | ||
@@ -792,16 +805,11 @@ static const struct regmap_config clkc_regmap_config = { | |||
792 | static int axg_clkc_probe(struct platform_device *pdev) | 805 | static int axg_clkc_probe(struct platform_device *pdev) |
793 | { | 806 | { |
794 | struct device *dev = &pdev->dev; | 807 | struct device *dev = &pdev->dev; |
795 | const struct clkc_data *clkc_data; | ||
796 | struct resource *res; | 808 | struct resource *res; |
797 | void __iomem *clk_base; | 809 | void __iomem *clk_base; |
798 | struct regmap *map; | 810 | struct regmap *map; |
799 | int ret, i; | 811 | int ret, i; |
800 | 812 | ||
801 | clkc_data = of_device_get_match_data(dev); | ||
802 | if (!clkc_data) | ||
803 | return -EINVAL; | ||
804 | |||
805 | /* Generic clocks and PLLs */ | 813 | /* Generic clocks and PLLs */ |
806 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 814 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
807 | if (!res) | 815 | if (!res) |
@@ -817,21 +825,16 @@ static int axg_clkc_probe(struct platform_device *pdev) | |||
817 | if (IS_ERR(map)) | 825 | if (IS_ERR(map)) |
818 | return PTR_ERR(map); | 826 | return PTR_ERR(map); |
819 | 827 | ||
820 | /* Populate base address for PLLs */ | ||
821 | for (i = 0; i < clkc_data->clk_plls_count; i++) | ||
822 | clkc_data->clk_plls[i]->base = clk_base; | ||
823 | |||
824 | /* Populate regmap for the regmap backed clocks */ | 828 | /* Populate regmap for the regmap backed clocks */ |
825 | for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) | 829 | for (i = 0; i < ARRAY_SIZE(axg_clk_regmaps); i++) |
826 | axg_clk_regmaps[i]->map = map; | 830 | axg_clk_regmaps[i]->map = map; |
827 | 831 | ||
828 | for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { | 832 | for (i = 0; i < axg_hw_onecell_data.num; i++) { |
829 | /* array might be sparse */ | 833 | /* array might be sparse */ |
830 | if (!clkc_data->hw_onecell_data->hws[i]) | 834 | if (!axg_hw_onecell_data.hws[i]) |
831 | continue; | 835 | continue; |
832 | 836 | ||
833 | ret = devm_clk_hw_register(dev, | 837 | ret = devm_clk_hw_register(dev, axg_hw_onecell_data.hws[i]); |
834 | clkc_data->hw_onecell_data->hws[i]); | ||
835 | if (ret) { | 838 | if (ret) { |
836 | dev_err(dev, "Clock registration failed\n"); | 839 | dev_err(dev, "Clock registration failed\n"); |
837 | return ret; | 840 | return ret; |
@@ -839,7 +842,7 @@ static int axg_clkc_probe(struct platform_device *pdev) | |||
839 | } | 842 | } |
840 | 843 | ||
841 | return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, | 844 | return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, |
842 | clkc_data->hw_onecell_data); | 845 | &axg_hw_onecell_data); |
843 | } | 846 | } |
844 | 847 | ||
845 | static struct platform_driver axg_driver = { | 848 | static struct platform_driver axg_driver = { |
diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 218c769c6d50..f3d909719111 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c | |||
@@ -42,52 +42,36 @@ | |||
42 | 42 | ||
43 | #include "clkc.h" | 43 | #include "clkc.h" |
44 | 44 | ||
45 | #define MESON_PLL_RESET BIT(29) | 45 | static inline struct meson_clk_pll_data * |
46 | #define MESON_PLL_LOCK BIT(31) | 46 | meson_clk_pll_data(struct clk_regmap *clk) |
47 | 47 | { | |
48 | #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) | 48 | return (struct meson_clk_pll_data *)clk->data; |
49 | } | ||
49 | 50 | ||
50 | static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, | 51 | static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, |
51 | unsigned long parent_rate) | 52 | unsigned long parent_rate) |
52 | { | 53 | { |
53 | struct meson_clk_pll *pll = to_meson_clk_pll(hw); | 54 | struct clk_regmap *clk = to_clk_regmap(hw); |
54 | struct parm *p; | 55 | struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); |
55 | u64 rate; | 56 | u64 rate; |
56 | u16 n, m, frac = 0, od, od2 = 0, od3 = 0; | 57 | u16 n, m, frac = 0, od, od2 = 0, od3 = 0; |
57 | u32 reg; | ||
58 | |||
59 | p = &pll->n; | ||
60 | reg = readl(pll->base + p->reg_off); | ||
61 | n = PARM_GET(p->width, p->shift, reg); | ||
62 | 58 | ||
63 | p = &pll->m; | 59 | n = meson_parm_read(clk->map, &pll->n); |
64 | reg = readl(pll->base + p->reg_off); | 60 | m = meson_parm_read(clk->map, &pll->m); |
65 | m = PARM_GET(p->width, p->shift, reg); | 61 | od = meson_parm_read(clk->map, &pll->od); |
66 | 62 | ||
67 | p = &pll->od; | 63 | if (MESON_PARM_APPLICABLE(&pll->od2)) |
68 | reg = readl(pll->base + p->reg_off); | 64 | od2 = meson_parm_read(clk->map, &pll->od2); |
69 | od = PARM_GET(p->width, p->shift, reg); | ||
70 | 65 | ||
71 | p = &pll->od2; | 66 | if (MESON_PARM_APPLICABLE(&pll->od3)) |
72 | if (p->width) { | 67 | od3 = meson_parm_read(clk->map, &pll->od3); |
73 | reg = readl(pll->base + p->reg_off); | ||
74 | od2 = PARM_GET(p->width, p->shift, reg); | ||
75 | } | ||
76 | |||
77 | p = &pll->od3; | ||
78 | if (p->width) { | ||
79 | reg = readl(pll->base + p->reg_off); | ||
80 | od3 = PARM_GET(p->width, p->shift, reg); | ||
81 | } | ||
82 | 68 | ||
83 | rate = (u64)m * parent_rate; | 69 | rate = (u64)m * parent_rate; |
84 | 70 | ||
85 | p = &pll->frac; | 71 | if (MESON_PARM_APPLICABLE(&pll->frac)) { |
86 | if (p->width) { | 72 | frac = meson_parm_read(clk->map, &pll->frac); |
87 | reg = readl(pll->base + p->reg_off); | ||
88 | frac = PARM_GET(p->width, p->shift, reg); | ||
89 | 73 | ||
90 | rate += mul_u64_u32_shr(parent_rate, frac, p->width); | 74 | rate += mul_u64_u32_shr(parent_rate, frac, pll->frac.width); |
91 | } | 75 | } |
92 | 76 | ||
93 | return div_u64(rate, n) >> od >> od2 >> od3; | 77 | return div_u64(rate, n) >> od >> od2 >> od3; |
@@ -96,177 +80,136 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, | |||
96 | static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, | 80 | static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, |
97 | unsigned long *parent_rate) | 81 | unsigned long *parent_rate) |
98 | { | 82 | { |
99 | struct meson_clk_pll *pll = to_meson_clk_pll(hw); | 83 | struct clk_regmap *clk = to_clk_regmap(hw); |
100 | const struct pll_rate_table *rate_table = pll->rate_table; | 84 | struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); |
101 | int i; | 85 | const struct pll_rate_table *pllt; |
102 | 86 | ||
103 | /* | 87 | /* |
104 | * if the table is missing, just return the current rate | 88 | * if the table is missing, just return the current rate |
105 | * since we don't have the other available frequencies | 89 | * since we don't have the other available frequencies |
106 | */ | 90 | */ |
107 | if (!rate_table) | 91 | if (!pll->table) |
108 | return meson_clk_pll_recalc_rate(hw, *parent_rate); | 92 | return meson_clk_pll_recalc_rate(hw, *parent_rate); |
109 | 93 | ||
110 | for (i = 0; i < pll->rate_count; i++) { | 94 | for (pllt = pll->table; pllt->rate; pllt++) { |
111 | if (rate <= rate_table[i].rate) | 95 | if (rate <= pllt->rate) |
112 | return rate_table[i].rate; | 96 | return pllt->rate; |
113 | } | 97 | } |
114 | 98 | ||
115 | /* else return the smallest value */ | 99 | /* else return the smallest value */ |
116 | return rate_table[0].rate; | 100 | return pll->table[0].rate; |
117 | } | 101 | } |
118 | 102 | ||
119 | static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll, | 103 | static const struct pll_rate_table * |
120 | unsigned long rate) | 104 | meson_clk_get_pll_settings(const struct pll_rate_table *table, |
105 | unsigned long rate) | ||
121 | { | 106 | { |
122 | const struct pll_rate_table *rate_table = pll->rate_table; | 107 | const struct pll_rate_table *pllt; |
123 | int i; | ||
124 | 108 | ||
125 | if (!rate_table) | 109 | if (!table) |
126 | return NULL; | 110 | return NULL; |
127 | 111 | ||
128 | for (i = 0; i < pll->rate_count; i++) { | 112 | for (pllt = table; pllt->rate; pllt++) { |
129 | if (rate == rate_table[i].rate) | 113 | if (rate == pllt->rate) |
130 | return &rate_table[i]; | 114 | return pllt; |
131 | } | 115 | } |
116 | |||
132 | return NULL; | 117 | return NULL; |
133 | } | 118 | } |
134 | 119 | ||
135 | /* Specific wait loop for GXL/GXM GP0 PLL */ | 120 | static int meson_clk_pll_wait_lock(struct clk_hw *hw) |
136 | static int meson_clk_pll_wait_lock_reset(struct meson_clk_pll *pll, | ||
137 | struct parm *p_n) | ||
138 | { | 121 | { |
139 | int delay = 100; | 122 | struct clk_regmap *clk = to_clk_regmap(hw); |
140 | u32 reg; | 123 | struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); |
141 | 124 | int delay = pll->flags & CLK_MESON_PLL_LOCK_LOOP_RST ? | |
142 | while (delay > 0) { | 125 | 100 : 24000000; |
143 | reg = readl(pll->base + p_n->reg_off); | 126 | |
144 | writel(reg | MESON_PLL_RESET, pll->base + p_n->reg_off); | 127 | do { |
145 | udelay(10); | 128 | /* Specific wait loop for GXL/GXM GP0 PLL */ |
146 | writel(reg & ~MESON_PLL_RESET, pll->base + p_n->reg_off); | 129 | if (pll->flags & CLK_MESON_PLL_LOCK_LOOP_RST) { |
147 | 130 | /* Procedure taken from the vendor kernel */ | |
148 | /* This delay comes from AMLogic tree clk-gp0-gxl driver */ | 131 | meson_parm_write(clk->map, &pll->rst, 1); |
149 | mdelay(1); | 132 | udelay(10); |
150 | 133 | meson_parm_write(clk->map, &pll->rst, 0); | |
151 | reg = readl(pll->base + p_n->reg_off); | 134 | mdelay(1); |
152 | if (reg & MESON_PLL_LOCK) | 135 | } |
136 | |||
137 | /* Is the clock locked now ? */ | ||
138 | if (meson_parm_read(clk->map, &pll->l)) | ||
153 | return 0; | 139 | return 0; |
154 | delay--; | ||
155 | } | ||
156 | return -ETIMEDOUT; | ||
157 | } | ||
158 | 140 | ||
159 | static int meson_clk_pll_wait_lock(struct meson_clk_pll *pll, | ||
160 | struct parm *p_n) | ||
161 | { | ||
162 | int delay = 24000000; | ||
163 | u32 reg; | ||
164 | |||
165 | while (delay > 0) { | ||
166 | reg = readl(pll->base + p_n->reg_off); | ||
167 | |||
168 | if (reg & MESON_PLL_LOCK) | ||
169 | return 0; | ||
170 | delay--; | 141 | delay--; |
171 | } | 142 | } while (delay > 0); |
143 | |||
172 | return -ETIMEDOUT; | 144 | return -ETIMEDOUT; |
173 | } | 145 | } |
174 | 146 | ||
175 | static void meson_clk_pll_init_params(struct meson_clk_pll *pll) | 147 | static void meson_clk_pll_init(struct clk_hw *hw) |
176 | { | 148 | { |
177 | int i; | 149 | struct clk_regmap *clk = to_clk_regmap(hw); |
178 | 150 | struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); | |
179 | for (i = 0 ; i < pll->params.params_count ; ++i) | 151 | |
180 | writel(pll->params.params_table[i].value, | 152 | if (pll->init_count) { |
181 | pll->base + pll->params.params_table[i].reg_off); | 153 | meson_parm_write(clk->map, &pll->rst, 1); |
154 | regmap_multi_reg_write(clk->map, pll->init_regs, | ||
155 | pll->init_count); | ||
156 | meson_parm_write(clk->map, &pll->rst, 0); | ||
157 | } | ||
182 | } | 158 | } |
183 | 159 | ||
184 | static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, | 160 | static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, |
185 | unsigned long parent_rate) | 161 | unsigned long parent_rate) |
186 | { | 162 | { |
187 | struct meson_clk_pll *pll = to_meson_clk_pll(hw); | 163 | struct clk_regmap *clk = to_clk_regmap(hw); |
188 | struct parm *p; | 164 | struct meson_clk_pll_data *pll = meson_clk_pll_data(clk); |
189 | const struct pll_rate_table *rate_set; | 165 | const struct pll_rate_table *pllt; |
190 | unsigned long old_rate; | 166 | unsigned long old_rate; |
191 | int ret = 0; | ||
192 | u32 reg; | ||
193 | 167 | ||
194 | if (parent_rate == 0 || rate == 0) | 168 | if (parent_rate == 0 || rate == 0) |
195 | return -EINVAL; | 169 | return -EINVAL; |
196 | 170 | ||
197 | old_rate = rate; | 171 | old_rate = rate; |
198 | 172 | ||
199 | rate_set = meson_clk_get_pll_settings(pll, rate); | 173 | pllt = meson_clk_get_pll_settings(pll->table, rate); |
200 | if (!rate_set) | 174 | if (!pllt) |
201 | return -EINVAL; | 175 | return -EINVAL; |
202 | 176 | ||
203 | /* Initialize the PLL in a clean state if specified */ | 177 | /* Put the pll in reset to write the params */ |
204 | if (pll->params.params_count) | 178 | meson_parm_write(clk->map, &pll->rst, 1); |
205 | meson_clk_pll_init_params(pll); | ||
206 | |||
207 | /* PLL reset */ | ||
208 | p = &pll->n; | ||
209 | reg = readl(pll->base + p->reg_off); | ||
210 | /* If no_init_reset is provided, avoid resetting at this point */ | ||
211 | if (!pll->params.no_init_reset) | ||
212 | writel(reg | MESON_PLL_RESET, pll->base + p->reg_off); | ||
213 | |||
214 | reg = PARM_SET(p->width, p->shift, reg, rate_set->n); | ||
215 | writel(reg, pll->base + p->reg_off); | ||
216 | |||
217 | p = &pll->m; | ||
218 | reg = readl(pll->base + p->reg_off); | ||
219 | reg = PARM_SET(p->width, p->shift, reg, rate_set->m); | ||
220 | writel(reg, pll->base + p->reg_off); | ||
221 | |||
222 | p = &pll->od; | ||
223 | reg = readl(pll->base + p->reg_off); | ||
224 | reg = PARM_SET(p->width, p->shift, reg, rate_set->od); | ||
225 | writel(reg, pll->base + p->reg_off); | ||
226 | |||
227 | p = &pll->od2; | ||
228 | if (p->width) { | ||
229 | reg = readl(pll->base + p->reg_off); | ||
230 | reg = PARM_SET(p->width, p->shift, reg, rate_set->od2); | ||
231 | writel(reg, pll->base + p->reg_off); | ||
232 | } | ||
233 | 179 | ||
234 | p = &pll->od3; | 180 | meson_parm_write(clk->map, &pll->n, pllt->n); |
235 | if (p->width) { | 181 | meson_parm_write(clk->map, &pll->m, pllt->m); |
236 | reg = readl(pll->base + p->reg_off); | 182 | meson_parm_write(clk->map, &pll->od, pllt->od); |
237 | reg = PARM_SET(p->width, p->shift, reg, rate_set->od3); | ||
238 | writel(reg, pll->base + p->reg_off); | ||
239 | } | ||
240 | 183 | ||
241 | p = &pll->frac; | 184 | if (MESON_PARM_APPLICABLE(&pll->od2)) |
242 | if (p->width) { | 185 | meson_parm_write(clk->map, &pll->od2, pllt->od2); |
243 | reg = readl(pll->base + p->reg_off); | ||
244 | reg = PARM_SET(p->width, p->shift, reg, rate_set->frac); | ||
245 | writel(reg, pll->base + p->reg_off); | ||
246 | } | ||
247 | 186 | ||
248 | p = &pll->n; | 187 | if (MESON_PARM_APPLICABLE(&pll->od3)) |
249 | /* If clear_reset_for_lock is provided, remove the reset bit here */ | 188 | meson_parm_write(clk->map, &pll->od3, pllt->od3); |
250 | if (pll->params.clear_reset_for_lock) { | 189 | |
251 | reg = readl(pll->base + p->reg_off); | 190 | if (MESON_PARM_APPLICABLE(&pll->frac)) |
252 | writel(reg & ~MESON_PLL_RESET, pll->base + p->reg_off); | 191 | meson_parm_write(clk->map, &pll->frac, pllt->frac); |
253 | } | 192 | |
193 | /* make sure the reset is cleared at this point */ | ||
194 | meson_parm_write(clk->map, &pll->rst, 0); | ||
254 | 195 | ||
255 | /* If reset_lock_loop, use a special loop including resetting */ | 196 | if (meson_clk_pll_wait_lock(hw)) { |
256 | if (pll->params.reset_lock_loop) | ||
257 | ret = meson_clk_pll_wait_lock_reset(pll, p); | ||
258 | else | ||
259 | ret = meson_clk_pll_wait_lock(pll, p); | ||
260 | if (ret) { | ||
261 | pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", | 197 | pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", |
262 | __func__, old_rate); | 198 | __func__, old_rate); |
199 | /* | ||
200 | * FIXME: Do we really need/want this HACK ? | ||
201 | * It looks unsafe. what happens if the clock gets into a | ||
202 | * broken state and we can't lock back on the old_rate ? Looks | ||
203 | * like an infinite recursion is possible | ||
204 | */ | ||
263 | meson_clk_pll_set_rate(hw, old_rate, parent_rate); | 205 | meson_clk_pll_set_rate(hw, old_rate, parent_rate); |
264 | } | 206 | } |
265 | 207 | ||
266 | return ret; | 208 | return 0; |
267 | } | 209 | } |
268 | 210 | ||
269 | const struct clk_ops meson_clk_pll_ops = { | 211 | const struct clk_ops meson_clk_pll_ops = { |
212 | .init = meson_clk_pll_init, | ||
270 | .recalc_rate = meson_clk_pll_recalc_rate, | 213 | .recalc_rate = meson_clk_pll_recalc_rate, |
271 | .round_rate = meson_clk_pll_round_rate, | 214 | .round_rate = meson_clk_pll_round_rate, |
272 | .set_rate = meson_clk_pll_set_rate, | 215 | .set_rate = meson_clk_pll_set_rate, |
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index a4a526cbca4c..f0d70eaffcf3 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h | |||
@@ -82,41 +82,21 @@ struct pll_rate_table { | |||
82 | .frac = (_frac), \ | 82 | .frac = (_frac), \ |
83 | } \ | 83 | } \ |
84 | 84 | ||
85 | struct pll_params_table { | 85 | #define CLK_MESON_PLL_LOCK_LOOP_RST BIT(0) |
86 | unsigned int reg_off; | ||
87 | unsigned int value; | ||
88 | }; | ||
89 | |||
90 | #define PLL_PARAM(_reg, _val) \ | ||
91 | { \ | ||
92 | .reg_off = (_reg), \ | ||
93 | .value = (_val), \ | ||
94 | } | ||
95 | |||
96 | struct pll_setup_params { | ||
97 | struct pll_params_table *params_table; | ||
98 | unsigned int params_count; | ||
99 | /* Workaround for GP0, do not reset before configuring */ | ||
100 | bool no_init_reset; | ||
101 | /* Workaround for GP0, unreset right before checking for lock */ | ||
102 | bool clear_reset_for_lock; | ||
103 | /* Workaround for GXL GP0, reset in the lock checking loop */ | ||
104 | bool reset_lock_loop; | ||
105 | }; | ||
106 | 86 | ||
107 | struct meson_clk_pll { | 87 | struct meson_clk_pll_data { |
108 | struct clk_hw hw; | ||
109 | void __iomem *base; | ||
110 | struct parm m; | 88 | struct parm m; |
111 | struct parm n; | 89 | struct parm n; |
112 | struct parm frac; | 90 | struct parm frac; |
113 | struct parm od; | 91 | struct parm od; |
114 | struct parm od2; | 92 | struct parm od2; |
115 | struct parm od3; | 93 | struct parm od3; |
116 | const struct pll_setup_params params; | 94 | struct parm l; |
117 | const struct pll_rate_table *rate_table; | 95 | struct parm rst; |
118 | unsigned int rate_count; | 96 | const struct reg_sequence *init_regs; |
119 | spinlock_t *lock; | 97 | unsigned int init_count; |
98 | const struct pll_rate_table *table; | ||
99 | u8 flags; | ||
120 | }; | 100 | }; |
121 | 101 | ||
122 | #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) | 102 | #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) |
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 196557f11608..49f5716ce8b6 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c | |||
@@ -188,28 +188,39 @@ static const struct pll_rate_table gxl_gp0_pll_rate_table[] = { | |||
188 | { /* sentinel */ }, | 188 | { /* sentinel */ }, |
189 | }; | 189 | }; |
190 | 190 | ||
191 | static struct meson_clk_pll gxbb_fixed_pll = { | 191 | static struct clk_regmap gxbb_fixed_pll = { |
192 | .m = { | 192 | .data = &(struct meson_clk_pll_data){ |
193 | .reg_off = HHI_MPLL_CNTL, | 193 | .m = { |
194 | .shift = 0, | 194 | .reg_off = HHI_MPLL_CNTL, |
195 | .width = 9, | 195 | .shift = 0, |
196 | }, | 196 | .width = 9, |
197 | .n = { | 197 | }, |
198 | .reg_off = HHI_MPLL_CNTL, | 198 | .n = { |
199 | .shift = 9, | 199 | .reg_off = HHI_MPLL_CNTL, |
200 | .width = 5, | 200 | .shift = 9, |
201 | }, | 201 | .width = 5, |
202 | .od = { | 202 | }, |
203 | .reg_off = HHI_MPLL_CNTL, | 203 | .od = { |
204 | .shift = 16, | 204 | .reg_off = HHI_MPLL_CNTL, |
205 | .width = 2, | 205 | .shift = 16, |
206 | }, | 206 | .width = 2, |
207 | .frac = { | 207 | }, |
208 | .reg_off = HHI_MPLL_CNTL2, | 208 | .frac = { |
209 | .shift = 0, | 209 | .reg_off = HHI_MPLL_CNTL2, |
210 | .width = 12, | 210 | .shift = 0, |
211 | }, | 211 | .width = 12, |
212 | .lock = &meson_clk_lock, | 212 | }, |
213 | .l = { | ||
214 | .reg_off = HHI_MPLL_CNTL, | ||
215 | .shift = 31, | ||
216 | .width = 1, | ||
217 | }, | ||
218 | .rst = { | ||
219 | .reg_off = HHI_MPLL_CNTL, | ||
220 | .shift = 29, | ||
221 | .width = 1, | ||
222 | }, | ||
223 | }, | ||
213 | .hw.init = &(struct clk_init_data){ | 224 | .hw.init = &(struct clk_init_data){ |
214 | .name = "fixed_pll", | 225 | .name = "fixed_pll", |
215 | .ops = &meson_clk_pll_ro_ops, | 226 | .ops = &meson_clk_pll_ro_ops, |
@@ -230,38 +241,49 @@ static struct clk_fixed_factor gxbb_hdmi_pll_pre_mult = { | |||
230 | }, | 241 | }, |
231 | }; | 242 | }; |
232 | 243 | ||
233 | static struct meson_clk_pll gxbb_hdmi_pll = { | 244 | static struct clk_regmap gxbb_hdmi_pll = { |
234 | .m = { | 245 | .data = &(struct meson_clk_pll_data){ |
235 | .reg_off = HHI_HDMI_PLL_CNTL, | 246 | .m = { |
236 | .shift = 0, | 247 | .reg_off = HHI_HDMI_PLL_CNTL, |
237 | .width = 9, | 248 | .shift = 0, |
238 | }, | 249 | .width = 9, |
239 | .n = { | 250 | }, |
240 | .reg_off = HHI_HDMI_PLL_CNTL, | 251 | .n = { |
241 | .shift = 9, | 252 | .reg_off = HHI_HDMI_PLL_CNTL, |
242 | .width = 5, | 253 | .shift = 9, |
243 | }, | 254 | .width = 5, |
244 | .frac = { | 255 | }, |
245 | .reg_off = HHI_HDMI_PLL_CNTL2, | 256 | .frac = { |
246 | .shift = 0, | 257 | .reg_off = HHI_HDMI_PLL_CNTL2, |
247 | .width = 12, | 258 | .shift = 0, |
248 | }, | 259 | .width = 12, |
249 | .od = { | 260 | }, |
250 | .reg_off = HHI_HDMI_PLL_CNTL2, | 261 | .od = { |
251 | .shift = 16, | 262 | .reg_off = HHI_HDMI_PLL_CNTL2, |
252 | .width = 2, | 263 | .shift = 16, |
253 | }, | 264 | .width = 2, |
254 | .od2 = { | 265 | }, |
255 | .reg_off = HHI_HDMI_PLL_CNTL2, | 266 | .od2 = { |
256 | .shift = 22, | 267 | .reg_off = HHI_HDMI_PLL_CNTL2, |
257 | .width = 2, | 268 | .shift = 22, |
258 | }, | 269 | .width = 2, |
259 | .od3 = { | 270 | }, |
260 | .reg_off = HHI_HDMI_PLL_CNTL2, | 271 | .od3 = { |
261 | .shift = 18, | 272 | .reg_off = HHI_HDMI_PLL_CNTL2, |
262 | .width = 2, | 273 | .shift = 18, |
274 | .width = 2, | ||
275 | }, | ||
276 | .l = { | ||
277 | .reg_off = HHI_HDMI_PLL_CNTL, | ||
278 | .shift = 31, | ||
279 | .width = 1, | ||
280 | }, | ||
281 | .rst = { | ||
282 | .reg_off = HHI_HDMI_PLL_CNTL, | ||
283 | .shift = 28, | ||
284 | .width = 1, | ||
285 | }, | ||
263 | }, | 286 | }, |
264 | .lock = &meson_clk_lock, | ||
265 | .hw.init = &(struct clk_init_data){ | 287 | .hw.init = &(struct clk_init_data){ |
266 | .name = "hdmi_pll", | 288 | .name = "hdmi_pll", |
267 | .ops = &meson_clk_pll_ro_ops, | 289 | .ops = &meson_clk_pll_ro_ops, |
@@ -271,43 +293,55 @@ static struct meson_clk_pll gxbb_hdmi_pll = { | |||
271 | }, | 293 | }, |
272 | }; | 294 | }; |
273 | 295 | ||
274 | static struct meson_clk_pll gxl_hdmi_pll = { | 296 | static struct clk_regmap gxl_hdmi_pll = { |
275 | .m = { | 297 | .data = &(struct meson_clk_pll_data){ |
276 | .reg_off = HHI_HDMI_PLL_CNTL, | 298 | .m = { |
277 | .shift = 0, | 299 | .reg_off = HHI_HDMI_PLL_CNTL, |
278 | .width = 9, | 300 | .shift = 0, |
279 | }, | 301 | .width = 9, |
280 | .n = { | 302 | }, |
281 | .reg_off = HHI_HDMI_PLL_CNTL, | 303 | .n = { |
282 | .shift = 9, | 304 | .reg_off = HHI_HDMI_PLL_CNTL, |
283 | .width = 5, | 305 | .shift = 9, |
306 | .width = 5, | ||
307 | }, | ||
308 | .frac = { | ||
309 | /* | ||
310 | * On gxl, there is a register shift due to | ||
311 | * HHI_HDMI_PLL_CNTL1 which does not exist on gxbb, | ||
312 | * so we compute the register offset based on the PLL | ||
313 | * base to get it right | ||
314 | */ | ||
315 | .reg_off = HHI_HDMI_PLL_CNTL + 4, | ||
316 | .shift = 0, | ||
317 | .width = 12, | ||
318 | }, | ||
319 | .od = { | ||
320 | .reg_off = HHI_HDMI_PLL_CNTL + 8, | ||
321 | .shift = 21, | ||
322 | .width = 2, | ||
323 | }, | ||
324 | .od2 = { | ||
325 | .reg_off = HHI_HDMI_PLL_CNTL + 8, | ||
326 | .shift = 23, | ||
327 | .width = 2, | ||
328 | }, | ||
329 | .od3 = { | ||
330 | .reg_off = HHI_HDMI_PLL_CNTL + 8, | ||
331 | .shift = 19, | ||
332 | .width = 2, | ||
333 | }, | ||
334 | .l = { | ||
335 | .reg_off = HHI_HDMI_PLL_CNTL, | ||
336 | .shift = 31, | ||
337 | .width = 1, | ||
338 | }, | ||
339 | .rst = { | ||
340 | .reg_off = HHI_HDMI_PLL_CNTL, | ||
341 | .shift = 29, | ||
342 | .width = 1, | ||
343 | }, | ||
284 | }, | 344 | }, |
285 | .frac = { | ||
286 | /* | ||
287 | * On gxl, there is a register shift due to HHI_HDMI_PLL_CNTL1 | ||
288 | * which does not exist on gxbb, so we compute the register | ||
289 | * offset based on the PLL base to get it right | ||
290 | */ | ||
291 | .reg_off = HHI_HDMI_PLL_CNTL + 4, | ||
292 | .shift = 0, | ||
293 | .width = 12, | ||
294 | }, | ||
295 | .od = { | ||
296 | .reg_off = HHI_HDMI_PLL_CNTL + 8, | ||
297 | .shift = 21, | ||
298 | .width = 2, | ||
299 | }, | ||
300 | .od2 = { | ||
301 | .reg_off = HHI_HDMI_PLL_CNTL + 8, | ||
302 | .shift = 23, | ||
303 | .width = 2, | ||
304 | }, | ||
305 | .od3 = { | ||
306 | .reg_off = HHI_HDMI_PLL_CNTL + 8, | ||
307 | .shift = 19, | ||
308 | .width = 2, | ||
309 | }, | ||
310 | .lock = &meson_clk_lock, | ||
311 | .hw.init = &(struct clk_init_data){ | 345 | .hw.init = &(struct clk_init_data){ |
312 | .name = "hdmi_pll", | 346 | .name = "hdmi_pll", |
313 | .ops = &meson_clk_pll_ro_ops, | 347 | .ops = &meson_clk_pll_ro_ops, |
@@ -317,23 +351,34 @@ static struct meson_clk_pll gxl_hdmi_pll = { | |||
317 | }, | 351 | }, |
318 | }; | 352 | }; |
319 | 353 | ||
320 | static struct meson_clk_pll gxbb_sys_pll = { | 354 | static struct clk_regmap gxbb_sys_pll = { |
321 | .m = { | 355 | .data = &(struct meson_clk_pll_data){ |
322 | .reg_off = HHI_SYS_PLL_CNTL, | 356 | .m = { |
323 | .shift = 0, | 357 | .reg_off = HHI_SYS_PLL_CNTL, |
324 | .width = 9, | 358 | .shift = 0, |
325 | }, | 359 | .width = 9, |
326 | .n = { | 360 | }, |
327 | .reg_off = HHI_SYS_PLL_CNTL, | 361 | .n = { |
328 | .shift = 9, | 362 | .reg_off = HHI_SYS_PLL_CNTL, |
329 | .width = 5, | 363 | .shift = 9, |
330 | }, | 364 | .width = 5, |
331 | .od = { | 365 | }, |
332 | .reg_off = HHI_SYS_PLL_CNTL, | 366 | .od = { |
333 | .shift = 10, | 367 | .reg_off = HHI_SYS_PLL_CNTL, |
334 | .width = 2, | 368 | .shift = 10, |
369 | .width = 2, | ||
370 | }, | ||
371 | .l = { | ||
372 | .reg_off = HHI_SYS_PLL_CNTL, | ||
373 | .shift = 31, | ||
374 | .width = 1, | ||
375 | }, | ||
376 | .rst = { | ||
377 | .reg_off = HHI_SYS_PLL_CNTL, | ||
378 | .shift = 29, | ||
379 | .width = 1, | ||
380 | }, | ||
335 | }, | 381 | }, |
336 | .lock = &meson_clk_lock, | ||
337 | .hw.init = &(struct clk_init_data){ | 382 | .hw.init = &(struct clk_init_data){ |
338 | .name = "sys_pll", | 383 | .name = "sys_pll", |
339 | .ops = &meson_clk_pll_ro_ops, | 384 | .ops = &meson_clk_pll_ro_ops, |
@@ -343,38 +388,44 @@ static struct meson_clk_pll gxbb_sys_pll = { | |||
343 | }, | 388 | }, |
344 | }; | 389 | }; |
345 | 390 | ||
346 | struct pll_params_table gxbb_gp0_params_table[] = { | 391 | const struct reg_sequence gxbb_gp0_init_regs[] = { |
347 | PLL_PARAM(HHI_GP0_PLL_CNTL, 0x6a000228), | 392 | { .reg = HHI_GP0_PLL_CNTL, .def = 0x6a000228 }, |
348 | PLL_PARAM(HHI_GP0_PLL_CNTL2, 0x69c80000), | 393 | { .reg = HHI_GP0_PLL_CNTL2, .def = 0x69c80000 }, |
349 | PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a5590c4), | 394 | { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a5590c4 }, |
350 | PLL_PARAM(HHI_GP0_PLL_CNTL4, 0x0000500d), | 395 | { .reg = HHI_GP0_PLL_CNTL4, .def = 0x0000500d }, |
351 | }; | 396 | }; |
352 | 397 | ||
353 | static struct meson_clk_pll gxbb_gp0_pll = { | 398 | static struct clk_regmap gxbb_gp0_pll = { |
354 | .m = { | 399 | .data = &(struct meson_clk_pll_data){ |
355 | .reg_off = HHI_GP0_PLL_CNTL, | 400 | .m = { |
356 | .shift = 0, | 401 | .reg_off = HHI_GP0_PLL_CNTL, |
357 | .width = 9, | 402 | .shift = 0, |
358 | }, | 403 | .width = 9, |
359 | .n = { | 404 | }, |
360 | .reg_off = HHI_GP0_PLL_CNTL, | 405 | .n = { |
361 | .shift = 9, | 406 | .reg_off = HHI_GP0_PLL_CNTL, |
362 | .width = 5, | 407 | .shift = 9, |
363 | }, | 408 | .width = 5, |
364 | .od = { | 409 | }, |
365 | .reg_off = HHI_GP0_PLL_CNTL, | 410 | .od = { |
366 | .shift = 16, | 411 | .reg_off = HHI_GP0_PLL_CNTL, |
367 | .width = 2, | 412 | .shift = 16, |
368 | }, | 413 | .width = 2, |
369 | .params = { | 414 | }, |
370 | .params_table = gxbb_gp0_params_table, | 415 | .l = { |
371 | .params_count = ARRAY_SIZE(gxbb_gp0_params_table), | 416 | .reg_off = HHI_GP0_PLL_CNTL, |
372 | .no_init_reset = true, | 417 | .shift = 31, |
373 | .clear_reset_for_lock = true, | 418 | .width = 1, |
419 | }, | ||
420 | .rst = { | ||
421 | .reg_off = HHI_GP0_PLL_CNTL, | ||
422 | .shift = 29, | ||
423 | .width = 1, | ||
424 | }, | ||
425 | .table = gxbb_gp0_pll_rate_table, | ||
426 | .init_regs = gxbb_gp0_init_regs, | ||
427 | .init_count = ARRAY_SIZE(gxbb_gp0_init_regs), | ||
374 | }, | 428 | }, |
375 | .rate_table = gxbb_gp0_pll_rate_table, | ||
376 | .rate_count = ARRAY_SIZE(gxbb_gp0_pll_rate_table), | ||
377 | .lock = &meson_clk_lock, | ||
378 | .hw.init = &(struct clk_init_data){ | 429 | .hw.init = &(struct clk_init_data){ |
379 | .name = "gp0_pll", | 430 | .name = "gp0_pll", |
380 | .ops = &meson_clk_pll_ops, | 431 | .ops = &meson_clk_pll_ops, |
@@ -384,40 +435,47 @@ static struct meson_clk_pll gxbb_gp0_pll = { | |||
384 | }, | 435 | }, |
385 | }; | 436 | }; |
386 | 437 | ||
387 | struct pll_params_table gxl_gp0_params_table[] = { | 438 | const struct reg_sequence gxl_gp0_init_regs[] = { |
388 | PLL_PARAM(HHI_GP0_PLL_CNTL, 0x40010250), | 439 | { .reg = HHI_GP0_PLL_CNTL, .def = 0x40010250 }, |
389 | PLL_PARAM(HHI_GP0_PLL_CNTL1, 0xc084a000), | 440 | { .reg = HHI_GP0_PLL_CNTL1, .def = 0xc084a000 }, |
390 | PLL_PARAM(HHI_GP0_PLL_CNTL2, 0xb75020be), | 441 | { .reg = HHI_GP0_PLL_CNTL2, .def = 0xb75020be }, |
391 | PLL_PARAM(HHI_GP0_PLL_CNTL3, 0x0a59a288), | 442 | { .reg = HHI_GP0_PLL_CNTL3, .def = 0x0a59a288 }, |
392 | PLL_PARAM(HHI_GP0_PLL_CNTL4, 0xc000004d), | 443 | { .reg = HHI_GP0_PLL_CNTL4, .def = 0xc000004d }, |
393 | PLL_PARAM(HHI_GP0_PLL_CNTL5, 0x00078000), | 444 | { .reg = HHI_GP0_PLL_CNTL5, .def = 0x00078000 }, |
394 | }; | 445 | }; |
395 | 446 | ||
396 | static struct meson_clk_pll gxl_gp0_pll = { | 447 | static struct clk_regmap gxl_gp0_pll = { |
397 | .m = { | 448 | .data = &(struct meson_clk_pll_data){ |
398 | .reg_off = HHI_GP0_PLL_CNTL, | 449 | .m = { |
399 | .shift = 0, | 450 | .reg_off = HHI_GP0_PLL_CNTL, |
400 | .width = 9, | 451 | .shift = 0, |
401 | }, | 452 | .width = 9, |
402 | .n = { | 453 | }, |
403 | .reg_off = HHI_GP0_PLL_CNTL, | 454 | .n = { |
404 | .shift = 9, | 455 | .reg_off = HHI_GP0_PLL_CNTL, |
405 | .width = 5, | 456 | .shift = 9, |
406 | }, | 457 | .width = 5, |
407 | .od = { | 458 | }, |
408 | .reg_off = HHI_GP0_PLL_CNTL, | 459 | .od = { |
409 | .shift = 16, | 460 | .reg_off = HHI_GP0_PLL_CNTL, |
410 | .width = 2, | 461 | .shift = 16, |
411 | }, | 462 | .width = 2, |
412 | .params = { | 463 | }, |
413 | .params_table = gxl_gp0_params_table, | 464 | .l = { |
414 | .params_count = ARRAY_SIZE(gxl_gp0_params_table), | 465 | .reg_off = HHI_GP0_PLL_CNTL, |
415 | .no_init_reset = true, | 466 | .shift = 31, |
416 | .reset_lock_loop = true, | 467 | .width = 1, |
468 | }, | ||
469 | .rst = { | ||
470 | .reg_off = HHI_GP0_PLL_CNTL, | ||
471 | .shift = 29, | ||
472 | .width = 1, | ||
473 | }, | ||
474 | .table = gxl_gp0_pll_rate_table, | ||
475 | .init_regs = gxl_gp0_init_regs, | ||
476 | .init_count = ARRAY_SIZE(gxl_gp0_init_regs), | ||
477 | .flags = CLK_MESON_PLL_LOCK_LOOP_RST, | ||
417 | }, | 478 | }, |
418 | .rate_table = gxl_gp0_pll_rate_table, | ||
419 | .rate_count = ARRAY_SIZE(gxl_gp0_pll_rate_table), | ||
420 | .lock = &meson_clk_lock, | ||
421 | .hw.init = &(struct clk_init_data){ | 479 | .hw.init = &(struct clk_init_data){ |
422 | .name = "gp0_pll", | 480 | .name = "gp0_pll", |
423 | .ops = &meson_clk_pll_ops, | 481 | .ops = &meson_clk_pll_ops, |
@@ -1762,20 +1820,14 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { | |||
1762 | .num = NR_CLKS, | 1820 | .num = NR_CLKS, |
1763 | }; | 1821 | }; |
1764 | 1822 | ||
1765 | /* Convenience tables to populate base addresses in .probe */ | 1823 | static struct clk_regmap *const gxbb_clk_regmaps[] = { |
1766 | |||
1767 | static struct meson_clk_pll *const gxbb_clk_plls[] = { | ||
1768 | &gxbb_fixed_pll, | ||
1769 | &gxbb_hdmi_pll, | ||
1770 | &gxbb_sys_pll, | ||
1771 | &gxbb_gp0_pll, | 1824 | &gxbb_gp0_pll, |
1825 | &gxbb_hdmi_pll, | ||
1772 | }; | 1826 | }; |
1773 | 1827 | ||
1774 | static struct meson_clk_pll *const gxl_clk_plls[] = { | 1828 | static struct clk_regmap *const gxl_clk_regmaps[] = { |
1775 | &gxbb_fixed_pll, | ||
1776 | &gxl_hdmi_pll, | ||
1777 | &gxbb_sys_pll, | ||
1778 | &gxl_gp0_pll, | 1829 | &gxl_gp0_pll, |
1830 | &gxl_hdmi_pll, | ||
1779 | }; | 1831 | }; |
1780 | 1832 | ||
1781 | static struct clk_regmap *const gx_clk_regmaps[] = { | 1833 | static struct clk_regmap *const gx_clk_regmaps[] = { |
@@ -1910,23 +1962,25 @@ static struct clk_regmap *const gx_clk_regmaps[] = { | |||
1910 | &gxbb_mpll1, | 1962 | &gxbb_mpll1, |
1911 | &gxbb_mpll2, | 1963 | &gxbb_mpll2, |
1912 | &gxbb_cts_amclk_div, | 1964 | &gxbb_cts_amclk_div, |
1965 | &gxbb_fixed_pll, | ||
1966 | &gxbb_sys_pll, | ||
1913 | }; | 1967 | }; |
1914 | 1968 | ||
1915 | struct clkc_data { | 1969 | struct clkc_data { |
1916 | struct meson_clk_pll *const *clk_plls; | 1970 | struct clk_regmap *const *regmap_clks; |
1917 | unsigned int clk_plls_count; | 1971 | unsigned int regmap_clks_count; |
1918 | struct clk_hw_onecell_data *hw_onecell_data; | 1972 | struct clk_hw_onecell_data *hw_onecell_data; |
1919 | }; | 1973 | }; |
1920 | 1974 | ||
1921 | static const struct clkc_data gxbb_clkc_data = { | 1975 | static const struct clkc_data gxbb_clkc_data = { |
1922 | .clk_plls = gxbb_clk_plls, | 1976 | .regmap_clks = gxbb_clk_regmaps, |
1923 | .clk_plls_count = ARRAY_SIZE(gxbb_clk_plls), | 1977 | .regmap_clks_count = ARRAY_SIZE(gxbb_clk_regmaps), |
1924 | .hw_onecell_data = &gxbb_hw_onecell_data, | 1978 | .hw_onecell_data = &gxbb_hw_onecell_data, |
1925 | }; | 1979 | }; |
1926 | 1980 | ||
1927 | static const struct clkc_data gxl_clkc_data = { | 1981 | static const struct clkc_data gxl_clkc_data = { |
1928 | .clk_plls = gxl_clk_plls, | 1982 | .regmap_clks = gxl_clk_regmaps, |
1929 | .clk_plls_count = ARRAY_SIZE(gxl_clk_plls), | 1983 | .regmap_clks_count = ARRAY_SIZE(gxl_clk_regmaps), |
1930 | .hw_onecell_data = &gxl_hw_onecell_data, | 1984 | .hw_onecell_data = &gxl_hw_onecell_data, |
1931 | }; | 1985 | }; |
1932 | 1986 | ||
@@ -1969,14 +2023,14 @@ static int gxbb_clkc_probe(struct platform_device *pdev) | |||
1969 | if (IS_ERR(map)) | 2023 | if (IS_ERR(map)) |
1970 | return PTR_ERR(map); | 2024 | return PTR_ERR(map); |
1971 | 2025 | ||
1972 | /* Populate base address for PLLs */ | ||
1973 | for (i = 0; i < clkc_data->clk_plls_count; i++) | ||
1974 | clkc_data->clk_plls[i]->base = clk_base; | ||
1975 | |||
1976 | /* Populate regmap for the common regmap backed clocks */ | 2026 | /* Populate regmap for the common regmap backed clocks */ |
1977 | for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) | 2027 | for (i = 0; i < ARRAY_SIZE(gx_clk_regmaps); i++) |
1978 | gx_clk_regmaps[i]->map = map; | 2028 | gx_clk_regmaps[i]->map = map; |
1979 | 2029 | ||
2030 | /* Populate regmap for soc specific clocks */ | ||
2031 | for (i = 0; i < clkc_data->regmap_clks_count; i++) | ||
2032 | clkc_data->regmap_clks[i]->map = map; | ||
2033 | |||
1980 | /* Register all clks */ | 2034 | /* Register all clks */ |
1981 | for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { | 2035 | for (i = 0; i < clkc_data->hw_onecell_data->num; i++) { |
1982 | /* array might be sparse */ | 2036 | /* array might be sparse */ |
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 4bb51c8f3102..4fd8253c54bb 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c | |||
@@ -122,23 +122,34 @@ static struct clk_fixed_rate meson8b_xtal = { | |||
122 | }, | 122 | }, |
123 | }; | 123 | }; |
124 | 124 | ||
125 | static struct meson_clk_pll meson8b_fixed_pll = { | 125 | static struct clk_regmap meson8b_fixed_pll = { |
126 | .m = { | 126 | .data = &(struct meson_clk_pll_data){ |
127 | .reg_off = HHI_MPLL_CNTL, | 127 | .m = { |
128 | .shift = 0, | 128 | .reg_off = HHI_MPLL_CNTL, |
129 | .width = 9, | 129 | .shift = 0, |
130 | }, | 130 | .width = 9, |
131 | .n = { | 131 | }, |
132 | .reg_off = HHI_MPLL_CNTL, | 132 | .n = { |
133 | .shift = 9, | 133 | .reg_off = HHI_MPLL_CNTL, |
134 | .width = 5, | 134 | .shift = 9, |
135 | }, | 135 | .width = 5, |
136 | .od = { | 136 | }, |
137 | .reg_off = HHI_MPLL_CNTL, | 137 | .od = { |
138 | .shift = 16, | 138 | .reg_off = HHI_MPLL_CNTL, |
139 | .width = 2, | 139 | .shift = 16, |
140 | }, | 140 | .width = 2, |
141 | .lock = &meson_clk_lock, | 141 | }, |
142 | .l = { | ||
143 | .reg_off = HHI_MPLL_CNTL, | ||
144 | .shift = 31, | ||
145 | .width = 1, | ||
146 | }, | ||
147 | .rst = { | ||
148 | .reg_off = HHI_MPLL_CNTL, | ||
149 | .shift = 29, | ||
150 | .width = 1, | ||
151 | }, | ||
152 | }, | ||
142 | .hw.init = &(struct clk_init_data){ | 153 | .hw.init = &(struct clk_init_data){ |
143 | .name = "fixed_pll", | 154 | .name = "fixed_pll", |
144 | .ops = &meson_clk_pll_ro_ops, | 155 | .ops = &meson_clk_pll_ro_ops, |
@@ -148,23 +159,34 @@ static struct meson_clk_pll meson8b_fixed_pll = { | |||
148 | }, | 159 | }, |
149 | }; | 160 | }; |
150 | 161 | ||
151 | static struct meson_clk_pll meson8b_vid_pll = { | 162 | static struct clk_regmap meson8b_vid_pll = { |
152 | .m = { | 163 | .data = &(struct meson_clk_pll_data){ |
153 | .reg_off = HHI_VID_PLL_CNTL, | 164 | .m = { |
154 | .shift = 0, | 165 | .reg_off = HHI_VID_PLL_CNTL, |
155 | .width = 9, | 166 | .shift = 0, |
156 | }, | 167 | .width = 9, |
157 | .n = { | 168 | }, |
158 | .reg_off = HHI_VID_PLL_CNTL, | 169 | .n = { |
159 | .shift = 9, | 170 | .reg_off = HHI_VID_PLL_CNTL, |
160 | .width = 5, | 171 | .shift = 9, |
161 | }, | 172 | .width = 5, |
162 | .od = { | 173 | }, |
163 | .reg_off = HHI_VID_PLL_CNTL, | 174 | .od = { |
164 | .shift = 16, | 175 | .reg_off = HHI_VID_PLL_CNTL, |
165 | .width = 2, | 176 | .shift = 16, |
177 | .width = 2, | ||
178 | }, | ||
179 | .l = { | ||
180 | .reg_off = HHI_VID_PLL_CNTL, | ||
181 | .shift = 31, | ||
182 | .width = 1, | ||
183 | }, | ||
184 | .rst = { | ||
185 | .reg_off = HHI_VID_PLL_CNTL, | ||
186 | .shift = 29, | ||
187 | .width = 1, | ||
188 | }, | ||
166 | }, | 189 | }, |
167 | .lock = &meson_clk_lock, | ||
168 | .hw.init = &(struct clk_init_data){ | 190 | .hw.init = &(struct clk_init_data){ |
169 | .name = "vid_pll", | 191 | .name = "vid_pll", |
170 | .ops = &meson_clk_pll_ro_ops, | 192 | .ops = &meson_clk_pll_ro_ops, |
@@ -174,25 +196,35 @@ static struct meson_clk_pll meson8b_vid_pll = { | |||
174 | }, | 196 | }, |
175 | }; | 197 | }; |
176 | 198 | ||
177 | static struct meson_clk_pll meson8b_sys_pll = { | 199 | static struct clk_regmap meson8b_sys_pll = { |
178 | .m = { | 200 | .data = &(struct meson_clk_pll_data){ |
179 | .reg_off = HHI_SYS_PLL_CNTL, | 201 | .m = { |
180 | .shift = 0, | 202 | .reg_off = HHI_SYS_PLL_CNTL, |
181 | .width = 9, | 203 | .shift = 0, |
182 | }, | 204 | .width = 9, |
183 | .n = { | 205 | }, |
184 | .reg_off = HHI_SYS_PLL_CNTL, | 206 | .n = { |
185 | .shift = 9, | 207 | .reg_off = HHI_SYS_PLL_CNTL, |
186 | .width = 5, | 208 | .shift = 9, |
187 | }, | 209 | .width = 5, |
188 | .od = { | 210 | }, |
189 | .reg_off = HHI_SYS_PLL_CNTL, | 211 | .od = { |
190 | .shift = 16, | 212 | .reg_off = HHI_SYS_PLL_CNTL, |
191 | .width = 2, | 213 | .shift = 16, |
192 | }, | 214 | .width = 2, |
193 | .rate_table = sys_pll_rate_table, | 215 | }, |
194 | .rate_count = ARRAY_SIZE(sys_pll_rate_table), | 216 | .l = { |
195 | .lock = &meson_clk_lock, | 217 | .reg_off = HHI_SYS_PLL_CNTL, |
218 | .shift = 31, | ||
219 | .width = 1, | ||
220 | }, | ||
221 | .rst = { | ||
222 | .reg_off = HHI_SYS_PLL_CNTL, | ||
223 | .shift = 29, | ||
224 | .width = 1, | ||
225 | }, | ||
226 | .table = sys_pll_rate_table, | ||
227 | }, | ||
196 | .hw.init = &(struct clk_init_data){ | 228 | .hw.init = &(struct clk_init_data){ |
197 | .name = "sys_pll", | 229 | .name = "sys_pll", |
198 | .ops = &meson_clk_pll_ops, | 230 | .ops = &meson_clk_pll_ops, |
@@ -613,12 +645,6 @@ static struct clk_hw_onecell_data meson8b_hw_onecell_data = { | |||
613 | .num = CLK_NR_CLKS, | 645 | .num = CLK_NR_CLKS, |
614 | }; | 646 | }; |
615 | 647 | ||
616 | static struct meson_clk_pll *const meson8b_clk_plls[] = { | ||
617 | &meson8b_fixed_pll, | ||
618 | &meson8b_vid_pll, | ||
619 | &meson8b_sys_pll, | ||
620 | }; | ||
621 | |||
622 | static struct clk_regmap *const meson8b_clk_regmaps[] = { | 648 | static struct clk_regmap *const meson8b_clk_regmaps[] = { |
623 | &meson8b_clk81, | 649 | &meson8b_clk81, |
624 | &meson8b_ddr, | 650 | &meson8b_ddr, |
@@ -703,6 +729,9 @@ static struct clk_regmap *const meson8b_clk_regmaps[] = { | |||
703 | &meson8b_mpll0, | 729 | &meson8b_mpll0, |
704 | &meson8b_mpll1, | 730 | &meson8b_mpll1, |
705 | &meson8b_mpll2, | 731 | &meson8b_mpll2, |
732 | &meson8b_fixed_pll, | ||
733 | &meson8b_vid_pll, | ||
734 | &meson8b_sys_pll, | ||
706 | }; | 735 | }; |
707 | 736 | ||
708 | static const struct meson8b_clk_reset_line { | 737 | static const struct meson8b_clk_reset_line { |
@@ -825,10 +854,6 @@ static int meson8b_clkc_probe(struct platform_device *pdev) | |||
825 | if (IS_ERR(map)) | 854 | if (IS_ERR(map)) |
826 | return PTR_ERR(map); | 855 | return PTR_ERR(map); |
827 | 856 | ||
828 | /* Populate base address for PLLs */ | ||
829 | for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) | ||
830 | meson8b_clk_plls[i]->base = clk_base; | ||
831 | |||
832 | /* Populate the base address for CPU clk */ | 857 | /* Populate the base address for CPU clk */ |
833 | meson8b_cpu_clk.base = clk_base; | 858 | meson8b_cpu_clk.base = clk_base; |
834 | 859 | ||