diff options
author | Michael Turquette <mturquette@baylibre.com> | 2016-06-22 21:20:12 -0400 |
---|---|---|
committer | Michael Turquette <mturquette@baylibre.com> | 2016-06-22 21:20:12 -0400 |
commit | 367b30502d0717eb063d47112eb154076d479d92 (patch) | |
tree | a91d51c2db9c89ed34da795812a7ba321333c6f3 /drivers/clk | |
parent | b6f4f1f2c6daaf5a7c856c8a6ad0735f09642257 (diff) | |
parent | 738f66d3211d7ae0cd0012ba6457dac9a03bfd6b (diff) |
Merge remote-tracking branch 'clk/clk-s905' into clk-next
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/Kconfig | 1 | ||||
-rw-r--r-- | drivers/clk/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/meson/Kconfig | 19 | ||||
-rw-r--r-- | drivers/clk/meson/Makefile | 5 | ||||
-rw-r--r-- | drivers/clk/meson/clk-cpu.c | 73 | ||||
-rw-r--r-- | drivers/clk/meson/clk-mpll.c | 94 | ||||
-rw-r--r-- | drivers/clk/meson/clk-pll.c | 104 | ||||
-rw-r--r-- | drivers/clk/meson/clkc.c | 249 | ||||
-rw-r--r-- | drivers/clk/meson/clkc.h | 179 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb.c | 954 | ||||
-rw-r--r-- | drivers/clk/meson/gxbb.h | 271 | ||||
-rw-r--r-- | drivers/clk/meson/meson8b-clkc.c | 436 |
12 files changed, 1793 insertions, 594 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 98efbfcdb503..bfaad3d72233 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig | |||
@@ -209,6 +209,7 @@ config COMMON_CLK_OXNAS | |||
209 | 209 | ||
210 | source "drivers/clk/bcm/Kconfig" | 210 | source "drivers/clk/bcm/Kconfig" |
211 | source "drivers/clk/hisilicon/Kconfig" | 211 | source "drivers/clk/hisilicon/Kconfig" |
212 | source "drivers/clk/meson/Kconfig" | ||
212 | source "drivers/clk/mvebu/Kconfig" | 213 | source "drivers/clk/mvebu/Kconfig" |
213 | source "drivers/clk/qcom/Kconfig" | 214 | source "drivers/clk/qcom/Kconfig" |
214 | source "drivers/clk/renesas/Kconfig" | 215 | source "drivers/clk/renesas/Kconfig" |
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index dcc5e698ff6d..af03eb2f6c05 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -65,7 +65,7 @@ ifeq ($(CONFIG_COMMON_CLK), y) | |||
65 | obj-$(CONFIG_ARCH_MMP) += mmp/ | 65 | obj-$(CONFIG_ARCH_MMP) += mmp/ |
66 | endif | 66 | endif |
67 | obj-y += mvebu/ | 67 | obj-y += mvebu/ |
68 | obj-$(CONFIG_ARCH_MESON) += meson/ | 68 | obj-$(CONFIG_COMMON_CLK_AMLOGIC) += meson/ |
69 | obj-$(CONFIG_ARCH_MXS) += mxs/ | 69 | obj-$(CONFIG_ARCH_MXS) += mxs/ |
70 | obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ | 70 | obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ |
71 | obj-$(CONFIG_COMMON_CLK_NXP) += nxp/ | 71 | obj-$(CONFIG_COMMON_CLK_NXP) += nxp/ |
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig new file mode 100644 index 000000000000..19480bcc7046 --- /dev/null +++ b/drivers/clk/meson/Kconfig | |||
@@ -0,0 +1,19 @@ | |||
1 | config COMMON_CLK_AMLOGIC | ||
2 | bool | ||
3 | depends on OF | ||
4 | depends on ARCH_MESON || COMPILE_TEST | ||
5 | |||
6 | config COMMON_CLK_MESON8B | ||
7 | bool | ||
8 | depends on COMMON_CLK_AMLOGIC | ||
9 | help | ||
10 | Support for the clock controller on AmLogic S805 devices, aka | ||
11 | meson8b. Say Y if you want peripherals and CPU frequency scaling to | ||
12 | work. | ||
13 | |||
14 | config COMMON_CLK_GXBB | ||
15 | bool | ||
16 | depends on COMMON_CLK_AMLOGIC | ||
17 | help | ||
18 | Support for the clock controller on AmLogic S905 devices, aka gxbb. | ||
19 | Say Y if you want peripherals and CPU frequency scaling to work. | ||
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 6d45531df9ab..197e40175166 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile | |||
@@ -2,5 +2,6 @@ | |||
2 | # Makefile for Meson specific clk | 2 | # Makefile for Meson specific clk |
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += clkc.o clk-pll.o clk-cpu.o | 5 | obj-$(CONFIG_COMMON_CLK_AMLOGIC) += clk-pll.o clk-cpu.o clk-mpll.o |
6 | obj-y += meson8b-clkc.o | 6 | obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b-clkc.o |
7 | obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o | ||
diff --git a/drivers/clk/meson/clk-cpu.c b/drivers/clk/meson/clk-cpu.c index f7c30ea54ca8..f8b2b7efd016 100644 --- a/drivers/clk/meson/clk-cpu.c +++ b/drivers/clk/meson/clk-cpu.c | |||
@@ -51,13 +51,6 @@ | |||
51 | 51 | ||
52 | #include "clkc.h" | 52 | #include "clkc.h" |
53 | 53 | ||
54 | struct meson_clk_cpu { | ||
55 | struct notifier_block clk_nb; | ||
56 | const struct clk_div_table *div_table; | ||
57 | struct clk_hw hw; | ||
58 | void __iomem *base; | ||
59 | u16 reg_off; | ||
60 | }; | ||
61 | #define to_meson_clk_cpu_hw(_hw) container_of(_hw, struct meson_clk_cpu, hw) | 54 | #define to_meson_clk_cpu_hw(_hw) container_of(_hw, struct meson_clk_cpu, hw) |
62 | #define to_meson_clk_cpu_nb(_nb) container_of(_nb, struct meson_clk_cpu, clk_nb) | 55 | #define to_meson_clk_cpu_nb(_nb) container_of(_nb, struct meson_clk_cpu, clk_nb) |
63 | 56 | ||
@@ -119,6 +112,7 @@ static unsigned long meson_clk_cpu_recalc_rate(struct clk_hw *hw, | |||
119 | return parent_rate / div; | 112 | return parent_rate / div; |
120 | } | 113 | } |
121 | 114 | ||
115 | /* FIXME MUX1 & MUX2 should be struct clk_hw objects */ | ||
122 | static int meson_clk_cpu_pre_rate_change(struct meson_clk_cpu *clk_cpu, | 116 | static int meson_clk_cpu_pre_rate_change(struct meson_clk_cpu *clk_cpu, |
123 | struct clk_notifier_data *ndata) | 117 | struct clk_notifier_data *ndata) |
124 | { | 118 | { |
@@ -140,6 +134,7 @@ static int meson_clk_cpu_pre_rate_change(struct meson_clk_cpu *clk_cpu, | |||
140 | return 0; | 134 | return 0; |
141 | } | 135 | } |
142 | 136 | ||
137 | /* FIXME MUX1 & MUX2 should be struct clk_hw objects */ | ||
143 | static int meson_clk_cpu_post_rate_change(struct meson_clk_cpu *clk_cpu, | 138 | static int meson_clk_cpu_post_rate_change(struct meson_clk_cpu *clk_cpu, |
144 | struct clk_notifier_data *ndata) | 139 | struct clk_notifier_data *ndata) |
145 | { | 140 | { |
@@ -161,7 +156,7 @@ static int meson_clk_cpu_post_rate_change(struct meson_clk_cpu *clk_cpu, | |||
161 | * PLL clock is to be changed. We use the xtal input as temporary parent | 156 | * PLL clock is to be changed. We use the xtal input as temporary parent |
162 | * while the PLL frequency is stabilized. | 157 | * while the PLL frequency is stabilized. |
163 | */ | 158 | */ |
164 | static int meson_clk_cpu_notifier_cb(struct notifier_block *nb, | 159 | int meson_clk_cpu_notifier_cb(struct notifier_block *nb, |
165 | unsigned long event, void *data) | 160 | unsigned long event, void *data) |
166 | { | 161 | { |
167 | struct clk_notifier_data *ndata = data; | 162 | struct clk_notifier_data *ndata = data; |
@@ -176,68 +171,8 @@ static int meson_clk_cpu_notifier_cb(struct notifier_block *nb, | |||
176 | return notifier_from_errno(ret); | 171 | return notifier_from_errno(ret); |
177 | } | 172 | } |
178 | 173 | ||
179 | static const struct clk_ops meson_clk_cpu_ops = { | 174 | const struct clk_ops meson_clk_cpu_ops = { |
180 | .recalc_rate = meson_clk_cpu_recalc_rate, | 175 | .recalc_rate = meson_clk_cpu_recalc_rate, |
181 | .round_rate = meson_clk_cpu_round_rate, | 176 | .round_rate = meson_clk_cpu_round_rate, |
182 | .set_rate = meson_clk_cpu_set_rate, | 177 | .set_rate = meson_clk_cpu_set_rate, |
183 | }; | 178 | }; |
184 | |||
185 | struct clk *meson_clk_register_cpu(const struct clk_conf *clk_conf, | ||
186 | void __iomem *reg_base, | ||
187 | spinlock_t *lock) | ||
188 | { | ||
189 | struct clk *clk; | ||
190 | struct clk *pclk; | ||
191 | struct meson_clk_cpu *clk_cpu; | ||
192 | struct clk_init_data init; | ||
193 | int ret; | ||
194 | |||
195 | clk_cpu = kzalloc(sizeof(*clk_cpu), GFP_KERNEL); | ||
196 | if (!clk_cpu) | ||
197 | return ERR_PTR(-ENOMEM); | ||
198 | |||
199 | clk_cpu->base = reg_base; | ||
200 | clk_cpu->reg_off = clk_conf->reg_off; | ||
201 | clk_cpu->div_table = clk_conf->conf.div_table; | ||
202 | clk_cpu->clk_nb.notifier_call = meson_clk_cpu_notifier_cb; | ||
203 | |||
204 | init.name = clk_conf->clk_name; | ||
205 | init.ops = &meson_clk_cpu_ops; | ||
206 | init.flags = clk_conf->flags | CLK_GET_RATE_NOCACHE; | ||
207 | init.flags |= CLK_SET_RATE_PARENT; | ||
208 | init.parent_names = clk_conf->clks_parent; | ||
209 | init.num_parents = 1; | ||
210 | |||
211 | clk_cpu->hw.init = &init; | ||
212 | |||
213 | pclk = __clk_lookup(clk_conf->clks_parent[0]); | ||
214 | if (!pclk) { | ||
215 | pr_err("%s: could not lookup parent clock %s\n", | ||
216 | __func__, clk_conf->clks_parent[0]); | ||
217 | ret = -EINVAL; | ||
218 | goto free_clk; | ||
219 | } | ||
220 | |||
221 | ret = clk_notifier_register(pclk, &clk_cpu->clk_nb); | ||
222 | if (ret) { | ||
223 | pr_err("%s: failed to register clock notifier for %s\n", | ||
224 | __func__, clk_conf->clk_name); | ||
225 | goto free_clk; | ||
226 | } | ||
227 | |||
228 | clk = clk_register(NULL, &clk_cpu->hw); | ||
229 | if (IS_ERR(clk)) { | ||
230 | ret = PTR_ERR(clk); | ||
231 | goto unregister_clk_nb; | ||
232 | } | ||
233 | |||
234 | return clk; | ||
235 | |||
236 | unregister_clk_nb: | ||
237 | clk_notifier_unregister(pclk, &clk_cpu->clk_nb); | ||
238 | free_clk: | ||
239 | kfree(clk_cpu); | ||
240 | |||
241 | return ERR_PTR(ret); | ||
242 | } | ||
243 | |||
diff --git a/drivers/clk/meson/clk-mpll.c b/drivers/clk/meson/clk-mpll.c new file mode 100644 index 000000000000..03af79005ddb --- /dev/null +++ b/drivers/clk/meson/clk-mpll.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
3 | * redistributing this file, you may do so under either license. | ||
4 | * | ||
5 | * GPL LICENSE SUMMARY | ||
6 | * | ||
7 | * Copyright (c) 2016 AmLogic, Inc. | ||
8 | * Author: Michael Turquette <mturquette@baylibre.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
22 | * The full GNU General Public License is included in this distribution | ||
23 | * in the file called COPYING | ||
24 | * | ||
25 | * BSD LICENSE | ||
26 | * | ||
27 | * Copyright (c) 2016 AmLogic, Inc. | ||
28 | * Author: Michael Turquette <mturquette@baylibre.com> | ||
29 | * | ||
30 | * Redistribution and use in source and binary forms, with or without | ||
31 | * modification, are permitted provided that the following conditions | ||
32 | * are met: | ||
33 | * | ||
34 | * * Redistributions of source code must retain the above copyright | ||
35 | * notice, this list of conditions and the following disclaimer. | ||
36 | * * Redistributions in binary form must reproduce the above copyright | ||
37 | * notice, this list of conditions and the following disclaimer in | ||
38 | * the documentation and/or other materials provided with the | ||
39 | * distribution. | ||
40 | * * Neither the name of Intel Corporation nor the names of its | ||
41 | * contributors may be used to endorse or promote products derived | ||
42 | * from this software without specific prior written permission. | ||
43 | * | ||
44 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
45 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
46 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
47 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
48 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
49 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
50 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
51 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
52 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
53 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
54 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
55 | */ | ||
56 | |||
57 | /* | ||
58 | * MultiPhase Locked Loops are outputs from a PLL with additional frequency | ||
59 | * scaling capabilities. MPLL rates are calculated as: | ||
60 | * | ||
61 | * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384) | ||
62 | */ | ||
63 | |||
64 | #include <linux/clk-provider.h> | ||
65 | #include "clkc.h" | ||
66 | |||
67 | #define SDM_MAX 16384 | ||
68 | |||
69 | #define to_meson_clk_mpll(_hw) container_of(_hw, struct meson_clk_mpll, hw) | ||
70 | |||
71 | static unsigned long mpll_recalc_rate(struct clk_hw *hw, | ||
72 | unsigned long parent_rate) | ||
73 | { | ||
74 | struct meson_clk_mpll *mpll = to_meson_clk_mpll(hw); | ||
75 | struct parm *p; | ||
76 | unsigned long rate = 0; | ||
77 | unsigned long reg, sdm, n2; | ||
78 | |||
79 | p = &mpll->sdm; | ||
80 | reg = readl(mpll->base + p->reg_off); | ||
81 | sdm = PARM_GET(p->width, p->shift, reg); | ||
82 | |||
83 | p = &mpll->n2; | ||
84 | reg = readl(mpll->base + p->reg_off); | ||
85 | n2 = PARM_GET(p->width, p->shift, reg); | ||
86 | |||
87 | rate = (parent_rate * SDM_MAX) / ((SDM_MAX * n2) + sdm); | ||
88 | |||
89 | return rate; | ||
90 | } | ||
91 | |||
92 | const struct clk_ops meson_clk_mpll_ro_ops = { | ||
93 | .recalc_rate = mpll_recalc_rate, | ||
94 | }; | ||
diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 664edf0708ea..4adc1e89212c 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c | |||
@@ -44,13 +44,6 @@ | |||
44 | #define MESON_PLL_RESET BIT(29) | 44 | #define MESON_PLL_RESET BIT(29) |
45 | #define MESON_PLL_LOCK BIT(31) | 45 | #define MESON_PLL_LOCK BIT(31) |
46 | 46 | ||
47 | struct meson_clk_pll { | ||
48 | struct clk_hw hw; | ||
49 | void __iomem *base; | ||
50 | struct pll_conf *conf; | ||
51 | unsigned int rate_count; | ||
52 | spinlock_t *lock; | ||
53 | }; | ||
54 | #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) | 47 | #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) |
55 | 48 | ||
56 | static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, | 49 | static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, |
@@ -60,22 +53,36 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw, | |||
60 | struct parm *p; | 53 | struct parm *p; |
61 | unsigned long parent_rate_mhz = parent_rate / 1000000; | 54 | unsigned long parent_rate_mhz = parent_rate / 1000000; |
62 | unsigned long rate_mhz; | 55 | unsigned long rate_mhz; |
63 | u16 n, m, od; | 56 | u16 n, m, frac = 0, od, od2 = 0; |
64 | u32 reg; | 57 | u32 reg; |
65 | 58 | ||
66 | p = &pll->conf->n; | 59 | p = &pll->n; |
67 | reg = readl(pll->base + p->reg_off); | 60 | reg = readl(pll->base + p->reg_off); |
68 | n = PARM_GET(p->width, p->shift, reg); | 61 | n = PARM_GET(p->width, p->shift, reg); |
69 | 62 | ||
70 | p = &pll->conf->m; | 63 | p = &pll->m; |
71 | reg = readl(pll->base + p->reg_off); | 64 | reg = readl(pll->base + p->reg_off); |
72 | m = PARM_GET(p->width, p->shift, reg); | 65 | m = PARM_GET(p->width, p->shift, reg); |
73 | 66 | ||
74 | p = &pll->conf->od; | 67 | p = &pll->od; |
75 | reg = readl(pll->base + p->reg_off); | 68 | reg = readl(pll->base + p->reg_off); |
76 | od = PARM_GET(p->width, p->shift, reg); | 69 | od = PARM_GET(p->width, p->shift, reg); |
77 | 70 | ||
78 | rate_mhz = (parent_rate_mhz * m / n) >> od; | 71 | p = &pll->od2; |
72 | if (p->width) { | ||
73 | reg = readl(pll->base + p->reg_off); | ||
74 | od2 = PARM_GET(p->width, p->shift, reg); | ||
75 | } | ||
76 | |||
77 | p = &pll->frac; | ||
78 | if (p->width) { | ||
79 | reg = readl(pll->base + p->reg_off); | ||
80 | frac = PARM_GET(p->width, p->shift, reg); | ||
81 | rate_mhz = (parent_rate_mhz * m + \ | ||
82 | (parent_rate_mhz * frac >> 12)) * 2 / n; | ||
83 | rate_mhz = rate_mhz >> od >> od2; | ||
84 | } else | ||
85 | rate_mhz = (parent_rate_mhz * m / n) >> od >> od2; | ||
79 | 86 | ||
80 | return rate_mhz * 1000000; | 87 | return rate_mhz * 1000000; |
81 | } | 88 | } |
@@ -84,7 +91,7 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, | |||
84 | unsigned long *parent_rate) | 91 | unsigned long *parent_rate) |
85 | { | 92 | { |
86 | struct meson_clk_pll *pll = to_meson_clk_pll(hw); | 93 | struct meson_clk_pll *pll = to_meson_clk_pll(hw); |
87 | const struct pll_rate_table *rate_table = pll->conf->rate_table; | 94 | const struct pll_rate_table *rate_table = pll->rate_table; |
88 | int i; | 95 | int i; |
89 | 96 | ||
90 | for (i = 0; i < pll->rate_count; i++) { | 97 | for (i = 0; i < pll->rate_count; i++) { |
@@ -99,7 +106,7 @@ static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, | |||
99 | static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll, | 106 | static const struct pll_rate_table *meson_clk_get_pll_settings(struct meson_clk_pll *pll, |
100 | unsigned long rate) | 107 | unsigned long rate) |
101 | { | 108 | { |
102 | const struct pll_rate_table *rate_table = pll->conf->rate_table; | 109 | const struct pll_rate_table *rate_table = pll->rate_table; |
103 | int i; | 110 | int i; |
104 | 111 | ||
105 | for (i = 0; i < pll->rate_count; i++) { | 112 | for (i = 0; i < pll->rate_count; i++) { |
@@ -145,24 +152,38 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, | |||
145 | return -EINVAL; | 152 | return -EINVAL; |
146 | 153 | ||
147 | /* PLL reset */ | 154 | /* PLL reset */ |
148 | p = &pll->conf->n; | 155 | p = &pll->n; |
149 | reg = readl(pll->base + p->reg_off); | 156 | reg = readl(pll->base + p->reg_off); |
150 | writel(reg | MESON_PLL_RESET, pll->base + p->reg_off); | 157 | writel(reg | MESON_PLL_RESET, pll->base + p->reg_off); |
151 | 158 | ||
152 | reg = PARM_SET(p->width, p->shift, reg, rate_set->n); | 159 | reg = PARM_SET(p->width, p->shift, reg, rate_set->n); |
153 | writel(reg, pll->base + p->reg_off); | 160 | writel(reg, pll->base + p->reg_off); |
154 | 161 | ||
155 | p = &pll->conf->m; | 162 | p = &pll->m; |
156 | reg = readl(pll->base + p->reg_off); | 163 | reg = readl(pll->base + p->reg_off); |
157 | reg = PARM_SET(p->width, p->shift, reg, rate_set->m); | 164 | reg = PARM_SET(p->width, p->shift, reg, rate_set->m); |
158 | writel(reg, pll->base + p->reg_off); | 165 | writel(reg, pll->base + p->reg_off); |
159 | 166 | ||
160 | p = &pll->conf->od; | 167 | p = &pll->od; |
161 | reg = readl(pll->base + p->reg_off); | 168 | reg = readl(pll->base + p->reg_off); |
162 | reg = PARM_SET(p->width, p->shift, reg, rate_set->od); | 169 | reg = PARM_SET(p->width, p->shift, reg, rate_set->od); |
163 | writel(reg, pll->base + p->reg_off); | 170 | writel(reg, pll->base + p->reg_off); |
164 | 171 | ||
165 | p = &pll->conf->n; | 172 | p = &pll->od2; |
173 | if (p->width) { | ||
174 | reg = readl(pll->base + p->reg_off); | ||
175 | reg = PARM_SET(p->width, p->shift, reg, rate_set->od2); | ||
176 | writel(reg, pll->base + p->reg_off); | ||
177 | } | ||
178 | |||
179 | p = &pll->frac; | ||
180 | if (p->width) { | ||
181 | reg = readl(pll->base + p->reg_off); | ||
182 | reg = PARM_SET(p->width, p->shift, reg, rate_set->frac); | ||
183 | writel(reg, pll->base + p->reg_off); | ||
184 | } | ||
185 | |||
186 | p = &pll->n; | ||
166 | ret = meson_clk_pll_wait_lock(pll, p); | 187 | ret = meson_clk_pll_wait_lock(pll, p); |
167 | if (ret) { | 188 | if (ret) { |
168 | pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", | 189 | pr_warn("%s: pll did not lock, trying to restore old rate %lu\n", |
@@ -173,55 +194,12 @@ static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, | |||
173 | return ret; | 194 | return ret; |
174 | } | 195 | } |
175 | 196 | ||
176 | static const struct clk_ops meson_clk_pll_ops = { | 197 | const struct clk_ops meson_clk_pll_ops = { |
177 | .recalc_rate = meson_clk_pll_recalc_rate, | 198 | .recalc_rate = meson_clk_pll_recalc_rate, |
178 | .round_rate = meson_clk_pll_round_rate, | 199 | .round_rate = meson_clk_pll_round_rate, |
179 | .set_rate = meson_clk_pll_set_rate, | 200 | .set_rate = meson_clk_pll_set_rate, |
180 | }; | 201 | }; |
181 | 202 | ||
182 | static const struct clk_ops meson_clk_pll_ro_ops = { | 203 | const struct clk_ops meson_clk_pll_ro_ops = { |
183 | .recalc_rate = meson_clk_pll_recalc_rate, | 204 | .recalc_rate = meson_clk_pll_recalc_rate, |
184 | }; | 205 | }; |
185 | |||
186 | struct clk *meson_clk_register_pll(const struct clk_conf *clk_conf, | ||
187 | void __iomem *reg_base, | ||
188 | spinlock_t *lock) | ||
189 | { | ||
190 | struct clk *clk; | ||
191 | struct meson_clk_pll *clk_pll; | ||
192 | struct clk_init_data init; | ||
193 | |||
194 | clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL); | ||
195 | if (!clk_pll) | ||
196 | return ERR_PTR(-ENOMEM); | ||
197 | |||
198 | clk_pll->base = reg_base + clk_conf->reg_off; | ||
199 | clk_pll->lock = lock; | ||
200 | clk_pll->conf = clk_conf->conf.pll; | ||
201 | |||
202 | init.name = clk_conf->clk_name; | ||
203 | init.flags = clk_conf->flags | CLK_GET_RATE_NOCACHE; | ||
204 | |||
205 | init.parent_names = &clk_conf->clks_parent[0]; | ||
206 | init.num_parents = 1; | ||
207 | init.ops = &meson_clk_pll_ro_ops; | ||
208 | |||
209 | /* If no rate_table is specified we assume the PLL is read-only */ | ||
210 | if (clk_pll->conf->rate_table) { | ||
211 | int len; | ||
212 | |||
213 | for (len = 0; clk_pll->conf->rate_table[len].rate != 0; ) | ||
214 | len++; | ||
215 | |||
216 | clk_pll->rate_count = len; | ||
217 | init.ops = &meson_clk_pll_ops; | ||
218 | } | ||
219 | |||
220 | clk_pll->hw.init = &init; | ||
221 | |||
222 | clk = clk_register(NULL, &clk_pll->hw); | ||
223 | if (IS_ERR(clk)) | ||
224 | kfree(clk_pll); | ||
225 | |||
226 | return clk; | ||
227 | } | ||
diff --git a/drivers/clk/meson/clkc.c b/drivers/clk/meson/clkc.c deleted file mode 100644 index d920d410b51d..000000000000 --- a/drivers/clk/meson/clkc.c +++ /dev/null | |||
@@ -1,249 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015 Endless Mobile, Inc. | ||
3 | * Author: Carlo Caione <carlo@endlessm.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <linux/clk-provider.h> | ||
19 | #include <linux/mfd/syscon.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include "clkc.h" | ||
23 | |||
24 | static DEFINE_SPINLOCK(clk_lock); | ||
25 | |||
26 | static struct clk **clks; | ||
27 | static struct clk_onecell_data clk_data; | ||
28 | |||
29 | struct clk ** __init meson_clk_init(struct device_node *np, | ||
30 | unsigned long nr_clks) | ||
31 | { | ||
32 | clks = kcalloc(nr_clks, sizeof(*clks), GFP_KERNEL); | ||
33 | if (!clks) | ||
34 | return ERR_PTR(-ENOMEM); | ||
35 | |||
36 | clk_data.clks = clks; | ||
37 | clk_data.clk_num = nr_clks; | ||
38 | of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | ||
39 | |||
40 | return clks; | ||
41 | } | ||
42 | |||
43 | static void meson_clk_add_lookup(struct clk *clk, unsigned int id) | ||
44 | { | ||
45 | if (clks && id) | ||
46 | clks[id] = clk; | ||
47 | } | ||
48 | |||
49 | static struct clk * __init | ||
50 | meson_clk_register_composite(const struct clk_conf *clk_conf, | ||
51 | void __iomem *clk_base) | ||
52 | { | ||
53 | struct clk *clk; | ||
54 | struct clk_mux *mux = NULL; | ||
55 | struct clk_divider *div = NULL; | ||
56 | struct clk_gate *gate = NULL; | ||
57 | const struct clk_ops *mux_ops = NULL; | ||
58 | const struct composite_conf *composite_conf; | ||
59 | |||
60 | composite_conf = clk_conf->conf.composite; | ||
61 | |||
62 | if (clk_conf->num_parents > 1) { | ||
63 | mux = kzalloc(sizeof(*mux), GFP_KERNEL); | ||
64 | if (!mux) | ||
65 | return ERR_PTR(-ENOMEM); | ||
66 | |||
67 | mux->reg = clk_base + clk_conf->reg_off | ||
68 | + composite_conf->mux_parm.reg_off; | ||
69 | mux->shift = composite_conf->mux_parm.shift; | ||
70 | mux->mask = BIT(composite_conf->mux_parm.width) - 1; | ||
71 | mux->flags = composite_conf->mux_flags; | ||
72 | mux->lock = &clk_lock; | ||
73 | mux->table = composite_conf->mux_table; | ||
74 | mux_ops = (composite_conf->mux_flags & CLK_MUX_READ_ONLY) ? | ||
75 | &clk_mux_ro_ops : &clk_mux_ops; | ||
76 | } | ||
77 | |||
78 | if (MESON_PARM_APPLICABLE(&composite_conf->div_parm)) { | ||
79 | div = kzalloc(sizeof(*div), GFP_KERNEL); | ||
80 | if (!div) { | ||
81 | clk = ERR_PTR(-ENOMEM); | ||
82 | goto error; | ||
83 | } | ||
84 | |||
85 | div->reg = clk_base + clk_conf->reg_off | ||
86 | + composite_conf->div_parm.reg_off; | ||
87 | div->shift = composite_conf->div_parm.shift; | ||
88 | div->width = composite_conf->div_parm.width; | ||
89 | div->lock = &clk_lock; | ||
90 | div->flags = composite_conf->div_flags; | ||
91 | div->table = composite_conf->div_table; | ||
92 | } | ||
93 | |||
94 | if (MESON_PARM_APPLICABLE(&composite_conf->gate_parm)) { | ||
95 | gate = kzalloc(sizeof(*gate), GFP_KERNEL); | ||
96 | if (!gate) { | ||
97 | clk = ERR_PTR(-ENOMEM); | ||
98 | goto error; | ||
99 | } | ||
100 | |||
101 | gate->reg = clk_base + clk_conf->reg_off | ||
102 | + composite_conf->div_parm.reg_off; | ||
103 | gate->bit_idx = composite_conf->gate_parm.shift; | ||
104 | gate->flags = composite_conf->gate_flags; | ||
105 | gate->lock = &clk_lock; | ||
106 | } | ||
107 | |||
108 | clk = clk_register_composite(NULL, clk_conf->clk_name, | ||
109 | clk_conf->clks_parent, | ||
110 | clk_conf->num_parents, | ||
111 | mux ? &mux->hw : NULL, mux_ops, | ||
112 | div ? &div->hw : NULL, &clk_divider_ops, | ||
113 | gate ? &gate->hw : NULL, &clk_gate_ops, | ||
114 | clk_conf->flags); | ||
115 | if (IS_ERR(clk)) | ||
116 | goto error; | ||
117 | |||
118 | return clk; | ||
119 | |||
120 | error: | ||
121 | kfree(gate); | ||
122 | kfree(div); | ||
123 | kfree(mux); | ||
124 | |||
125 | return clk; | ||
126 | } | ||
127 | |||
128 | static struct clk * __init | ||
129 | meson_clk_register_fixed_factor(const struct clk_conf *clk_conf, | ||
130 | void __iomem *clk_base) | ||
131 | { | ||
132 | struct clk *clk; | ||
133 | const struct fixed_fact_conf *fixed_fact_conf; | ||
134 | const struct parm *p; | ||
135 | unsigned int mult, div; | ||
136 | u32 reg; | ||
137 | |||
138 | fixed_fact_conf = &clk_conf->conf.fixed_fact; | ||
139 | |||
140 | mult = clk_conf->conf.fixed_fact.mult; | ||
141 | div = clk_conf->conf.fixed_fact.div; | ||
142 | |||
143 | if (!mult) { | ||
144 | mult = 1; | ||
145 | p = &fixed_fact_conf->mult_parm; | ||
146 | if (MESON_PARM_APPLICABLE(p)) { | ||
147 | reg = readl(clk_base + clk_conf->reg_off + p->reg_off); | ||
148 | mult = PARM_GET(p->width, p->shift, reg); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | if (!div) { | ||
153 | div = 1; | ||
154 | p = &fixed_fact_conf->div_parm; | ||
155 | if (MESON_PARM_APPLICABLE(p)) { | ||
156 | reg = readl(clk_base + clk_conf->reg_off + p->reg_off); | ||
157 | mult = PARM_GET(p->width, p->shift, reg); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | clk = clk_register_fixed_factor(NULL, | ||
162 | clk_conf->clk_name, | ||
163 | clk_conf->clks_parent[0], | ||
164 | clk_conf->flags, | ||
165 | mult, div); | ||
166 | |||
167 | return clk; | ||
168 | } | ||
169 | |||
170 | static struct clk * __init | ||
171 | meson_clk_register_fixed_rate(const struct clk_conf *clk_conf, | ||
172 | void __iomem *clk_base) | ||
173 | { | ||
174 | struct clk *clk; | ||
175 | const struct fixed_rate_conf *fixed_rate_conf; | ||
176 | const struct parm *r; | ||
177 | unsigned long rate; | ||
178 | u32 reg; | ||
179 | |||
180 | fixed_rate_conf = &clk_conf->conf.fixed_rate; | ||
181 | rate = fixed_rate_conf->rate; | ||
182 | |||
183 | if (!rate) { | ||
184 | r = &fixed_rate_conf->rate_parm; | ||
185 | reg = readl(clk_base + clk_conf->reg_off + r->reg_off); | ||
186 | rate = PARM_GET(r->width, r->shift, reg); | ||
187 | } | ||
188 | |||
189 | rate *= 1000000; | ||
190 | |||
191 | clk = clk_register_fixed_rate(NULL, | ||
192 | clk_conf->clk_name, | ||
193 | clk_conf->num_parents | ||
194 | ? clk_conf->clks_parent[0] : NULL, | ||
195 | clk_conf->flags, rate); | ||
196 | |||
197 | return clk; | ||
198 | } | ||
199 | |||
200 | void __init meson_clk_register_clks(const struct clk_conf *clk_confs, | ||
201 | unsigned int nr_confs, | ||
202 | void __iomem *clk_base) | ||
203 | { | ||
204 | unsigned int i; | ||
205 | struct clk *clk = NULL; | ||
206 | |||
207 | for (i = 0; i < nr_confs; i++) { | ||
208 | const struct clk_conf *clk_conf = &clk_confs[i]; | ||
209 | |||
210 | switch (clk_conf->clk_type) { | ||
211 | case CLK_FIXED_RATE: | ||
212 | clk = meson_clk_register_fixed_rate(clk_conf, | ||
213 | clk_base); | ||
214 | break; | ||
215 | case CLK_FIXED_FACTOR: | ||
216 | clk = meson_clk_register_fixed_factor(clk_conf, | ||
217 | clk_base); | ||
218 | break; | ||
219 | case CLK_COMPOSITE: | ||
220 | clk = meson_clk_register_composite(clk_conf, | ||
221 | clk_base); | ||
222 | break; | ||
223 | case CLK_CPU: | ||
224 | clk = meson_clk_register_cpu(clk_conf, clk_base, | ||
225 | &clk_lock); | ||
226 | break; | ||
227 | case CLK_PLL: | ||
228 | clk = meson_clk_register_pll(clk_conf, clk_base, | ||
229 | &clk_lock); | ||
230 | break; | ||
231 | default: | ||
232 | clk = NULL; | ||
233 | } | ||
234 | |||
235 | if (!clk) { | ||
236 | pr_err("%s: unknown clock type %d\n", __func__, | ||
237 | clk_conf->clk_type); | ||
238 | continue; | ||
239 | } | ||
240 | |||
241 | if (IS_ERR(clk)) { | ||
242 | pr_warn("%s: Unable to create %s clock\n", __func__, | ||
243 | clk_conf->clk_name); | ||
244 | continue; | ||
245 | } | ||
246 | |||
247 | meson_clk_add_lookup(clk, clk_conf->clk_id); | ||
248 | } | ||
249 | } | ||
diff --git a/drivers/clk/meson/clkc.h b/drivers/clk/meson/clkc.h index 609ae92cc13f..53326c32e853 100644 --- a/drivers/clk/meson/clkc.h +++ b/drivers/clk/meson/clkc.h | |||
@@ -34,19 +34,16 @@ struct parm { | |||
34 | u8 shift; | 34 | u8 shift; |
35 | u8 width; | 35 | u8 width; |
36 | }; | 36 | }; |
37 | #define PARM(_r, _s, _w) \ | ||
38 | { \ | ||
39 | .reg_off = (_r), \ | ||
40 | .shift = (_s), \ | ||
41 | .width = (_w), \ | ||
42 | } \ | ||
43 | 37 | ||
44 | struct pll_rate_table { | 38 | struct pll_rate_table { |
45 | unsigned long rate; | 39 | unsigned long rate; |
46 | u16 m; | 40 | u16 m; |
47 | u16 n; | 41 | u16 n; |
48 | u16 od; | 42 | u16 od; |
43 | u16 od2; | ||
44 | u16 frac; | ||
49 | }; | 45 | }; |
46 | |||
50 | #define PLL_RATE(_r, _m, _n, _od) \ | 47 | #define PLL_RATE(_r, _m, _n, _od) \ |
51 | { \ | 48 | { \ |
52 | .rate = (_r), \ | 49 | .rate = (_r), \ |
@@ -55,133 +52,69 @@ struct pll_rate_table { | |||
55 | .od = (_od), \ | 52 | .od = (_od), \ |
56 | } \ | 53 | } \ |
57 | 54 | ||
58 | struct pll_conf { | 55 | #define PLL_FRAC_RATE(_r, _m, _n, _od, _od2, _frac) \ |
59 | const struct pll_rate_table *rate_table; | 56 | { \ |
60 | struct parm m; | 57 | .rate = (_r), \ |
61 | struct parm n; | 58 | .m = (_m), \ |
62 | struct parm od; | 59 | .n = (_n), \ |
63 | }; | 60 | .od = (_od), \ |
61 | .od2 = (_od2), \ | ||
62 | .frac = (_frac), \ | ||
63 | } \ | ||
64 | 64 | ||
65 | struct fixed_fact_conf { | 65 | struct meson_clk_pll { |
66 | unsigned int div; | 66 | struct clk_hw hw; |
67 | unsigned int mult; | 67 | void __iomem *base; |
68 | struct parm div_parm; | 68 | struct parm m; |
69 | struct parm mult_parm; | 69 | struct parm n; |
70 | struct parm frac; | ||
71 | struct parm od; | ||
72 | struct parm od2; | ||
73 | const struct pll_rate_table *rate_table; | ||
74 | unsigned int rate_count; | ||
75 | spinlock_t *lock; | ||
70 | }; | 76 | }; |
71 | 77 | ||
72 | struct fixed_rate_conf { | 78 | #define to_meson_clk_pll(_hw) container_of(_hw, struct meson_clk_pll, hw) |
73 | unsigned long rate; | ||
74 | struct parm rate_parm; | ||
75 | }; | ||
76 | 79 | ||
77 | struct composite_conf { | 80 | struct meson_clk_cpu { |
78 | struct parm mux_parm; | 81 | struct clk_hw hw; |
79 | struct parm div_parm; | 82 | void __iomem *base; |
80 | struct parm gate_parm; | 83 | u16 reg_off; |
81 | struct clk_div_table *div_table; | 84 | struct notifier_block clk_nb; |
82 | u32 *mux_table; | 85 | const struct clk_div_table *div_table; |
83 | u8 mux_flags; | ||
84 | u8 div_flags; | ||
85 | u8 gate_flags; | ||
86 | }; | 86 | }; |
87 | 87 | ||
88 | #define PNAME(x) static const char *x[] | 88 | int meson_clk_cpu_notifier_cb(struct notifier_block *nb, unsigned long event, |
89 | void *data); | ||
89 | 90 | ||
90 | enum clk_type { | 91 | struct meson_clk_mpll { |
91 | CLK_FIXED_FACTOR, | 92 | struct clk_hw hw; |
92 | CLK_FIXED_RATE, | 93 | void __iomem *base; |
93 | CLK_COMPOSITE, | 94 | struct parm sdm; |
94 | CLK_CPU, | 95 | struct parm n2; |
95 | CLK_PLL, | 96 | /* FIXME ssen gate control? */ |
97 | spinlock_t *lock; | ||
96 | }; | 98 | }; |
97 | 99 | ||
98 | struct clk_conf { | 100 | #define MESON_GATE(_name, _reg, _bit) \ |
99 | u16 reg_off; | 101 | struct clk_gate gxbb_##_name = { \ |
100 | enum clk_type clk_type; | 102 | .reg = (void __iomem *) _reg, \ |
101 | unsigned int clk_id; | 103 | .bit_idx = (_bit), \ |
102 | const char *clk_name; | 104 | .lock = &clk_lock, \ |
103 | const char **clks_parent; | 105 | .hw.init = &(struct clk_init_data) { \ |
104 | int num_parents; | 106 | .name = #_name, \ |
105 | unsigned long flags; | 107 | .ops = &clk_gate_ops, \ |
106 | union { | 108 | .parent_names = (const char *[]){ "clk81" }, \ |
107 | struct fixed_fact_conf fixed_fact; | 109 | .num_parents = 1, \ |
108 | struct fixed_rate_conf fixed_rate; | 110 | .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), \ |
109 | const struct composite_conf *composite; | 111 | }, \ |
110 | struct pll_conf *pll; | ||
111 | const struct clk_div_table *div_table; | ||
112 | } conf; | ||
113 | }; | 112 | }; |
114 | 113 | ||
115 | #define FIXED_RATE_P(_ro, _ci, _cn, _f, _c) \ | 114 | /* clk_ops */ |
116 | { \ | 115 | extern const struct clk_ops meson_clk_pll_ro_ops; |
117 | .reg_off = (_ro), \ | 116 | extern const struct clk_ops meson_clk_pll_ops; |
118 | .clk_type = CLK_FIXED_RATE, \ | 117 | extern const struct clk_ops meson_clk_cpu_ops; |
119 | .clk_id = (_ci), \ | 118 | extern const struct clk_ops meson_clk_mpll_ro_ops; |
120 | .clk_name = (_cn), \ | ||
121 | .flags = (_f), \ | ||
122 | .conf.fixed_rate.rate_parm = _c, \ | ||
123 | } \ | ||
124 | |||
125 | #define FIXED_RATE(_ci, _cn, _f, _r) \ | ||
126 | { \ | ||
127 | .clk_type = CLK_FIXED_RATE, \ | ||
128 | .clk_id = (_ci), \ | ||
129 | .clk_name = (_cn), \ | ||
130 | .flags = (_f), \ | ||
131 | .conf.fixed_rate.rate = (_r), \ | ||
132 | } \ | ||
133 | |||
134 | #define PLL(_ro, _ci, _cn, _cp, _f, _c) \ | ||
135 | { \ | ||
136 | .reg_off = (_ro), \ | ||
137 | .clk_type = CLK_PLL, \ | ||
138 | .clk_id = (_ci), \ | ||
139 | .clk_name = (_cn), \ | ||
140 | .clks_parent = (_cp), \ | ||
141 | .num_parents = ARRAY_SIZE(_cp), \ | ||
142 | .flags = (_f), \ | ||
143 | .conf.pll = (_c), \ | ||
144 | } \ | ||
145 | |||
146 | #define FIXED_FACTOR_DIV(_ci, _cn, _cp, _f, _d) \ | ||
147 | { \ | ||
148 | .clk_type = CLK_FIXED_FACTOR, \ | ||
149 | .clk_id = (_ci), \ | ||
150 | .clk_name = (_cn), \ | ||
151 | .clks_parent = (_cp), \ | ||
152 | .num_parents = ARRAY_SIZE(_cp), \ | ||
153 | .conf.fixed_fact.div = (_d), \ | ||
154 | } \ | ||
155 | |||
156 | #define CPU(_ro, _ci, _cn, _cp, _dt) \ | ||
157 | { \ | ||
158 | .reg_off = (_ro), \ | ||
159 | .clk_type = CLK_CPU, \ | ||
160 | .clk_id = (_ci), \ | ||
161 | .clk_name = (_cn), \ | ||
162 | .clks_parent = (_cp), \ | ||
163 | .num_parents = ARRAY_SIZE(_cp), \ | ||
164 | .conf.div_table = (_dt), \ | ||
165 | } \ | ||
166 | |||
167 | #define COMPOSITE(_ro, _ci, _cn, _cp, _f, _c) \ | ||
168 | { \ | ||
169 | .reg_off = (_ro), \ | ||
170 | .clk_type = CLK_COMPOSITE, \ | ||
171 | .clk_id = (_ci), \ | ||
172 | .clk_name = (_cn), \ | ||
173 | .clks_parent = (_cp), \ | ||
174 | .num_parents = ARRAY_SIZE(_cp), \ | ||
175 | .flags = (_f), \ | ||
176 | .conf.composite = (_c), \ | ||
177 | } \ | ||
178 | |||
179 | struct clk **meson_clk_init(struct device_node *np, unsigned long nr_clks); | ||
180 | void meson_clk_register_clks(const struct clk_conf *clk_confs, | ||
181 | unsigned int nr_confs, void __iomem *clk_base); | ||
182 | struct clk *meson_clk_register_cpu(const struct clk_conf *clk_conf, | ||
183 | void __iomem *reg_base, spinlock_t *lock); | ||
184 | struct clk *meson_clk_register_pll(const struct clk_conf *clk_conf, | ||
185 | void __iomem *reg_base, spinlock_t *lock); | ||
186 | 119 | ||
187 | #endif /* __CLKC_H */ | 120 | #endif /* __CLKC_H */ |
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c new file mode 100644 index 000000000000..007b7157cf4b --- /dev/null +++ b/drivers/clk/meson/gxbb.c | |||
@@ -0,0 +1,954 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016 AmLogic, Inc. | ||
3 | * Michael Turquette <mturquette@baylibre.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <linux/clk.h> | ||
19 | #include <linux/clk-provider.h> | ||
20 | #include <linux/of_address.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/module.h> | ||
23 | |||
24 | #include "clkc.h" | ||
25 | #include "gxbb.h" | ||
26 | |||
27 | static DEFINE_SPINLOCK(clk_lock); | ||
28 | |||
29 | static const struct pll_rate_table sys_pll_rate_table[] = { | ||
30 | PLL_RATE(24000000, 56, 1, 2), | ||
31 | PLL_RATE(48000000, 64, 1, 2), | ||
32 | PLL_RATE(72000000, 72, 1, 2), | ||
33 | PLL_RATE(96000000, 64, 1, 2), | ||
34 | PLL_RATE(120000000, 80, 1, 2), | ||
35 | PLL_RATE(144000000, 96, 1, 2), | ||
36 | PLL_RATE(168000000, 56, 1, 1), | ||
37 | PLL_RATE(192000000, 64, 1, 1), | ||
38 | PLL_RATE(216000000, 72, 1, 1), | ||
39 | PLL_RATE(240000000, 80, 1, 1), | ||
40 | PLL_RATE(264000000, 88, 1, 1), | ||
41 | PLL_RATE(288000000, 96, 1, 1), | ||
42 | PLL_RATE(312000000, 52, 1, 2), | ||
43 | PLL_RATE(336000000, 56, 1, 2), | ||
44 | PLL_RATE(360000000, 60, 1, 2), | ||
45 | PLL_RATE(384000000, 64, 1, 2), | ||
46 | PLL_RATE(408000000, 68, 1, 2), | ||
47 | PLL_RATE(432000000, 72, 1, 2), | ||
48 | PLL_RATE(456000000, 76, 1, 2), | ||
49 | PLL_RATE(480000000, 80, 1, 2), | ||
50 | PLL_RATE(504000000, 84, 1, 2), | ||
51 | PLL_RATE(528000000, 88, 1, 2), | ||
52 | PLL_RATE(552000000, 92, 1, 2), | ||
53 | PLL_RATE(576000000, 96, 1, 2), | ||
54 | PLL_RATE(600000000, 50, 1, 1), | ||
55 | PLL_RATE(624000000, 52, 1, 1), | ||
56 | PLL_RATE(648000000, 54, 1, 1), | ||
57 | PLL_RATE(672000000, 56, 1, 1), | ||
58 | PLL_RATE(696000000, 58, 1, 1), | ||
59 | PLL_RATE(720000000, 60, 1, 1), | ||
60 | PLL_RATE(744000000, 62, 1, 1), | ||
61 | PLL_RATE(768000000, 64, 1, 1), | ||
62 | PLL_RATE(792000000, 66, 1, 1), | ||
63 | PLL_RATE(816000000, 68, 1, 1), | ||
64 | PLL_RATE(840000000, 70, 1, 1), | ||
65 | PLL_RATE(864000000, 72, 1, 1), | ||
66 | PLL_RATE(888000000, 74, 1, 1), | ||
67 | PLL_RATE(912000000, 76, 1, 1), | ||
68 | PLL_RATE(936000000, 78, 1, 1), | ||
69 | PLL_RATE(960000000, 80, 1, 1), | ||
70 | PLL_RATE(984000000, 82, 1, 1), | ||
71 | PLL_RATE(1008000000, 84, 1, 1), | ||
72 | PLL_RATE(1032000000, 86, 1, 1), | ||
73 | PLL_RATE(1056000000, 88, 1, 1), | ||
74 | PLL_RATE(1080000000, 90, 1, 1), | ||
75 | PLL_RATE(1104000000, 92, 1, 1), | ||
76 | PLL_RATE(1128000000, 94, 1, 1), | ||
77 | PLL_RATE(1152000000, 96, 1, 1), | ||
78 | PLL_RATE(1176000000, 98, 1, 1), | ||
79 | PLL_RATE(1200000000, 50, 1, 0), | ||
80 | PLL_RATE(1224000000, 51, 1, 0), | ||
81 | PLL_RATE(1248000000, 52, 1, 0), | ||
82 | PLL_RATE(1272000000, 53, 1, 0), | ||
83 | PLL_RATE(1296000000, 54, 1, 0), | ||
84 | PLL_RATE(1320000000, 55, 1, 0), | ||
85 | PLL_RATE(1344000000, 56, 1, 0), | ||
86 | PLL_RATE(1368000000, 57, 1, 0), | ||
87 | PLL_RATE(1392000000, 58, 1, 0), | ||
88 | PLL_RATE(1416000000, 59, 1, 0), | ||
89 | PLL_RATE(1440000000, 60, 1, 0), | ||
90 | PLL_RATE(1464000000, 61, 1, 0), | ||
91 | PLL_RATE(1488000000, 62, 1, 0), | ||
92 | PLL_RATE(1512000000, 63, 1, 0), | ||
93 | PLL_RATE(1536000000, 64, 1, 0), | ||
94 | PLL_RATE(1560000000, 65, 1, 0), | ||
95 | PLL_RATE(1584000000, 66, 1, 0), | ||
96 | PLL_RATE(1608000000, 67, 1, 0), | ||
97 | PLL_RATE(1632000000, 68, 1, 0), | ||
98 | PLL_RATE(1656000000, 68, 1, 0), | ||
99 | PLL_RATE(1680000000, 68, 1, 0), | ||
100 | PLL_RATE(1704000000, 68, 1, 0), | ||
101 | PLL_RATE(1728000000, 69, 1, 0), | ||
102 | PLL_RATE(1752000000, 69, 1, 0), | ||
103 | PLL_RATE(1776000000, 69, 1, 0), | ||
104 | PLL_RATE(1800000000, 69, 1, 0), | ||
105 | PLL_RATE(1824000000, 70, 1, 0), | ||
106 | PLL_RATE(1848000000, 70, 1, 0), | ||
107 | PLL_RATE(1872000000, 70, 1, 0), | ||
108 | PLL_RATE(1896000000, 70, 1, 0), | ||
109 | PLL_RATE(1920000000, 71, 1, 0), | ||
110 | PLL_RATE(1944000000, 71, 1, 0), | ||
111 | PLL_RATE(1968000000, 71, 1, 0), | ||
112 | PLL_RATE(1992000000, 71, 1, 0), | ||
113 | PLL_RATE(2016000000, 72, 1, 0), | ||
114 | PLL_RATE(2040000000, 72, 1, 0), | ||
115 | PLL_RATE(2064000000, 72, 1, 0), | ||
116 | PLL_RATE(2088000000, 72, 1, 0), | ||
117 | PLL_RATE(2112000000, 73, 1, 0), | ||
118 | { /* sentinel */ }, | ||
119 | }; | ||
120 | |||
121 | static const struct pll_rate_table gp0_pll_rate_table[] = { | ||
122 | PLL_RATE(96000000, 32, 1, 3), | ||
123 | PLL_RATE(99000000, 33, 1, 3), | ||
124 | PLL_RATE(102000000, 34, 1, 3), | ||
125 | PLL_RATE(105000000, 35, 1, 3), | ||
126 | PLL_RATE(108000000, 36, 1, 3), | ||
127 | PLL_RATE(111000000, 37, 1, 3), | ||
128 | PLL_RATE(114000000, 38, 1, 3), | ||
129 | PLL_RATE(117000000, 39, 1, 3), | ||
130 | PLL_RATE(120000000, 40, 1, 3), | ||
131 | PLL_RATE(123000000, 41, 1, 3), | ||
132 | PLL_RATE(126000000, 42, 1, 3), | ||
133 | PLL_RATE(129000000, 43, 1, 3), | ||
134 | PLL_RATE(132000000, 44, 1, 3), | ||
135 | PLL_RATE(135000000, 45, 1, 3), | ||
136 | PLL_RATE(138000000, 46, 1, 3), | ||
137 | PLL_RATE(141000000, 47, 1, 3), | ||
138 | PLL_RATE(144000000, 48, 1, 3), | ||
139 | PLL_RATE(147000000, 49, 1, 3), | ||
140 | PLL_RATE(150000000, 50, 1, 3), | ||
141 | PLL_RATE(153000000, 51, 1, 3), | ||
142 | PLL_RATE(156000000, 52, 1, 3), | ||
143 | PLL_RATE(159000000, 53, 1, 3), | ||
144 | PLL_RATE(162000000, 54, 1, 3), | ||
145 | PLL_RATE(165000000, 55, 1, 3), | ||
146 | PLL_RATE(168000000, 56, 1, 3), | ||
147 | PLL_RATE(171000000, 57, 1, 3), | ||
148 | PLL_RATE(174000000, 58, 1, 3), | ||
149 | PLL_RATE(177000000, 59, 1, 3), | ||
150 | PLL_RATE(180000000, 60, 1, 3), | ||
151 | PLL_RATE(183000000, 61, 1, 3), | ||
152 | PLL_RATE(186000000, 62, 1, 3), | ||
153 | PLL_RATE(192000000, 32, 1, 2), | ||
154 | PLL_RATE(198000000, 33, 1, 2), | ||
155 | PLL_RATE(204000000, 34, 1, 2), | ||
156 | PLL_RATE(210000000, 35, 1, 2), | ||
157 | PLL_RATE(216000000, 36, 1, 2), | ||
158 | PLL_RATE(222000000, 37, 1, 2), | ||
159 | PLL_RATE(228000000, 38, 1, 2), | ||
160 | PLL_RATE(234000000, 39, 1, 2), | ||
161 | PLL_RATE(240000000, 40, 1, 2), | ||
162 | PLL_RATE(246000000, 41, 1, 2), | ||
163 | PLL_RATE(252000000, 42, 1, 2), | ||
164 | PLL_RATE(258000000, 43, 1, 2), | ||
165 | PLL_RATE(264000000, 44, 1, 2), | ||
166 | PLL_RATE(270000000, 45, 1, 2), | ||
167 | PLL_RATE(276000000, 46, 1, 2), | ||
168 | PLL_RATE(282000000, 47, 1, 2), | ||
169 | PLL_RATE(288000000, 48, 1, 2), | ||
170 | PLL_RATE(294000000, 49, 1, 2), | ||
171 | PLL_RATE(300000000, 50, 1, 2), | ||
172 | PLL_RATE(306000000, 51, 1, 2), | ||
173 | PLL_RATE(312000000, 52, 1, 2), | ||
174 | PLL_RATE(318000000, 53, 1, 2), | ||
175 | PLL_RATE(324000000, 54, 1, 2), | ||
176 | PLL_RATE(330000000, 55, 1, 2), | ||
177 | PLL_RATE(336000000, 56, 1, 2), | ||
178 | PLL_RATE(342000000, 57, 1, 2), | ||
179 | PLL_RATE(348000000, 58, 1, 2), | ||
180 | PLL_RATE(354000000, 59, 1, 2), | ||
181 | PLL_RATE(360000000, 60, 1, 2), | ||
182 | PLL_RATE(366000000, 61, 1, 2), | ||
183 | PLL_RATE(372000000, 62, 1, 2), | ||
184 | PLL_RATE(384000000, 32, 1, 1), | ||
185 | PLL_RATE(396000000, 33, 1, 1), | ||
186 | PLL_RATE(408000000, 34, 1, 1), | ||
187 | PLL_RATE(420000000, 35, 1, 1), | ||
188 | PLL_RATE(432000000, 36, 1, 1), | ||
189 | PLL_RATE(444000000, 37, 1, 1), | ||
190 | PLL_RATE(456000000, 38, 1, 1), | ||
191 | PLL_RATE(468000000, 39, 1, 1), | ||
192 | PLL_RATE(480000000, 40, 1, 1), | ||
193 | PLL_RATE(492000000, 41, 1, 1), | ||
194 | PLL_RATE(504000000, 42, 1, 1), | ||
195 | PLL_RATE(516000000, 43, 1, 1), | ||
196 | PLL_RATE(528000000, 44, 1, 1), | ||
197 | PLL_RATE(540000000, 45, 1, 1), | ||
198 | PLL_RATE(552000000, 46, 1, 1), | ||
199 | PLL_RATE(564000000, 47, 1, 1), | ||
200 | PLL_RATE(576000000, 48, 1, 1), | ||
201 | PLL_RATE(588000000, 49, 1, 1), | ||
202 | PLL_RATE(600000000, 50, 1, 1), | ||
203 | PLL_RATE(612000000, 51, 1, 1), | ||
204 | PLL_RATE(624000000, 52, 1, 1), | ||
205 | PLL_RATE(636000000, 53, 1, 1), | ||
206 | PLL_RATE(648000000, 54, 1, 1), | ||
207 | PLL_RATE(660000000, 55, 1, 1), | ||
208 | PLL_RATE(672000000, 56, 1, 1), | ||
209 | PLL_RATE(684000000, 57, 1, 1), | ||
210 | PLL_RATE(696000000, 58, 1, 1), | ||
211 | PLL_RATE(708000000, 59, 1, 1), | ||
212 | PLL_RATE(720000000, 60, 1, 1), | ||
213 | PLL_RATE(732000000, 61, 1, 1), | ||
214 | PLL_RATE(744000000, 62, 1, 1), | ||
215 | PLL_RATE(768000000, 32, 1, 0), | ||
216 | PLL_RATE(792000000, 33, 1, 0), | ||
217 | PLL_RATE(816000000, 34, 1, 0), | ||
218 | PLL_RATE(840000000, 35, 1, 0), | ||
219 | PLL_RATE(864000000, 36, 1, 0), | ||
220 | PLL_RATE(888000000, 37, 1, 0), | ||
221 | PLL_RATE(912000000, 38, 1, 0), | ||
222 | PLL_RATE(936000000, 39, 1, 0), | ||
223 | PLL_RATE(960000000, 40, 1, 0), | ||
224 | PLL_RATE(984000000, 41, 1, 0), | ||
225 | PLL_RATE(1008000000, 42, 1, 0), | ||
226 | PLL_RATE(1032000000, 43, 1, 0), | ||
227 | PLL_RATE(1056000000, 44, 1, 0), | ||
228 | PLL_RATE(1080000000, 45, 1, 0), | ||
229 | PLL_RATE(1104000000, 46, 1, 0), | ||
230 | PLL_RATE(1128000000, 47, 1, 0), | ||
231 | PLL_RATE(1152000000, 48, 1, 0), | ||
232 | PLL_RATE(1176000000, 49, 1, 0), | ||
233 | PLL_RATE(1200000000, 50, 1, 0), | ||
234 | PLL_RATE(1224000000, 51, 1, 0), | ||
235 | PLL_RATE(1248000000, 52, 1, 0), | ||
236 | PLL_RATE(1272000000, 53, 1, 0), | ||
237 | PLL_RATE(1296000000, 54, 1, 0), | ||
238 | PLL_RATE(1320000000, 55, 1, 0), | ||
239 | PLL_RATE(1344000000, 56, 1, 0), | ||
240 | PLL_RATE(1368000000, 57, 1, 0), | ||
241 | PLL_RATE(1392000000, 58, 1, 0), | ||
242 | PLL_RATE(1416000000, 59, 1, 0), | ||
243 | PLL_RATE(1440000000, 60, 1, 0), | ||
244 | PLL_RATE(1464000000, 61, 1, 0), | ||
245 | PLL_RATE(1488000000, 62, 1, 0), | ||
246 | { /* sentinel */ }, | ||
247 | }; | ||
248 | |||
249 | static const struct clk_div_table cpu_div_table[] = { | ||
250 | { .val = 1, .div = 1 }, | ||
251 | { .val = 2, .div = 2 }, | ||
252 | { .val = 3, .div = 3 }, | ||
253 | { .val = 2, .div = 4 }, | ||
254 | { .val = 3, .div = 6 }, | ||
255 | { .val = 4, .div = 8 }, | ||
256 | { .val = 5, .div = 10 }, | ||
257 | { .val = 6, .div = 12 }, | ||
258 | { .val = 7, .div = 14 }, | ||
259 | { .val = 8, .div = 16 }, | ||
260 | { /* sentinel */ }, | ||
261 | }; | ||
262 | |||
263 | static struct meson_clk_pll gxbb_fixed_pll = { | ||
264 | .m = { | ||
265 | .reg_off = HHI_MPLL_CNTL, | ||
266 | .shift = 0, | ||
267 | .width = 9, | ||
268 | }, | ||
269 | .n = { | ||
270 | .reg_off = HHI_MPLL_CNTL, | ||
271 | .shift = 9, | ||
272 | .width = 5, | ||
273 | }, | ||
274 | .od = { | ||
275 | .reg_off = HHI_MPLL_CNTL, | ||
276 | .shift = 16, | ||
277 | .width = 2, | ||
278 | }, | ||
279 | .lock = &clk_lock, | ||
280 | .hw.init = &(struct clk_init_data){ | ||
281 | .name = "fixed_pll", | ||
282 | .ops = &meson_clk_pll_ro_ops, | ||
283 | .parent_names = (const char *[]){ "xtal" }, | ||
284 | .num_parents = 1, | ||
285 | .flags = CLK_GET_RATE_NOCACHE, | ||
286 | }, | ||
287 | }; | ||
288 | |||
289 | static struct meson_clk_pll gxbb_hdmi_pll = { | ||
290 | .m = { | ||
291 | .reg_off = HHI_HDMI_PLL_CNTL, | ||
292 | .shift = 0, | ||
293 | .width = 9, | ||
294 | }, | ||
295 | .n = { | ||
296 | .reg_off = HHI_HDMI_PLL_CNTL, | ||
297 | .shift = 9, | ||
298 | .width = 5, | ||
299 | }, | ||
300 | .frac = { | ||
301 | .reg_off = HHI_HDMI_PLL_CNTL2, | ||
302 | .shift = 0, | ||
303 | .width = 12, | ||
304 | }, | ||
305 | .od = { | ||
306 | .reg_off = HHI_HDMI_PLL_CNTL2, | ||
307 | .shift = 16, | ||
308 | .width = 2, | ||
309 | }, | ||
310 | .od2 = { | ||
311 | .reg_off = HHI_HDMI_PLL_CNTL2, | ||
312 | .shift = 22, | ||
313 | .width = 2, | ||
314 | }, | ||
315 | .lock = &clk_lock, | ||
316 | .hw.init = &(struct clk_init_data){ | ||
317 | .name = "hdmi_pll", | ||
318 | .ops = &meson_clk_pll_ro_ops, | ||
319 | .parent_names = (const char *[]){ "xtal" }, | ||
320 | .num_parents = 1, | ||
321 | .flags = CLK_GET_RATE_NOCACHE, | ||
322 | }, | ||
323 | }; | ||
324 | |||
325 | static struct meson_clk_pll gxbb_sys_pll = { | ||
326 | .m = { | ||
327 | .reg_off = HHI_SYS_PLL_CNTL, | ||
328 | .shift = 0, | ||
329 | .width = 9, | ||
330 | }, | ||
331 | .n = { | ||
332 | .reg_off = HHI_SYS_PLL_CNTL, | ||
333 | .shift = 9, | ||
334 | .width = 5, | ||
335 | }, | ||
336 | .od = { | ||
337 | .reg_off = HHI_SYS_PLL_CNTL, | ||
338 | .shift = 10, | ||
339 | .width = 2, | ||
340 | }, | ||
341 | .rate_table = sys_pll_rate_table, | ||
342 | .rate_count = ARRAY_SIZE(sys_pll_rate_table), | ||
343 | .lock = &clk_lock, | ||
344 | .hw.init = &(struct clk_init_data){ | ||
345 | .name = "sys_pll", | ||
346 | .ops = &meson_clk_pll_ro_ops, | ||
347 | .parent_names = (const char *[]){ "xtal" }, | ||
348 | .num_parents = 1, | ||
349 | .flags = CLK_GET_RATE_NOCACHE, | ||
350 | }, | ||
351 | }; | ||
352 | |||
353 | static struct meson_clk_pll gxbb_gp0_pll = { | ||
354 | .m = { | ||
355 | .reg_off = HHI_GP0_PLL_CNTL, | ||
356 | .shift = 0, | ||
357 | .width = 9, | ||
358 | }, | ||
359 | .n = { | ||
360 | .reg_off = HHI_GP0_PLL_CNTL, | ||
361 | .shift = 9, | ||
362 | .width = 5, | ||
363 | }, | ||
364 | .od = { | ||
365 | .reg_off = HHI_GP0_PLL_CNTL, | ||
366 | .shift = 16, | ||
367 | .width = 2, | ||
368 | }, | ||
369 | .rate_table = gp0_pll_rate_table, | ||
370 | .rate_count = ARRAY_SIZE(gp0_pll_rate_table), | ||
371 | .lock = &clk_lock, | ||
372 | .hw.init = &(struct clk_init_data){ | ||
373 | .name = "gp0_pll", | ||
374 | .ops = &meson_clk_pll_ops, | ||
375 | .parent_names = (const char *[]){ "xtal" }, | ||
376 | .num_parents = 1, | ||
377 | .flags = CLK_GET_RATE_NOCACHE, | ||
378 | }, | ||
379 | }; | ||
380 | |||
381 | static struct clk_fixed_factor gxbb_fclk_div2 = { | ||
382 | .mult = 1, | ||
383 | .div = 2, | ||
384 | .hw.init = &(struct clk_init_data){ | ||
385 | .name = "fclk_div2", | ||
386 | .ops = &clk_fixed_factor_ops, | ||
387 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
388 | .num_parents = 1, | ||
389 | }, | ||
390 | }; | ||
391 | |||
392 | static struct clk_fixed_factor gxbb_fclk_div3 = { | ||
393 | .mult = 1, | ||
394 | .div = 3, | ||
395 | .hw.init = &(struct clk_init_data){ | ||
396 | .name = "fclk_div3", | ||
397 | .ops = &clk_fixed_factor_ops, | ||
398 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
399 | .num_parents = 1, | ||
400 | }, | ||
401 | }; | ||
402 | |||
403 | static struct clk_fixed_factor gxbb_fclk_div4 = { | ||
404 | .mult = 1, | ||
405 | .div = 4, | ||
406 | .hw.init = &(struct clk_init_data){ | ||
407 | .name = "fclk_div4", | ||
408 | .ops = &clk_fixed_factor_ops, | ||
409 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
410 | .num_parents = 1, | ||
411 | }, | ||
412 | }; | ||
413 | |||
414 | static struct clk_fixed_factor gxbb_fclk_div5 = { | ||
415 | .mult = 1, | ||
416 | .div = 5, | ||
417 | .hw.init = &(struct clk_init_data){ | ||
418 | .name = "fclk_div5", | ||
419 | .ops = &clk_fixed_factor_ops, | ||
420 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
421 | .num_parents = 1, | ||
422 | }, | ||
423 | }; | ||
424 | |||
425 | static struct clk_fixed_factor gxbb_fclk_div7 = { | ||
426 | .mult = 1, | ||
427 | .div = 7, | ||
428 | .hw.init = &(struct clk_init_data){ | ||
429 | .name = "fclk_div7", | ||
430 | .ops = &clk_fixed_factor_ops, | ||
431 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
432 | .num_parents = 1, | ||
433 | }, | ||
434 | }; | ||
435 | |||
436 | static struct meson_clk_mpll gxbb_mpll0 = { | ||
437 | .sdm = { | ||
438 | .reg_off = HHI_MPLL_CNTL7, | ||
439 | .shift = 0, | ||
440 | .width = 14, | ||
441 | }, | ||
442 | .n2 = { | ||
443 | .reg_off = HHI_MPLL_CNTL7, | ||
444 | .shift = 16, | ||
445 | .width = 9, | ||
446 | }, | ||
447 | .lock = &clk_lock, | ||
448 | .hw.init = &(struct clk_init_data){ | ||
449 | .name = "mpll0", | ||
450 | .ops = &meson_clk_mpll_ro_ops, | ||
451 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
452 | .num_parents = 1, | ||
453 | }, | ||
454 | }; | ||
455 | |||
456 | static struct meson_clk_mpll gxbb_mpll1 = { | ||
457 | .sdm = { | ||
458 | .reg_off = HHI_MPLL_CNTL8, | ||
459 | .shift = 0, | ||
460 | .width = 14, | ||
461 | }, | ||
462 | .n2 = { | ||
463 | .reg_off = HHI_MPLL_CNTL8, | ||
464 | .shift = 16, | ||
465 | .width = 9, | ||
466 | }, | ||
467 | .lock = &clk_lock, | ||
468 | .hw.init = &(struct clk_init_data){ | ||
469 | .name = "mpll1", | ||
470 | .ops = &meson_clk_mpll_ro_ops, | ||
471 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
472 | .num_parents = 1, | ||
473 | }, | ||
474 | }; | ||
475 | |||
476 | static struct meson_clk_mpll gxbb_mpll2 = { | ||
477 | .sdm = { | ||
478 | .reg_off = HHI_MPLL_CNTL9, | ||
479 | .shift = 0, | ||
480 | .width = 14, | ||
481 | }, | ||
482 | .n2 = { | ||
483 | .reg_off = HHI_MPLL_CNTL9, | ||
484 | .shift = 16, | ||
485 | .width = 9, | ||
486 | }, | ||
487 | .lock = &clk_lock, | ||
488 | .hw.init = &(struct clk_init_data){ | ||
489 | .name = "mpll2", | ||
490 | .ops = &meson_clk_mpll_ro_ops, | ||
491 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
492 | .num_parents = 1, | ||
493 | }, | ||
494 | }; | ||
495 | |||
496 | /* | ||
497 | * FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL | ||
498 | * post-dividers and should be modeled with their respective PLLs via the | ||
499 | * forthcoming coordinated clock rates feature | ||
500 | */ | ||
501 | static struct meson_clk_cpu gxbb_cpu_clk = { | ||
502 | .reg_off = HHI_SYS_CPU_CLK_CNTL1, | ||
503 | .div_table = cpu_div_table, | ||
504 | .clk_nb.notifier_call = meson_clk_cpu_notifier_cb, | ||
505 | .hw.init = &(struct clk_init_data){ | ||
506 | .name = "cpu_clk", | ||
507 | .ops = &meson_clk_cpu_ops, | ||
508 | .parent_names = (const char *[]){ "sys_pll" }, | ||
509 | .num_parents = 1, | ||
510 | }, | ||
511 | }; | ||
512 | |||
513 | static u32 mux_table_clk81[] = { 6, 5, 7 }; | ||
514 | |||
515 | static struct clk_mux gxbb_mpeg_clk_sel = { | ||
516 | .reg = (void *)HHI_MPEG_CLK_CNTL, | ||
517 | .mask = 0x7, | ||
518 | .shift = 12, | ||
519 | .flags = CLK_MUX_READ_ONLY, | ||
520 | .table = mux_table_clk81, | ||
521 | .lock = &clk_lock, | ||
522 | .hw.init = &(struct clk_init_data){ | ||
523 | .name = "mpeg_clk_sel", | ||
524 | .ops = &clk_mux_ro_ops, | ||
525 | /* | ||
526 | * FIXME bits 14:12 selects from 8 possible parents: | ||
527 | * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, | ||
528 | * fclk_div4, fclk_div3, fclk_div5 | ||
529 | */ | ||
530 | .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", | ||
531 | "fclk_div5" }, | ||
532 | .num_parents = 3, | ||
533 | .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), | ||
534 | }, | ||
535 | }; | ||
536 | |||
537 | static struct clk_divider gxbb_mpeg_clk_div = { | ||
538 | .reg = (void *)HHI_MPEG_CLK_CNTL, | ||
539 | .shift = 0, | ||
540 | .width = 7, | ||
541 | .lock = &clk_lock, | ||
542 | .hw.init = &(struct clk_init_data){ | ||
543 | .name = "mpeg_clk_div", | ||
544 | .ops = &clk_divider_ops, | ||
545 | .parent_names = (const char *[]){ "mpeg_clk_sel" }, | ||
546 | .num_parents = 1, | ||
547 | .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), | ||
548 | }, | ||
549 | }; | ||
550 | |||
551 | /* the mother of dragons^W gates */ | ||
552 | static struct clk_gate gxbb_clk81 = { | ||
553 | .reg = (void *)HHI_MPEG_CLK_CNTL, | ||
554 | .bit_idx = 7, | ||
555 | .lock = &clk_lock, | ||
556 | .hw.init = &(struct clk_init_data){ | ||
557 | .name = "clk81", | ||
558 | .ops = &clk_gate_ops, | ||
559 | .parent_names = (const char *[]){ "mpeg_clk_div" }, | ||
560 | .num_parents = 1, | ||
561 | .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED | CLK_IS_CRITICAL), | ||
562 | }, | ||
563 | }; | ||
564 | |||
565 | /* Everything Else (EE) domain gates */ | ||
566 | static MESON_GATE(ddr, HHI_GCLK_MPEG0, 0); | ||
567 | static MESON_GATE(dos, HHI_GCLK_MPEG0, 1); | ||
568 | static MESON_GATE(isa, HHI_GCLK_MPEG0, 5); | ||
569 | static MESON_GATE(pl301, HHI_GCLK_MPEG0, 6); | ||
570 | static MESON_GATE(periphs, HHI_GCLK_MPEG0, 7); | ||
571 | static MESON_GATE(spicc, HHI_GCLK_MPEG0, 8); | ||
572 | static MESON_GATE(i2c, HHI_GCLK_MPEG0, 9); | ||
573 | static MESON_GATE(sar_adc, HHI_GCLK_MPEG0, 10); | ||
574 | static MESON_GATE(smart_card, HHI_GCLK_MPEG0, 11); | ||
575 | static MESON_GATE(rng0, HHI_GCLK_MPEG0, 12); | ||
576 | static MESON_GATE(uart0, HHI_GCLK_MPEG0, 13); | ||
577 | static MESON_GATE(sdhc, HHI_GCLK_MPEG0, 14); | ||
578 | static MESON_GATE(stream, HHI_GCLK_MPEG0, 15); | ||
579 | static MESON_GATE(async_fifo, HHI_GCLK_MPEG0, 16); | ||
580 | static MESON_GATE(sdio, HHI_GCLK_MPEG0, 17); | ||
581 | static MESON_GATE(abuf, HHI_GCLK_MPEG0, 18); | ||
582 | static MESON_GATE(hiu_iface, HHI_GCLK_MPEG0, 19); | ||
583 | static MESON_GATE(assist_misc, HHI_GCLK_MPEG0, 23); | ||
584 | static MESON_GATE(spi, HHI_GCLK_MPEG0, 30); | ||
585 | |||
586 | static MESON_GATE(i2s_spdif, HHI_GCLK_MPEG1, 2); | ||
587 | static MESON_GATE(eth, HHI_GCLK_MPEG1, 3); | ||
588 | static MESON_GATE(demux, HHI_GCLK_MPEG1, 4); | ||
589 | static MESON_GATE(aiu_glue, HHI_GCLK_MPEG1, 6); | ||
590 | static MESON_GATE(iec958, HHI_GCLK_MPEG1, 7); | ||
591 | static MESON_GATE(i2s_out, HHI_GCLK_MPEG1, 8); | ||
592 | static MESON_GATE(amclk, HHI_GCLK_MPEG1, 9); | ||
593 | static MESON_GATE(aififo2, HHI_GCLK_MPEG1, 10); | ||
594 | static MESON_GATE(mixer, HHI_GCLK_MPEG1, 11); | ||
595 | static MESON_GATE(mixer_iface, HHI_GCLK_MPEG1, 12); | ||
596 | static MESON_GATE(adc, HHI_GCLK_MPEG1, 13); | ||
597 | static MESON_GATE(blkmv, HHI_GCLK_MPEG1, 14); | ||
598 | static MESON_GATE(aiu, HHI_GCLK_MPEG1, 15); | ||
599 | static MESON_GATE(uart1, HHI_GCLK_MPEG1, 16); | ||
600 | static MESON_GATE(g2d, HHI_GCLK_MPEG1, 20); | ||
601 | static MESON_GATE(usb0, HHI_GCLK_MPEG1, 21); | ||
602 | static MESON_GATE(usb1, HHI_GCLK_MPEG1, 22); | ||
603 | static MESON_GATE(reset, HHI_GCLK_MPEG1, 23); | ||
604 | static MESON_GATE(nand, HHI_GCLK_MPEG1, 24); | ||
605 | static MESON_GATE(dos_parser, HHI_GCLK_MPEG1, 25); | ||
606 | static MESON_GATE(usb, HHI_GCLK_MPEG1, 26); | ||
607 | static MESON_GATE(vdin1, HHI_GCLK_MPEG1, 28); | ||
608 | static MESON_GATE(ahb_arb0, HHI_GCLK_MPEG1, 29); | ||
609 | static MESON_GATE(efuse, HHI_GCLK_MPEG1, 30); | ||
610 | static MESON_GATE(boot_rom, HHI_GCLK_MPEG1, 31); | ||
611 | |||
612 | static MESON_GATE(ahb_data_bus, HHI_GCLK_MPEG2, 1); | ||
613 | static MESON_GATE(ahb_ctrl_bus, HHI_GCLK_MPEG2, 2); | ||
614 | static MESON_GATE(hdmi_intr_sync, HHI_GCLK_MPEG2, 3); | ||
615 | static MESON_GATE(hdmi_pclk, HHI_GCLK_MPEG2, 4); | ||
616 | static MESON_GATE(usb1_ddr_bridge, HHI_GCLK_MPEG2, 8); | ||
617 | static MESON_GATE(usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); | ||
618 | static MESON_GATE(mmc_pclk, HHI_GCLK_MPEG2, 11); | ||
619 | static MESON_GATE(dvin, HHI_GCLK_MPEG2, 12); | ||
620 | static MESON_GATE(uart2, HHI_GCLK_MPEG2, 15); | ||
621 | static MESON_GATE(sana, HHI_GCLK_MPEG2, 22); | ||
622 | static MESON_GATE(vpu_intr, HHI_GCLK_MPEG2, 25); | ||
623 | static MESON_GATE(sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); | ||
624 | static MESON_GATE(clk81_a53, HHI_GCLK_MPEG2, 29); | ||
625 | |||
626 | static MESON_GATE(vclk2_venci0, HHI_GCLK_OTHER, 1); | ||
627 | static MESON_GATE(vclk2_venci1, HHI_GCLK_OTHER, 2); | ||
628 | static MESON_GATE(vclk2_vencp0, HHI_GCLK_OTHER, 3); | ||
629 | static MESON_GATE(vclk2_vencp1, HHI_GCLK_OTHER, 4); | ||
630 | static MESON_GATE(gclk_venci_int0, HHI_GCLK_OTHER, 8); | ||
631 | static MESON_GATE(gclk_vencp_int, HHI_GCLK_OTHER, 9); | ||
632 | static MESON_GATE(dac_clk, HHI_GCLK_OTHER, 10); | ||
633 | static MESON_GATE(aoclk_gate, HHI_GCLK_OTHER, 14); | ||
634 | static MESON_GATE(iec958_gate, HHI_GCLK_OTHER, 16); | ||
635 | static MESON_GATE(enc480p, HHI_GCLK_OTHER, 20); | ||
636 | static MESON_GATE(rng1, HHI_GCLK_OTHER, 21); | ||
637 | static MESON_GATE(gclk_venci_int1, HHI_GCLK_OTHER, 22); | ||
638 | static MESON_GATE(vclk2_venclmcc, HHI_GCLK_OTHER, 24); | ||
639 | static MESON_GATE(vclk2_vencl, HHI_GCLK_OTHER, 25); | ||
640 | static MESON_GATE(vclk_other, HHI_GCLK_OTHER, 26); | ||
641 | static MESON_GATE(edp, HHI_GCLK_OTHER, 31); | ||
642 | |||
643 | /* Always On (AO) domain gates */ | ||
644 | |||
645 | static MESON_GATE(ao_media_cpu, HHI_GCLK_AO, 0); | ||
646 | static MESON_GATE(ao_ahb_sram, HHI_GCLK_AO, 1); | ||
647 | static MESON_GATE(ao_ahb_bus, HHI_GCLK_AO, 2); | ||
648 | static MESON_GATE(ao_iface, HHI_GCLK_AO, 3); | ||
649 | static MESON_GATE(ao_i2c, HHI_GCLK_AO, 4); | ||
650 | |||
651 | /* Array of all clocks provided by this provider */ | ||
652 | |||
653 | static struct clk_hw_onecell_data gxbb_hw_onecell_data = { | ||
654 | .hws = { | ||
655 | [CLKID_SYS_PLL] = &gxbb_sys_pll.hw, | ||
656 | [CLKID_CPUCLK] = &gxbb_cpu_clk.hw, | ||
657 | [CLKID_HDMI_PLL] = &gxbb_hdmi_pll.hw, | ||
658 | [CLKID_FIXED_PLL] = &gxbb_fixed_pll.hw, | ||
659 | [CLKID_FCLK_DIV2] = &gxbb_fclk_div2.hw, | ||
660 | [CLKID_FCLK_DIV3] = &gxbb_fclk_div3.hw, | ||
661 | [CLKID_FCLK_DIV4] = &gxbb_fclk_div4.hw, | ||
662 | [CLKID_FCLK_DIV5] = &gxbb_fclk_div5.hw, | ||
663 | [CLKID_FCLK_DIV7] = &gxbb_fclk_div7.hw, | ||
664 | [CLKID_GP0_PLL] = &gxbb_gp0_pll.hw, | ||
665 | [CLKID_MPEG_SEL] = &gxbb_mpeg_clk_sel.hw, | ||
666 | [CLKID_MPEG_DIV] = &gxbb_mpeg_clk_div.hw, | ||
667 | [CLKID_CLK81] = &gxbb_clk81.hw, | ||
668 | [CLKID_MPLL0] = &gxbb_mpll0.hw, | ||
669 | [CLKID_MPLL1] = &gxbb_mpll1.hw, | ||
670 | [CLKID_MPLL2] = &gxbb_mpll2.hw, | ||
671 | [CLKID_DDR] = &gxbb_ddr.hw, | ||
672 | [CLKID_DOS] = &gxbb_dos.hw, | ||
673 | [CLKID_ISA] = &gxbb_isa.hw, | ||
674 | [CLKID_PL301] = &gxbb_pl301.hw, | ||
675 | [CLKID_PERIPHS] = &gxbb_periphs.hw, | ||
676 | [CLKID_SPICC] = &gxbb_spicc.hw, | ||
677 | [CLKID_I2C] = &gxbb_i2c.hw, | ||
678 | [CLKID_SAR_ADC] = &gxbb_sar_adc.hw, | ||
679 | [CLKID_SMART_CARD] = &gxbb_smart_card.hw, | ||
680 | [CLKID_RNG0] = &gxbb_rng0.hw, | ||
681 | [CLKID_UART0] = &gxbb_uart0.hw, | ||
682 | [CLKID_SDHC] = &gxbb_sdhc.hw, | ||
683 | [CLKID_STREAM] = &gxbb_stream.hw, | ||
684 | [CLKID_ASYNC_FIFO] = &gxbb_async_fifo.hw, | ||
685 | [CLKID_SDIO] = &gxbb_sdio.hw, | ||
686 | [CLKID_ABUF] = &gxbb_abuf.hw, | ||
687 | [CLKID_HIU_IFACE] = &gxbb_hiu_iface.hw, | ||
688 | [CLKID_ASSIST_MISC] = &gxbb_assist_misc.hw, | ||
689 | [CLKID_SPI] = &gxbb_spi.hw, | ||
690 | [CLKID_I2S_SPDIF] = &gxbb_i2s_spdif.hw, | ||
691 | [CLKID_ETH] = &gxbb_eth.hw, | ||
692 | [CLKID_DEMUX] = &gxbb_demux.hw, | ||
693 | [CLKID_AIU_GLUE] = &gxbb_aiu_glue.hw, | ||
694 | [CLKID_IEC958] = &gxbb_iec958.hw, | ||
695 | [CLKID_I2S_OUT] = &gxbb_i2s_out.hw, | ||
696 | [CLKID_AMCLK] = &gxbb_amclk.hw, | ||
697 | [CLKID_AIFIFO2] = &gxbb_aififo2.hw, | ||
698 | [CLKID_MIXER] = &gxbb_mixer.hw, | ||
699 | [CLKID_MIXER_IFACE] = &gxbb_mixer_iface.hw, | ||
700 | [CLKID_ADC] = &gxbb_adc.hw, | ||
701 | [CLKID_BLKMV] = &gxbb_blkmv.hw, | ||
702 | [CLKID_AIU] = &gxbb_aiu.hw, | ||
703 | [CLKID_UART1] = &gxbb_uart1.hw, | ||
704 | [CLKID_G2D] = &gxbb_g2d.hw, | ||
705 | [CLKID_USB0] = &gxbb_usb0.hw, | ||
706 | [CLKID_USB1] = &gxbb_usb1.hw, | ||
707 | [CLKID_RESET] = &gxbb_reset.hw, | ||
708 | [CLKID_NAND] = &gxbb_nand.hw, | ||
709 | [CLKID_DOS_PARSER] = &gxbb_dos_parser.hw, | ||
710 | [CLKID_USB] = &gxbb_usb.hw, | ||
711 | [CLKID_VDIN1] = &gxbb_vdin1.hw, | ||
712 | [CLKID_AHB_ARB0] = &gxbb_ahb_arb0.hw, | ||
713 | [CLKID_EFUSE] = &gxbb_efuse.hw, | ||
714 | [CLKID_BOOT_ROM] = &gxbb_boot_rom.hw, | ||
715 | [CLKID_AHB_DATA_BUS] = &gxbb_ahb_data_bus.hw, | ||
716 | [CLKID_AHB_CTRL_BUS] = &gxbb_ahb_ctrl_bus.hw, | ||
717 | [CLKID_HDMI_INTR_SYNC] = &gxbb_hdmi_intr_sync.hw, | ||
718 | [CLKID_HDMI_PCLK] = &gxbb_hdmi_pclk.hw, | ||
719 | [CLKID_USB1_DDR_BRIDGE] = &gxbb_usb1_ddr_bridge.hw, | ||
720 | [CLKID_USB0_DDR_BRIDGE] = &gxbb_usb0_ddr_bridge.hw, | ||
721 | [CLKID_MMC_PCLK] = &gxbb_mmc_pclk.hw, | ||
722 | [CLKID_DVIN] = &gxbb_dvin.hw, | ||
723 | [CLKID_UART2] = &gxbb_uart2.hw, | ||
724 | [CLKID_SANA] = &gxbb_sana.hw, | ||
725 | [CLKID_VPU_INTR] = &gxbb_vpu_intr.hw, | ||
726 | [CLKID_SEC_AHB_AHB3_BRIDGE] = &gxbb_sec_ahb_ahb3_bridge.hw, | ||
727 | [CLKID_CLK81_A53] = &gxbb_clk81_a53.hw, | ||
728 | [CLKID_VCLK2_VENCI0] = &gxbb_vclk2_venci0.hw, | ||
729 | [CLKID_VCLK2_VENCI1] = &gxbb_vclk2_venci1.hw, | ||
730 | [CLKID_VCLK2_VENCP0] = &gxbb_vclk2_vencp0.hw, | ||
731 | [CLKID_VCLK2_VENCP1] = &gxbb_vclk2_vencp1.hw, | ||
732 | [CLKID_GCLK_VENCI_INT0] = &gxbb_gclk_venci_int0.hw, | ||
733 | [CLKID_GCLK_VENCI_INT] = &gxbb_gclk_vencp_int.hw, | ||
734 | [CLKID_DAC_CLK] = &gxbb_dac_clk.hw, | ||
735 | [CLKID_AOCLK_GATE] = &gxbb_aoclk_gate.hw, | ||
736 | [CLKID_IEC958_GATE] = &gxbb_iec958_gate.hw, | ||
737 | [CLKID_ENC480P] = &gxbb_enc480p.hw, | ||
738 | [CLKID_RNG1] = &gxbb_rng1.hw, | ||
739 | [CLKID_GCLK_VENCI_INT1] = &gxbb_gclk_venci_int1.hw, | ||
740 | [CLKID_VCLK2_VENCLMCC] = &gxbb_vclk2_venclmcc.hw, | ||
741 | [CLKID_VCLK2_VENCL] = &gxbb_vclk2_vencl.hw, | ||
742 | [CLKID_VCLK_OTHER] = &gxbb_vclk_other.hw, | ||
743 | [CLKID_EDP] = &gxbb_edp.hw, | ||
744 | [CLKID_AO_MEDIA_CPU] = &gxbb_ao_media_cpu.hw, | ||
745 | [CLKID_AO_AHB_SRAM] = &gxbb_ao_ahb_sram.hw, | ||
746 | [CLKID_AO_AHB_BUS] = &gxbb_ao_ahb_bus.hw, | ||
747 | [CLKID_AO_IFACE] = &gxbb_ao_iface.hw, | ||
748 | [CLKID_AO_I2C] = &gxbb_ao_i2c.hw, | ||
749 | }, | ||
750 | .num = NR_CLKS, | ||
751 | }; | ||
752 | |||
753 | /* Convenience tables to populate base addresses in .probe */ | ||
754 | |||
755 | static struct meson_clk_pll *const gxbb_clk_plls[] = { | ||
756 | &gxbb_fixed_pll, | ||
757 | &gxbb_hdmi_pll, | ||
758 | &gxbb_sys_pll, | ||
759 | &gxbb_gp0_pll, | ||
760 | }; | ||
761 | |||
762 | static struct meson_clk_mpll *const gxbb_clk_mplls[] = { | ||
763 | &gxbb_mpll0, | ||
764 | &gxbb_mpll1, | ||
765 | &gxbb_mpll2, | ||
766 | }; | ||
767 | |||
768 | static struct clk_gate *gxbb_clk_gates[] = { | ||
769 | &gxbb_clk81, | ||
770 | &gxbb_ddr, | ||
771 | &gxbb_dos, | ||
772 | &gxbb_isa, | ||
773 | &gxbb_pl301, | ||
774 | &gxbb_periphs, | ||
775 | &gxbb_spicc, | ||
776 | &gxbb_i2c, | ||
777 | &gxbb_sar_adc, | ||
778 | &gxbb_smart_card, | ||
779 | &gxbb_rng0, | ||
780 | &gxbb_uart0, | ||
781 | &gxbb_sdhc, | ||
782 | &gxbb_stream, | ||
783 | &gxbb_async_fifo, | ||
784 | &gxbb_sdio, | ||
785 | &gxbb_abuf, | ||
786 | &gxbb_hiu_iface, | ||
787 | &gxbb_assist_misc, | ||
788 | &gxbb_spi, | ||
789 | &gxbb_i2s_spdif, | ||
790 | &gxbb_eth, | ||
791 | &gxbb_demux, | ||
792 | &gxbb_aiu_glue, | ||
793 | &gxbb_iec958, | ||
794 | &gxbb_i2s_out, | ||
795 | &gxbb_amclk, | ||
796 | &gxbb_aififo2, | ||
797 | &gxbb_mixer, | ||
798 | &gxbb_mixer_iface, | ||
799 | &gxbb_adc, | ||
800 | &gxbb_blkmv, | ||
801 | &gxbb_aiu, | ||
802 | &gxbb_uart1, | ||
803 | &gxbb_g2d, | ||
804 | &gxbb_usb0, | ||
805 | &gxbb_usb1, | ||
806 | &gxbb_reset, | ||
807 | &gxbb_nand, | ||
808 | &gxbb_dos_parser, | ||
809 | &gxbb_usb, | ||
810 | &gxbb_vdin1, | ||
811 | &gxbb_ahb_arb0, | ||
812 | &gxbb_efuse, | ||
813 | &gxbb_boot_rom, | ||
814 | &gxbb_ahb_data_bus, | ||
815 | &gxbb_ahb_ctrl_bus, | ||
816 | &gxbb_hdmi_intr_sync, | ||
817 | &gxbb_hdmi_pclk, | ||
818 | &gxbb_usb1_ddr_bridge, | ||
819 | &gxbb_usb0_ddr_bridge, | ||
820 | &gxbb_mmc_pclk, | ||
821 | &gxbb_dvin, | ||
822 | &gxbb_uart2, | ||
823 | &gxbb_sana, | ||
824 | &gxbb_vpu_intr, | ||
825 | &gxbb_sec_ahb_ahb3_bridge, | ||
826 | &gxbb_clk81_a53, | ||
827 | &gxbb_vclk2_venci0, | ||
828 | &gxbb_vclk2_venci1, | ||
829 | &gxbb_vclk2_vencp0, | ||
830 | &gxbb_vclk2_vencp1, | ||
831 | &gxbb_gclk_venci_int0, | ||
832 | &gxbb_gclk_vencp_int, | ||
833 | &gxbb_dac_clk, | ||
834 | &gxbb_aoclk_gate, | ||
835 | &gxbb_iec958_gate, | ||
836 | &gxbb_enc480p, | ||
837 | &gxbb_rng1, | ||
838 | &gxbb_gclk_venci_int1, | ||
839 | &gxbb_vclk2_venclmcc, | ||
840 | &gxbb_vclk2_vencl, | ||
841 | &gxbb_vclk_other, | ||
842 | &gxbb_edp, | ||
843 | &gxbb_ao_media_cpu, | ||
844 | &gxbb_ao_ahb_sram, | ||
845 | &gxbb_ao_ahb_bus, | ||
846 | &gxbb_ao_iface, | ||
847 | &gxbb_ao_i2c, | ||
848 | }; | ||
849 | |||
850 | static int gxbb_clkc_probe(struct platform_device *pdev) | ||
851 | { | ||
852 | void __iomem *clk_base; | ||
853 | int ret, clkid, i; | ||
854 | struct clk_hw *parent_hw; | ||
855 | struct clk *parent_clk; | ||
856 | struct device *dev = &pdev->dev; | ||
857 | |||
858 | /* Generic clocks and PLLs */ | ||
859 | clk_base = of_iomap(dev->of_node, 0); | ||
860 | if (!clk_base) { | ||
861 | pr_err("%s: Unable to map clk base\n", __func__); | ||
862 | return -ENXIO; | ||
863 | } | ||
864 | |||
865 | /* Populate base address for PLLs */ | ||
866 | for (i = 0; i < ARRAY_SIZE(gxbb_clk_plls); i++) | ||
867 | gxbb_clk_plls[i]->base = clk_base; | ||
868 | |||
869 | /* Populate base address for MPLLs */ | ||
870 | for (i = 0; i < ARRAY_SIZE(gxbb_clk_mplls); i++) | ||
871 | gxbb_clk_mplls[i]->base = clk_base; | ||
872 | |||
873 | /* Populate the base address for CPU clk */ | ||
874 | gxbb_cpu_clk.base = clk_base; | ||
875 | |||
876 | /* Populate the base address for the MPEG clks */ | ||
877 | gxbb_mpeg_clk_sel.reg = clk_base + (u64)gxbb_mpeg_clk_sel.reg; | ||
878 | gxbb_mpeg_clk_div.reg = clk_base + (u64)gxbb_mpeg_clk_div.reg; | ||
879 | |||
880 | /* Populate base address for gates */ | ||
881 | for (i = 0; i < ARRAY_SIZE(gxbb_clk_gates); i++) | ||
882 | gxbb_clk_gates[i]->reg = clk_base + | ||
883 | (u64)gxbb_clk_gates[i]->reg; | ||
884 | |||
885 | /* | ||
886 | * register all clks | ||
887 | */ | ||
888 | for (clkid = 0; clkid < NR_CLKS; clkid++) { | ||
889 | ret = devm_clk_hw_register(dev, gxbb_hw_onecell_data.hws[clkid]); | ||
890 | if (ret) | ||
891 | goto iounmap; | ||
892 | } | ||
893 | |||
894 | /* | ||
895 | * Register CPU clk notifier | ||
896 | * | ||
897 | * FIXME this is wrong for a lot of reasons. First, the muxes should be | ||
898 | * struct clk_hw objects. Second, we shouldn't program the muxes in | ||
899 | * notifier handlers. The tricky programming sequence will be handled | ||
900 | * by the forthcoming coordinated clock rates mechanism once that | ||
901 | * feature is released. | ||
902 | * | ||
903 | * Furthermore, looking up the parent this way is terrible. At some | ||
904 | * point we will stop allocating a default struct clk when registering | ||
905 | * a new clk_hw, and this hack will no longer work. Releasing the ccr | ||
906 | * feature before that time solves the problem :-) | ||
907 | */ | ||
908 | parent_hw = clk_hw_get_parent(&gxbb_cpu_clk.hw); | ||
909 | parent_clk = parent_hw->clk; | ||
910 | ret = clk_notifier_register(parent_clk, &gxbb_cpu_clk.clk_nb); | ||
911 | if (ret) { | ||
912 | pr_err("%s: failed to register clock notifier for cpu_clk\n", | ||
913 | __func__); | ||
914 | goto iounmap; | ||
915 | } | ||
916 | |||
917 | return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, | ||
918 | &gxbb_hw_onecell_data); | ||
919 | |||
920 | iounmap: | ||
921 | iounmap(clk_base); | ||
922 | return ret; | ||
923 | } | ||
924 | |||
925 | static const struct of_device_id gxbb_clkc_match_table[] = { | ||
926 | { .compatible = "amlogic,gxbb-clkc" }, | ||
927 | { } | ||
928 | }; | ||
929 | MODULE_DEVICE_TABLE(of, gxbb_match_table); | ||
930 | |||
931 | static struct platform_driver gxbb_driver = { | ||
932 | .probe = gxbb_clkc_probe, | ||
933 | .driver = { | ||
934 | .name = "gxbb-clkc", | ||
935 | .of_match_table = gxbb_clkc_match_table, | ||
936 | }, | ||
937 | }; | ||
938 | |||
939 | static int __init gxbb_clkc_init(void) | ||
940 | { | ||
941 | return platform_driver_register(&gxbb_driver); | ||
942 | } | ||
943 | module_init(gxbb_clkc_init); | ||
944 | |||
945 | static void __exit gxbb_clkc_exit(void) | ||
946 | { | ||
947 | platform_driver_unregister(&gxbb_driver); | ||
948 | } | ||
949 | module_exit(gxbb_clkc_exit); | ||
950 | |||
951 | MODULE_DESCRIPTION("AmLogic S905 / GXBB Clock Controller Driver"); | ||
952 | MODULE_LICENSE("GPL v2"); | ||
953 | MODULE_ALIAS("platform:gxbb-clkc"); | ||
954 | MODULE_AUTHOR("Michael Turquette <mturquette@baylibre.com>"); | ||
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h new file mode 100644 index 000000000000..a2adf3448b59 --- /dev/null +++ b/drivers/clk/meson/gxbb.h | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
3 | * redistributing this file, you may do so under either license. | ||
4 | * | ||
5 | * GPL LICENSE SUMMARY | ||
6 | * | ||
7 | * Copyright (c) 2016 AmLogic, Inc. | ||
8 | * Author: Michael Turquette <mturquette@baylibre.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of version 2 of the GNU General Public License as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
22 | * The full GNU General Public License is included in this distribution | ||
23 | * in the file called COPYING | ||
24 | * | ||
25 | * BSD LICENSE | ||
26 | * | ||
27 | * Copyright (c) 2016 BayLibre, Inc. | ||
28 | * Author: Michael Turquette <mturquette@baylibre.com> | ||
29 | * | ||
30 | * Redistribution and use in source and binary forms, with or without | ||
31 | * modification, are permitted provided that the following conditions | ||
32 | * are met: | ||
33 | * | ||
34 | * * Redistributions of source code must retain the above copyright | ||
35 | * notice, this list of conditions and the following disclaimer. | ||
36 | * * Redistributions in binary form must reproduce the above copyright | ||
37 | * notice, this list of conditions and the following disclaimer in | ||
38 | * the documentation and/or other materials provided with the | ||
39 | * distribution. | ||
40 | * * Neither the name of Intel Corporation nor the names of its | ||
41 | * contributors may be used to endorse or promote products derived | ||
42 | * from this software without specific prior written permission. | ||
43 | * | ||
44 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
45 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
46 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
47 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
48 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
49 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
50 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
51 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
52 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
53 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
54 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
55 | */ | ||
56 | |||
57 | #ifndef __GXBB_H | ||
58 | #define __GXBB_H | ||
59 | |||
60 | /* | ||
61 | * Clock controller register offsets | ||
62 | * | ||
63 | * Register offsets from the data sheet are listed in comment blocks below. | ||
64 | * Those offsets must be multiplied by 4 before adding them to the base address | ||
65 | * to get the right value | ||
66 | */ | ||
67 | #define SCR 0x2C /* 0x0b offset in data sheet */ | ||
68 | #define TIMEOUT_VALUE 0x3c /* 0x0f offset in data sheet */ | ||
69 | |||
70 | #define HHI_GP0_PLL_CNTL 0x40 /* 0x10 offset in data sheet */ | ||
71 | #define HHI_GP0_PLL_CNTL2 0x44 /* 0x11 offset in data sheet */ | ||
72 | #define HHI_GP0_PLL_CNTL3 0x48 /* 0x12 offset in data sheet */ | ||
73 | #define HHI_GP0_PLL_CNTL4 0x4c /* 0x13 offset in data sheet */ | ||
74 | |||
75 | #define HHI_XTAL_DIVN_CNTL 0xbc /* 0x2f offset in data sheet */ | ||
76 | #define HHI_TIMER90K 0xec /* 0x3b offset in data sheet */ | ||
77 | |||
78 | #define HHI_MEM_PD_REG0 0x100 /* 0x40 offset in data sheet */ | ||
79 | #define HHI_MEM_PD_REG1 0x104 /* 0x41 offset in data sheet */ | ||
80 | #define HHI_VPU_MEM_PD_REG1 0x108 /* 0x42 offset in data sheet */ | ||
81 | #define HHI_VIID_CLK_DIV 0x128 /* 0x4a offset in data sheet */ | ||
82 | #define HHI_VIID_CLK_CNTL 0x12c /* 0x4b offset in data sheet */ | ||
83 | |||
84 | #define HHI_GCLK_MPEG0 0x140 /* 0x50 offset in data sheet */ | ||
85 | #define HHI_GCLK_MPEG1 0x144 /* 0x51 offset in data sheet */ | ||
86 | #define HHI_GCLK_MPEG2 0x148 /* 0x52 offset in data sheet */ | ||
87 | #define HHI_GCLK_OTHER 0x150 /* 0x54 offset in data sheet */ | ||
88 | #define HHI_GCLK_AO 0x154 /* 0x55 offset in data sheet */ | ||
89 | #define HHI_SYS_OSCIN_CNTL 0x158 /* 0x56 offset in data sheet */ | ||
90 | #define HHI_SYS_CPU_CLK_CNTL1 0x15c /* 0x57 offset in data sheet */ | ||
91 | #define HHI_SYS_CPU_RESET_CNTL 0x160 /* 0x58 offset in data sheet */ | ||
92 | #define HHI_VID_CLK_DIV 0x164 /* 0x59 offset in data sheet */ | ||
93 | |||
94 | #define HHI_MPEG_CLK_CNTL 0x174 /* 0x5d offset in data sheet */ | ||
95 | #define HHI_AUD_CLK_CNTL 0x178 /* 0x5e offset in data sheet */ | ||
96 | #define HHI_VID_CLK_CNTL 0x17c /* 0x5f offset in data sheet */ | ||
97 | #define HHI_AUD_CLK_CNTL2 0x190 /* 0x64 offset in data sheet */ | ||
98 | #define HHI_VID_CLK_CNTL2 0x194 /* 0x65 offset in data sheet */ | ||
99 | #define HHI_SYS_CPU_CLK_CNTL0 0x19c /* 0x67 offset in data sheet */ | ||
100 | #define HHI_VID_PLL_CLK_DIV 0x1a0 /* 0x68 offset in data sheet */ | ||
101 | #define HHI_AUD_CLK_CNTL3 0x1a4 /* 0x69 offset in data sheet */ | ||
102 | #define HHI_MALI_CLK_CNTL 0x1b0 /* 0x6c offset in data sheet */ | ||
103 | #define HHI_VPU_CLK_CNTL 0x1bC /* 0x6f offset in data sheet */ | ||
104 | |||
105 | #define HHI_HDMI_CLK_CNTL 0x1CC /* 0x73 offset in data sheet */ | ||
106 | #define HHI_VDEC_CLK_CNTL 0x1E0 /* 0x78 offset in data sheet */ | ||
107 | #define HHI_VDEC2_CLK_CNTL 0x1E4 /* 0x79 offset in data sheet */ | ||
108 | #define HHI_VDEC3_CLK_CNTL 0x1E8 /* 0x7a offset in data sheet */ | ||
109 | #define HHI_VDEC4_CLK_CNTL 0x1EC /* 0x7b offset in data sheet */ | ||
110 | #define HHI_HDCP22_CLK_CNTL 0x1F0 /* 0x7c offset in data sheet */ | ||
111 | #define HHI_VAPBCLK_CNTL 0x1F4 /* 0x7d offset in data sheet */ | ||
112 | |||
113 | #define HHI_VPU_CLKB_CNTL 0x20C /* 0x83 offset in data sheet */ | ||
114 | #define HHI_USB_CLK_CNTL 0x220 /* 0x88 offset in data sheet */ | ||
115 | #define HHI_32K_CLK_CNTL 0x224 /* 0x89 offset in data sheet */ | ||
116 | #define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */ | ||
117 | #define HHI_GEN_CLK_CNTL 0x228 /* 0x8a offset in data sheet */ | ||
118 | |||
119 | #define HHI_PCM_CLK_CNTL 0x258 /* 0x96 offset in data sheet */ | ||
120 | #define HHI_NAND_CLK_CNTL 0x25C /* 0x97 offset in data sheet */ | ||
121 | #define HHI_SD_EMMC_CLK_CNTL 0x264 /* 0x99 offset in data sheet */ | ||
122 | |||
123 | #define HHI_MPLL_CNTL 0x280 /* 0xa0 offset in data sheet */ | ||
124 | #define HHI_MPLL_CNTL2 0x284 /* 0xa1 offset in data sheet */ | ||
125 | #define HHI_MPLL_CNTL3 0x288 /* 0xa2 offset in data sheet */ | ||
126 | #define HHI_MPLL_CNTL4 0x28C /* 0xa3 offset in data sheet */ | ||
127 | #define HHI_MPLL_CNTL5 0x290 /* 0xa4 offset in data sheet */ | ||
128 | #define HHI_MPLL_CNTL6 0x294 /* 0xa5 offset in data sheet */ | ||
129 | #define HHI_MPLL_CNTL7 0x298 /* MP0, 0xa6 offset in data sheet */ | ||
130 | #define HHI_MPLL_CNTL8 0x29C /* MP1, 0xa7 offset in data sheet */ | ||
131 | #define HHI_MPLL_CNTL9 0x2A0 /* MP2, 0xa8 offset in data sheet */ | ||
132 | #define HHI_MPLL_CNTL10 0x2A4 /* MP2, 0xa9 offset in data sheet */ | ||
133 | |||
134 | #define HHI_MPLL3_CNTL0 0x2E0 /* 0xb8 offset in data sheet */ | ||
135 | #define HHI_MPLL3_CNTL1 0x2E4 /* 0xb9 offset in data sheet */ | ||
136 | #define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ | ||
137 | #define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ | ||
138 | |||
139 | #define HHI_SYS_PLL_CNTL 0x300 /* 0xc0 offset in data sheet */ | ||
140 | #define HHI_SYS_PLL_CNTL2 0x304 /* 0xc1 offset in data sheet */ | ||
141 | #define HHI_SYS_PLL_CNTL3 0x308 /* 0xc2 offset in data sheet */ | ||
142 | #define HHI_SYS_PLL_CNTL4 0x30c /* 0xc3 offset in data sheet */ | ||
143 | #define HHI_SYS_PLL_CNTL5 0x310 /* 0xc4 offset in data sheet */ | ||
144 | #define HHI_DPLL_TOP_I 0x318 /* 0xc6 offset in data sheet */ | ||
145 | #define HHI_DPLL_TOP2_I 0x31C /* 0xc7 offset in data sheet */ | ||
146 | #define HHI_HDMI_PLL_CNTL 0x320 /* 0xc8 offset in data sheet */ | ||
147 | #define HHI_HDMI_PLL_CNTL2 0x324 /* 0xc9 offset in data sheet */ | ||
148 | #define HHI_HDMI_PLL_CNTL3 0x328 /* 0xca offset in data sheet */ | ||
149 | #define HHI_HDMI_PLL_CNTL4 0x32C /* 0xcb offset in data sheet */ | ||
150 | #define HHI_HDMI_PLL_CNTL5 0x330 /* 0xcc offset in data sheet */ | ||
151 | #define HHI_HDMI_PLL_CNTL6 0x334 /* 0xcd offset in data sheet */ | ||
152 | #define HHI_HDMI_PLL_CNTL_I 0x338 /* 0xce offset in data sheet */ | ||
153 | #define HHI_HDMI_PLL_CNTL7 0x33C /* 0xcf offset in data sheet */ | ||
154 | |||
155 | #define HHI_HDMI_PHY_CNTL0 0x3A0 /* 0xe8 offset in data sheet */ | ||
156 | #define HHI_HDMI_PHY_CNTL1 0x3A4 /* 0xe9 offset in data sheet */ | ||
157 | #define HHI_HDMI_PHY_CNTL2 0x3A8 /* 0xea offset in data sheet */ | ||
158 | #define HHI_HDMI_PHY_CNTL3 0x3AC /* 0xeb offset in data sheet */ | ||
159 | |||
160 | #define HHI_VID_LOCK_CLK_CNTL 0x3C8 /* 0xf2 offset in data sheet */ | ||
161 | #define HHI_BT656_CLK_CNTL 0x3D4 /* 0xf5 offset in data sheet */ | ||
162 | #define HHI_SAR_CLK_CNTL 0x3D8 /* 0xf6 offset in data sheet */ | ||
163 | |||
164 | /* | ||
165 | * CLKID index values | ||
166 | * | ||
167 | * These indices are entirely contrived and do not map onto the hardware. | ||
168 | * Migrate them out of this header and into the DT header file when they need | ||
169 | * to be exposed to client nodes in DT: include/dt-bindings/clock/gxbb-clkc.h | ||
170 | */ | ||
171 | #define CLKID_SYS_PLL 0 | ||
172 | /* CLKID_CPUCLK */ | ||
173 | #define CLKID_HDMI_PLL 2 | ||
174 | #define CLKID_FIXED_PLL 3 | ||
175 | #define CLKID_FCLK_DIV2 4 | ||
176 | #define CLKID_FCLK_DIV3 5 | ||
177 | #define CLKID_FCLK_DIV4 6 | ||
178 | #define CLKID_FCLK_DIV5 7 | ||
179 | #define CLKID_FCLK_DIV7 8 | ||
180 | #define CLKID_GP0_PLL 9 | ||
181 | #define CLKID_MPEG_SEL 10 | ||
182 | #define CLKID_MPEG_DIV 11 | ||
183 | /* CLKID_CLK81 */ | ||
184 | #define CLKID_MPLL0 13 | ||
185 | #define CLKID_MPLL1 14 | ||
186 | #define CLKID_MPLL2 15 | ||
187 | #define CLKID_DDR 16 | ||
188 | #define CLKID_DOS 17 | ||
189 | #define CLKID_ISA 18 | ||
190 | #define CLKID_PL301 19 | ||
191 | #define CLKID_PERIPHS 20 | ||
192 | #define CLKID_SPICC 21 | ||
193 | #define CLKID_I2C 22 | ||
194 | #define CLKID_SAR_ADC 23 | ||
195 | #define CLKID_SMART_CARD 24 | ||
196 | #define CLKID_RNG0 25 | ||
197 | #define CLKID_UART0 26 | ||
198 | #define CLKID_SDHC 27 | ||
199 | #define CLKID_STREAM 28 | ||
200 | #define CLKID_ASYNC_FIFO 29 | ||
201 | #define CLKID_SDIO 30 | ||
202 | #define CLKID_ABUF 31 | ||
203 | #define CLKID_HIU_IFACE 32 | ||
204 | #define CLKID_ASSIST_MISC 33 | ||
205 | #define CLKID_SPI 34 | ||
206 | #define CLKID_I2S_SPDIF 35 | ||
207 | #define CLKID_ETH 36 | ||
208 | #define CLKID_DEMUX 37 | ||
209 | #define CLKID_AIU_GLUE 38 | ||
210 | #define CLKID_IEC958 39 | ||
211 | #define CLKID_I2S_OUT 40 | ||
212 | #define CLKID_AMCLK 41 | ||
213 | #define CLKID_AIFIFO2 42 | ||
214 | #define CLKID_MIXER 43 | ||
215 | #define CLKID_MIXER_IFACE 44 | ||
216 | #define CLKID_ADC 45 | ||
217 | #define CLKID_BLKMV 46 | ||
218 | #define CLKID_AIU 47 | ||
219 | #define CLKID_UART1 48 | ||
220 | #define CLKID_G2D 49 | ||
221 | #define CLKID_USB0 50 | ||
222 | #define CLKID_USB1 51 | ||
223 | #define CLKID_RESET 52 | ||
224 | #define CLKID_NAND 53 | ||
225 | #define CLKID_DOS_PARSER 54 | ||
226 | #define CLKID_USB 55 | ||
227 | #define CLKID_VDIN1 56 | ||
228 | #define CLKID_AHB_ARB0 57 | ||
229 | #define CLKID_EFUSE 58 | ||
230 | #define CLKID_BOOT_ROM 59 | ||
231 | #define CLKID_AHB_DATA_BUS 60 | ||
232 | #define CLKID_AHB_CTRL_BUS 61 | ||
233 | #define CLKID_HDMI_INTR_SYNC 62 | ||
234 | #define CLKID_HDMI_PCLK 63 | ||
235 | #define CLKID_USB1_DDR_BRIDGE 64 | ||
236 | #define CLKID_USB0_DDR_BRIDGE 65 | ||
237 | #define CLKID_MMC_PCLK 66 | ||
238 | #define CLKID_DVIN 67 | ||
239 | #define CLKID_UART2 68 | ||
240 | #define CLKID_SANA 69 | ||
241 | #define CLKID_VPU_INTR 70 | ||
242 | #define CLKID_SEC_AHB_AHB3_BRIDGE 71 | ||
243 | #define CLKID_CLK81_A53 72 | ||
244 | #define CLKID_VCLK2_VENCI0 73 | ||
245 | #define CLKID_VCLK2_VENCI1 74 | ||
246 | #define CLKID_VCLK2_VENCP0 75 | ||
247 | #define CLKID_VCLK2_VENCP1 76 | ||
248 | #define CLKID_GCLK_VENCI_INT0 77 | ||
249 | #define CLKID_GCLK_VENCI_INT 78 | ||
250 | #define CLKID_DAC_CLK 79 | ||
251 | #define CLKID_AOCLK_GATE 80 | ||
252 | #define CLKID_IEC958_GATE 81 | ||
253 | #define CLKID_ENC480P 82 | ||
254 | #define CLKID_RNG1 83 | ||
255 | #define CLKID_GCLK_VENCI_INT1 84 | ||
256 | #define CLKID_VCLK2_VENCLMCC 85 | ||
257 | #define CLKID_VCLK2_VENCL 86 | ||
258 | #define CLKID_VCLK_OTHER 87 | ||
259 | #define CLKID_EDP 88 | ||
260 | #define CLKID_AO_MEDIA_CPU 89 | ||
261 | #define CLKID_AO_AHB_SRAM 90 | ||
262 | #define CLKID_AO_AHB_BUS 91 | ||
263 | #define CLKID_AO_IFACE 92 | ||
264 | #define CLKID_AO_I2C 93 | ||
265 | |||
266 | #define NR_CLKS 94 | ||
267 | |||
268 | /* include the CLKIDs that have been made part of the stable DT binding */ | ||
269 | #include <dt-bindings/clock/gxbb-clkc.h> | ||
270 | |||
271 | #endif /* __GXBB_H */ | ||
diff --git a/drivers/clk/meson/meson8b-clkc.c b/drivers/clk/meson/meson8b-clkc.c index 4d057b3e21b2..b1902e91213d 100644 --- a/drivers/clk/meson/meson8b-clkc.c +++ b/drivers/clk/meson/meson8b-clkc.c | |||
@@ -2,6 +2,9 @@ | |||
2 | * Copyright (c) 2015 Endless Mobile, Inc. | 2 | * Copyright (c) 2015 Endless Mobile, Inc. |
3 | * Author: Carlo Caione <carlo@endlessm.com> | 3 | * Author: Carlo Caione <carlo@endlessm.com> |
4 | * | 4 | * |
5 | * Copyright (c) 2016 BayLibre, Inc. | ||
6 | * Michael Turquette <mturquette@baylibre.com> | ||
7 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms and conditions of the GNU General Public License, | 9 | * under the terms and conditions of the GNU General Public License, |
7 | * version 2, as published by the Free Software Foundation. | 10 | * version 2, as published by the Free Software Foundation. |
@@ -15,23 +18,33 @@ | |||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | 18 | * this program. If not, see <http://www.gnu.org/licenses/>. |
16 | */ | 19 | */ |
17 | 20 | ||
21 | #include <linux/clk.h> | ||
18 | #include <linux/clk-provider.h> | 22 | #include <linux/clk-provider.h> |
19 | #include <linux/kernel.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <linux/of_address.h> | 23 | #include <linux/of_address.h> |
22 | #include <linux/slab.h> | ||
23 | #include <dt-bindings/clock/meson8b-clkc.h> | 24 | #include <dt-bindings/clock/meson8b-clkc.h> |
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/module.h> | ||
24 | 27 | ||
25 | #include "clkc.h" | 28 | #include "clkc.h" |
26 | 29 | ||
27 | #define MESON8B_REG_CTL0_ADDR 0x0000 | 30 | /* |
28 | #define MESON8B_REG_SYS_CPU_CNTL1 0x015c | 31 | * Clock controller register offsets |
29 | #define MESON8B_REG_HHI_MPEG 0x0174 | 32 | * |
30 | #define MESON8B_REG_MALI 0x01b0 | 33 | * Register offsets from the HardKernel[0] data sheet are listed in comment |
34 | * blocks below. Those offsets must be multiplied by 4 before adding them to | ||
35 | * the base address to get the right value | ||
36 | * | ||
37 | * [0] http://dn.odroid.com/S805/Datasheet/S805_Datasheet%20V0.8%2020150126.pdf | ||
38 | */ | ||
39 | #define MESON8B_REG_SYS_CPU_CNTL1 0x015c /* 0x57 offset in data sheet */ | ||
40 | #define MESON8B_REG_HHI_MPEG 0x0174 /* 0x5d offset in data sheet */ | ||
41 | #define MESON8B_REG_MALI 0x01b0 /* 0x6c offset in data sheet */ | ||
31 | #define MESON8B_REG_PLL_FIXED 0x0280 | 42 | #define MESON8B_REG_PLL_FIXED 0x0280 |
32 | #define MESON8B_REG_PLL_SYS 0x0300 | 43 | #define MESON8B_REG_PLL_SYS 0x0300 |
33 | #define MESON8B_REG_PLL_VID 0x0320 | 44 | #define MESON8B_REG_PLL_VID 0x0320 |
34 | 45 | ||
46 | static DEFINE_SPINLOCK(clk_lock); | ||
47 | |||
35 | static const struct pll_rate_table sys_pll_rate_table[] = { | 48 | static const struct pll_rate_table sys_pll_rate_table[] = { |
36 | PLL_RATE(312000000, 52, 1, 2), | 49 | PLL_RATE(312000000, 52, 1, 2), |
37 | PLL_RATE(336000000, 56, 1, 2), | 50 | PLL_RATE(336000000, 56, 1, 2), |
@@ -102,95 +115,344 @@ static const struct clk_div_table cpu_div_table[] = { | |||
102 | { /* sentinel */ }, | 115 | { /* sentinel */ }, |
103 | }; | 116 | }; |
104 | 117 | ||
105 | PNAME(p_xtal) = { "xtal" }; | 118 | static struct clk_fixed_rate meson8b_xtal = { |
106 | PNAME(p_fclk_div) = { "fixed_pll" }; | 119 | .fixed_rate = 24000000, |
107 | PNAME(p_cpu_clk) = { "sys_pll" }; | 120 | .hw.init = &(struct clk_init_data){ |
108 | PNAME(p_clk81) = { "fclk_div3", "fclk_div4", "fclk_div5" }; | 121 | .name = "xtal", |
109 | PNAME(p_mali) = { "fclk_div3", "fclk_div4", "fclk_div5", | 122 | .num_parents = 0, |
110 | "fclk_div7", "zero" }; | 123 | .ops = &clk_fixed_rate_ops, |
124 | }, | ||
125 | }; | ||
126 | |||
127 | static struct meson_clk_pll meson8b_fixed_pll = { | ||
128 | .m = { | ||
129 | .reg_off = MESON8B_REG_PLL_FIXED, | ||
130 | .shift = 0, | ||
131 | .width = 9, | ||
132 | }, | ||
133 | .n = { | ||
134 | .reg_off = MESON8B_REG_PLL_FIXED, | ||
135 | .shift = 9, | ||
136 | .width = 5, | ||
137 | }, | ||
138 | .od = { | ||
139 | .reg_off = MESON8B_REG_PLL_FIXED, | ||
140 | .shift = 16, | ||
141 | .width = 2, | ||
142 | }, | ||
143 | .lock = &clk_lock, | ||
144 | .hw.init = &(struct clk_init_data){ | ||
145 | .name = "fixed_pll", | ||
146 | .ops = &meson_clk_pll_ro_ops, | ||
147 | .parent_names = (const char *[]){ "xtal" }, | ||
148 | .num_parents = 1, | ||
149 | .flags = CLK_GET_RATE_NOCACHE, | ||
150 | }, | ||
151 | }; | ||
152 | |||
153 | static struct meson_clk_pll meson8b_vid_pll = { | ||
154 | .m = { | ||
155 | .reg_off = MESON8B_REG_PLL_VID, | ||
156 | .shift = 0, | ||
157 | .width = 9, | ||
158 | }, | ||
159 | .n = { | ||
160 | .reg_off = MESON8B_REG_PLL_VID, | ||
161 | .shift = 9, | ||
162 | .width = 5, | ||
163 | }, | ||
164 | .od = { | ||
165 | .reg_off = MESON8B_REG_PLL_VID, | ||
166 | .shift = 16, | ||
167 | .width = 2, | ||
168 | }, | ||
169 | .lock = &clk_lock, | ||
170 | .hw.init = &(struct clk_init_data){ | ||
171 | .name = "vid_pll", | ||
172 | .ops = &meson_clk_pll_ro_ops, | ||
173 | .parent_names = (const char *[]){ "xtal" }, | ||
174 | .num_parents = 1, | ||
175 | .flags = CLK_GET_RATE_NOCACHE, | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | static struct meson_clk_pll meson8b_sys_pll = { | ||
180 | .m = { | ||
181 | .reg_off = MESON8B_REG_PLL_SYS, | ||
182 | .shift = 0, | ||
183 | .width = 9, | ||
184 | }, | ||
185 | .n = { | ||
186 | .reg_off = MESON8B_REG_PLL_SYS, | ||
187 | .shift = 9, | ||
188 | .width = 5, | ||
189 | }, | ||
190 | .od = { | ||
191 | .reg_off = MESON8B_REG_PLL_SYS, | ||
192 | .shift = 16, | ||
193 | .width = 2, | ||
194 | }, | ||
195 | .rate_table = sys_pll_rate_table, | ||
196 | .rate_count = ARRAY_SIZE(sys_pll_rate_table), | ||
197 | .lock = &clk_lock, | ||
198 | .hw.init = &(struct clk_init_data){ | ||
199 | .name = "sys_pll", | ||
200 | .ops = &meson_clk_pll_ops, | ||
201 | .parent_names = (const char *[]){ "xtal" }, | ||
202 | .num_parents = 1, | ||
203 | .flags = CLK_GET_RATE_NOCACHE, | ||
204 | }, | ||
205 | }; | ||
206 | |||
207 | static struct clk_fixed_factor meson8b_fclk_div2 = { | ||
208 | .mult = 1, | ||
209 | .div = 2, | ||
210 | .hw.init = &(struct clk_init_data){ | ||
211 | .name = "fclk_div2", | ||
212 | .ops = &clk_fixed_factor_ops, | ||
213 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
214 | .num_parents = 1, | ||
215 | }, | ||
216 | }; | ||
217 | |||
218 | static struct clk_fixed_factor meson8b_fclk_div3 = { | ||
219 | .mult = 1, | ||
220 | .div = 3, | ||
221 | .hw.init = &(struct clk_init_data){ | ||
222 | .name = "fclk_div3", | ||
223 | .ops = &clk_fixed_factor_ops, | ||
224 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
225 | .num_parents = 1, | ||
226 | }, | ||
227 | }; | ||
228 | |||
229 | static struct clk_fixed_factor meson8b_fclk_div4 = { | ||
230 | .mult = 1, | ||
231 | .div = 4, | ||
232 | .hw.init = &(struct clk_init_data){ | ||
233 | .name = "fclk_div4", | ||
234 | .ops = &clk_fixed_factor_ops, | ||
235 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
236 | .num_parents = 1, | ||
237 | }, | ||
238 | }; | ||
239 | |||
240 | static struct clk_fixed_factor meson8b_fclk_div5 = { | ||
241 | .mult = 1, | ||
242 | .div = 5, | ||
243 | .hw.init = &(struct clk_init_data){ | ||
244 | .name = "fclk_div5", | ||
245 | .ops = &clk_fixed_factor_ops, | ||
246 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
247 | .num_parents = 1, | ||
248 | }, | ||
249 | }; | ||
250 | |||
251 | static struct clk_fixed_factor meson8b_fclk_div7 = { | ||
252 | .mult = 1, | ||
253 | .div = 7, | ||
254 | .hw.init = &(struct clk_init_data){ | ||
255 | .name = "fclk_div7", | ||
256 | .ops = &clk_fixed_factor_ops, | ||
257 | .parent_names = (const char *[]){ "fixed_pll" }, | ||
258 | .num_parents = 1, | ||
259 | }, | ||
260 | }; | ||
261 | |||
262 | /* | ||
263 | * FIXME cpu clocks and the legacy composite clocks (e.g. clk81) are both PLL | ||
264 | * post-dividers and should be modeled with their respective PLLs via the | ||
265 | * forthcoming coordinated clock rates feature | ||
266 | */ | ||
267 | static struct meson_clk_cpu meson8b_cpu_clk = { | ||
268 | .reg_off = MESON8B_REG_SYS_CPU_CNTL1, | ||
269 | .div_table = cpu_div_table, | ||
270 | .clk_nb.notifier_call = meson_clk_cpu_notifier_cb, | ||
271 | .hw.init = &(struct clk_init_data){ | ||
272 | .name = "cpu_clk", | ||
273 | .ops = &meson_clk_cpu_ops, | ||
274 | .parent_names = (const char *[]){ "sys_pll" }, | ||
275 | .num_parents = 1, | ||
276 | }, | ||
277 | }; | ||
111 | 278 | ||
112 | static u32 mux_table_clk81[] = { 6, 5, 7 }; | 279 | static u32 mux_table_clk81[] = { 6, 5, 7 }; |
113 | static u32 mux_table_mali[] = { 6, 5, 7, 4, 0 }; | ||
114 | |||
115 | static struct pll_conf pll_confs = { | ||
116 | .m = PARM(0x00, 0, 9), | ||
117 | .n = PARM(0x00, 9, 5), | ||
118 | .od = PARM(0x00, 16, 2), | ||
119 | }; | ||
120 | |||
121 | static struct pll_conf sys_pll_conf = { | ||
122 | .m = PARM(0x00, 0, 9), | ||
123 | .n = PARM(0x00, 9, 5), | ||
124 | .od = PARM(0x00, 16, 2), | ||
125 | .rate_table = sys_pll_rate_table, | ||
126 | }; | ||
127 | |||
128 | static const struct composite_conf clk81_conf __initconst = { | ||
129 | .mux_table = mux_table_clk81, | ||
130 | .mux_flags = CLK_MUX_READ_ONLY, | ||
131 | .mux_parm = PARM(0x00, 12, 3), | ||
132 | .div_parm = PARM(0x00, 0, 7), | ||
133 | .gate_parm = PARM(0x00, 7, 1), | ||
134 | }; | ||
135 | |||
136 | static const struct composite_conf mali_conf __initconst = { | ||
137 | .mux_table = mux_table_mali, | ||
138 | .mux_parm = PARM(0x00, 9, 3), | ||
139 | .div_parm = PARM(0x00, 0, 7), | ||
140 | .gate_parm = PARM(0x00, 8, 1), | ||
141 | }; | ||
142 | |||
143 | static const struct clk_conf meson8b_xtal_conf __initconst = | ||
144 | FIXED_RATE_P(MESON8B_REG_CTL0_ADDR, CLKID_XTAL, "xtal", 0, | ||
145 | PARM(0x00, 4, 7)); | ||
146 | |||
147 | static const struct clk_conf meson8b_clk_confs[] __initconst = { | ||
148 | FIXED_RATE(CLKID_ZERO, "zero", 0, 0), | ||
149 | PLL(MESON8B_REG_PLL_FIXED, CLKID_PLL_FIXED, "fixed_pll", | ||
150 | p_xtal, 0, &pll_confs), | ||
151 | PLL(MESON8B_REG_PLL_VID, CLKID_PLL_VID, "vid_pll", | ||
152 | p_xtal, 0, &pll_confs), | ||
153 | PLL(MESON8B_REG_PLL_SYS, CLKID_PLL_SYS, "sys_pll", | ||
154 | p_xtal, 0, &sys_pll_conf), | ||
155 | FIXED_FACTOR_DIV(CLKID_FCLK_DIV2, "fclk_div2", p_fclk_div, 0, 2), | ||
156 | FIXED_FACTOR_DIV(CLKID_FCLK_DIV3, "fclk_div3", p_fclk_div, 0, 3), | ||
157 | FIXED_FACTOR_DIV(CLKID_FCLK_DIV4, "fclk_div4", p_fclk_div, 0, 4), | ||
158 | FIXED_FACTOR_DIV(CLKID_FCLK_DIV5, "fclk_div5", p_fclk_div, 0, 5), | ||
159 | FIXED_FACTOR_DIV(CLKID_FCLK_DIV7, "fclk_div7", p_fclk_div, 0, 7), | ||
160 | CPU(MESON8B_REG_SYS_CPU_CNTL1, CLKID_CPUCLK, "a5_clk", p_cpu_clk, | ||
161 | cpu_div_table), | ||
162 | COMPOSITE(MESON8B_REG_HHI_MPEG, CLKID_CLK81, "clk81", p_clk81, | ||
163 | CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED, &clk81_conf), | ||
164 | COMPOSITE(MESON8B_REG_MALI, CLKID_MALI, "mali", p_mali, | ||
165 | CLK_IGNORE_UNUSED, &mali_conf), | ||
166 | }; | ||
167 | |||
168 | static void __init meson8b_clkc_init(struct device_node *np) | ||
169 | { | ||
170 | void __iomem *clk_base; | ||
171 | 280 | ||
172 | if (!meson_clk_init(np, CLK_NR_CLKS)) | 281 | struct clk_mux meson8b_mpeg_clk_sel = { |
173 | return; | 282 | .reg = (void *)MESON8B_REG_HHI_MPEG, |
283 | .mask = 0x7, | ||
284 | .shift = 12, | ||
285 | .flags = CLK_MUX_READ_ONLY, | ||
286 | .table = mux_table_clk81, | ||
287 | .lock = &clk_lock, | ||
288 | .hw.init = &(struct clk_init_data){ | ||
289 | .name = "mpeg_clk_sel", | ||
290 | .ops = &clk_mux_ro_ops, | ||
291 | /* | ||
292 | * FIXME bits 14:12 selects from 8 possible parents: | ||
293 | * xtal, 1'b0 (wtf), fclk_div7, mpll_clkout1, mpll_clkout2, | ||
294 | * fclk_div4, fclk_div3, fclk_div5 | ||
295 | */ | ||
296 | .parent_names = (const char *[]){ "fclk_div3", "fclk_div4", | ||
297 | "fclk_div5" }, | ||
298 | .num_parents = 3, | ||
299 | .flags = (CLK_SET_RATE_NO_REPARENT | CLK_IGNORE_UNUSED), | ||
300 | }, | ||
301 | }; | ||
174 | 302 | ||
175 | /* XTAL */ | 303 | struct clk_divider meson8b_mpeg_clk_div = { |
176 | clk_base = of_iomap(np, 0); | 304 | .reg = (void *)MESON8B_REG_HHI_MPEG, |
177 | if (!clk_base) { | 305 | .shift = 0, |
178 | pr_err("%s: Unable to map xtal base\n", __func__); | 306 | .width = 7, |
179 | return; | 307 | .lock = &clk_lock, |
180 | } | 308 | .hw.init = &(struct clk_init_data){ |
309 | .name = "mpeg_clk_div", | ||
310 | .ops = &clk_divider_ops, | ||
311 | .parent_names = (const char *[]){ "mpeg_clk_sel" }, | ||
312 | .num_parents = 1, | ||
313 | .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), | ||
314 | }, | ||
315 | }; | ||
181 | 316 | ||
182 | meson_clk_register_clks(&meson8b_xtal_conf, 1, clk_base); | 317 | struct clk_gate meson8b_clk81 = { |
183 | iounmap(clk_base); | 318 | .reg = (void *)MESON8B_REG_HHI_MPEG, |
319 | .bit_idx = 7, | ||
320 | .lock = &clk_lock, | ||
321 | .hw.init = &(struct clk_init_data){ | ||
322 | .name = "clk81", | ||
323 | .ops = &clk_gate_ops, | ||
324 | .parent_names = (const char *[]){ "mpeg_clk_div" }, | ||
325 | .num_parents = 1, | ||
326 | .flags = (CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED), | ||
327 | }, | ||
328 | }; | ||
329 | |||
330 | static struct clk_hw_onecell_data meson8b_hw_onecell_data = { | ||
331 | .hws = { | ||
332 | [CLKID_XTAL] = &meson8b_xtal.hw, | ||
333 | [CLKID_PLL_FIXED] = &meson8b_fixed_pll.hw, | ||
334 | [CLKID_PLL_VID] = &meson8b_vid_pll.hw, | ||
335 | [CLKID_PLL_SYS] = &meson8b_sys_pll.hw, | ||
336 | [CLKID_FCLK_DIV2] = &meson8b_fclk_div2.hw, | ||
337 | [CLKID_FCLK_DIV3] = &meson8b_fclk_div3.hw, | ||
338 | [CLKID_FCLK_DIV4] = &meson8b_fclk_div4.hw, | ||
339 | [CLKID_FCLK_DIV5] = &meson8b_fclk_div5.hw, | ||
340 | [CLKID_FCLK_DIV7] = &meson8b_fclk_div7.hw, | ||
341 | [CLKID_CPUCLK] = &meson8b_cpu_clk.hw, | ||
342 | [CLKID_MPEG_SEL] = &meson8b_mpeg_clk_sel.hw, | ||
343 | [CLKID_MPEG_DIV] = &meson8b_mpeg_clk_div.hw, | ||
344 | [CLKID_CLK81] = &meson8b_clk81.hw, | ||
345 | }, | ||
346 | .num = CLK_NR_CLKS, | ||
347 | }; | ||
348 | |||
349 | static struct meson_clk_pll *const meson8b_clk_plls[] = { | ||
350 | &meson8b_fixed_pll, | ||
351 | &meson8b_vid_pll, | ||
352 | &meson8b_sys_pll, | ||
353 | }; | ||
354 | |||
355 | static int meson8b_clkc_probe(struct platform_device *pdev) | ||
356 | { | ||
357 | void __iomem *clk_base; | ||
358 | int ret, clkid, i; | ||
359 | struct clk_hw *parent_hw; | ||
360 | struct clk *parent_clk; | ||
361 | struct device *dev = &pdev->dev; | ||
184 | 362 | ||
185 | /* Generic clocks and PLLs */ | 363 | /* Generic clocks and PLLs */ |
186 | clk_base = of_iomap(np, 1); | 364 | clk_base = of_iomap(dev->of_node, 1); |
187 | if (!clk_base) { | 365 | if (!clk_base) { |
188 | pr_err("%s: Unable to map clk base\n", __func__); | 366 | pr_err("%s: Unable to map clk base\n", __func__); |
189 | return; | 367 | return -ENXIO; |
368 | } | ||
369 | |||
370 | /* Populate base address for PLLs */ | ||
371 | for (i = 0; i < ARRAY_SIZE(meson8b_clk_plls); i++) | ||
372 | meson8b_clk_plls[i]->base = clk_base; | ||
373 | |||
374 | /* Populate the base address for CPU clk */ | ||
375 | meson8b_cpu_clk.base = clk_base; | ||
376 | |||
377 | /* Populate the base address for the MPEG clks */ | ||
378 | meson8b_mpeg_clk_sel.reg = clk_base + (u32)meson8b_mpeg_clk_sel.reg; | ||
379 | meson8b_mpeg_clk_div.reg = clk_base + (u32)meson8b_mpeg_clk_div.reg; | ||
380 | meson8b_clk81.reg = clk_base + (u32)meson8b_clk81.reg; | ||
381 | |||
382 | /* | ||
383 | * register all clks | ||
384 | * CLKID_UNUSED = 0, so skip it and start with CLKID_XTAL = 1 | ||
385 | */ | ||
386 | for (clkid = CLKID_XTAL; clkid < CLK_NR_CLKS; clkid++) { | ||
387 | /* array might be sparse */ | ||
388 | if (!meson8b_hw_onecell_data.hws[clkid]) | ||
389 | continue; | ||
390 | |||
391 | /* FIXME convert to devm_clk_register */ | ||
392 | ret = devm_clk_hw_register(dev, meson8b_hw_onecell_data.hws[clkid]); | ||
393 | if (ret) | ||
394 | goto iounmap; | ||
190 | } | 395 | } |
191 | 396 | ||
192 | meson_clk_register_clks(meson8b_clk_confs, | 397 | /* |
193 | ARRAY_SIZE(meson8b_clk_confs), | 398 | * Register CPU clk notifier |
194 | clk_base); | 399 | * |
400 | * FIXME this is wrong for a lot of reasons. First, the muxes should be | ||
401 | * struct clk_hw objects. Second, we shouldn't program the muxes in | ||
402 | * notifier handlers. The tricky programming sequence will be handled | ||
403 | * by the forthcoming coordinated clock rates mechanism once that | ||
404 | * feature is released. | ||
405 | * | ||
406 | * Furthermore, looking up the parent this way is terrible. At some | ||
407 | * point we will stop allocating a default struct clk when registering | ||
408 | * a new clk_hw, and this hack will no longer work. Releasing the ccr | ||
409 | * feature before that time solves the problem :-) | ||
410 | */ | ||
411 | parent_hw = clk_hw_get_parent(&meson8b_cpu_clk.hw); | ||
412 | parent_clk = parent_hw->clk; | ||
413 | ret = clk_notifier_register(parent_clk, &meson8b_cpu_clk.clk_nb); | ||
414 | if (ret) { | ||
415 | pr_err("%s: failed to register clock notifier for cpu_clk\n", | ||
416 | __func__); | ||
417 | goto iounmap; | ||
418 | } | ||
419 | |||
420 | return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, | ||
421 | &meson8b_hw_onecell_data); | ||
422 | |||
423 | iounmap: | ||
424 | iounmap(clk_base); | ||
425 | return ret; | ||
195 | } | 426 | } |
196 | CLK_OF_DECLARE(meson8b_clock, "amlogic,meson8b-clkc", meson8b_clkc_init); | 427 | |
428 | static const struct of_device_id meson8b_clkc_match_table[] = { | ||
429 | { .compatible = "amlogic,meson8b-clkc" }, | ||
430 | { } | ||
431 | }; | ||
432 | MODULE_DEVICE_TABLE(of, meson8b_match_table); | ||
433 | |||
434 | static struct platform_driver meson8b_driver = { | ||
435 | .probe = meson8b_clkc_probe, | ||
436 | .driver = { | ||
437 | .name = "meson8b-clkc", | ||
438 | .of_match_table = meson8b_clkc_match_table, | ||
439 | }, | ||
440 | }; | ||
441 | |||
442 | static int __init meson8b_clkc_init(void) | ||
443 | { | ||
444 | return platform_driver_register(&meson8b_driver); | ||
445 | } | ||
446 | module_init(meson8b_clkc_init); | ||
447 | |||
448 | static void __exit meson8b_clkc_exit(void) | ||
449 | { | ||
450 | platform_driver_unregister(&meson8b_driver); | ||
451 | } | ||
452 | module_exit(meson8b_clkc_exit); | ||
453 | |||
454 | MODULE_DESCRIPTION("AmLogic S805 / Meson8b Clock Controller Driver"); | ||
455 | MODULE_LICENSE("GPL v2"); | ||
456 | MODULE_ALIAS("platform:meson8b-clkc"); | ||
457 | MODULE_AUTHOR("Michael Turquette <mturquette@baylibre.com>"); | ||
458 | MODULE_AUTHOR("Carlo Caione <carlo@endlessm.com>"); | ||