aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt56
-rw-r--r--drivers/clk/rockchip/Makefile1
-rw-r--r--drivers/clk/rockchip/clk-cpu.c4
-rw-r--r--drivers/clk/rockchip/clk-pll.c258
-rw-r--r--drivers/clk/rockchip/clk-rk3036.c478
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c36
-rw-r--r--drivers/clk/rockchip/clk-rk3368.c11
-rw-r--r--drivers/clk/rockchip/clk.h32
8 files changed, 850 insertions, 26 deletions
diff --git a/Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt b/Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt
new file mode 100644
index 000000000000..ace05992a262
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/rockchip,rk3036-cru.txt
@@ -0,0 +1,56 @@
1* Rockchip RK3036 Clock and Reset Unit
2
3The RK3036 clock controller generates and supplies clock to various
4controllers within the SoC and also implements a reset controller for SoC
5peripherals.
6
7Required Properties:
8
9- compatible: should be "rockchip,rk3036-cru"
10- reg: physical base address of the controller and length of memory mapped
11 region.
12- #clock-cells: should be 1.
13- #reset-cells: should be 1.
14
15Optional Properties:
16
17- rockchip,grf: phandle to the syscon managing the "general register files"
18 If missing pll rates are not changeable, due to the missing pll lock status.
19
20Each clock is assigned an identifier and client nodes can use this identifier
21to specify the clock which they consume. All available clocks are defined as
22preprocessor macros in the dt-bindings/clock/rk3036-cru.h headers and can be
23used in device tree sources. Similar macros exist for the reset sources in
24these files.
25
26External clocks:
27
28There are several clocks that are generated outside the SoC. It is expected
29that they are defined using standard clock bindings with following
30clock-output-names:
31 - "xin24m" - crystal input - required,
32 - "ext_i2s" - external I2S clock - optional,
33 - "ext_gmac" - external GMAC clock - optional
34
35Example: Clock controller node:
36
37 cru: cru@20000000 {
38 compatible = "rockchip,rk3036-cru";
39 reg = <0x20000000 0x1000>;
40 rockchip,grf = <&grf>;
41
42 #clock-cells = <1>;
43 #reset-cells = <1>;
44 };
45
46Example: UART controller node that consumes the clock generated by the clock
47 controller:
48
49 uart0: serial@20060000 {
50 compatible = "snps,dw-apb-uart";
51 reg = <0x20060000 0x100>;
52 interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
53 reg-shift = <2>;
54 reg-io-width = <4>;
55 clocks = <&cru SCLK_UART0>;
56 };
diff --git a/drivers/clk/rockchip/Makefile b/drivers/clk/rockchip/Makefile
index b27edd6c8183..d599829a021a 100644
--- a/drivers/clk/rockchip/Makefile
+++ b/drivers/clk/rockchip/Makefile
@@ -10,6 +10,7 @@ obj-y += clk-inverter.o
10obj-y += clk-mmc-phase.o 10obj-y += clk-mmc-phase.o
11obj-$(CONFIG_RESET_CONTROLLER) += softrst.o 11obj-$(CONFIG_RESET_CONTROLLER) += softrst.o
12 12
13obj-y += clk-rk3036.o
13obj-y += clk-rk3188.o 14obj-y += clk-rk3188.o
14obj-y += clk-rk3288.o 15obj-y += clk-rk3288.o
15obj-y += clk-rk3368.o 16obj-y += clk-rk3368.o
diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c
index 330870a6d8bf..d07374f48caf 100644
--- a/drivers/clk/rockchip/clk-cpu.c
+++ b/drivers/clk/rockchip/clk-cpu.c
@@ -242,8 +242,8 @@ struct clk *rockchip_clk_register_cpuclk(const char *name,
242 struct clk *clk, *cclk; 242 struct clk *clk, *cclk;
243 int ret; 243 int ret;
244 244
245 if (num_parents != 2) { 245 if (num_parents < 2) {
246 pr_err("%s: needs two parent clocks\n", __func__); 246 pr_err("%s: needs at least two parent clocks\n", __func__);
247 return ERR_PTR(-EINVAL); 247 return ERR_PTR(-EINVAL);
248 } 248 }
249 249
diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
index 4881eb8a1576..b7e66c9dd9f2 100644
--- a/drivers/clk/rockchip/clk-pll.c
+++ b/drivers/clk/rockchip/clk-pll.c
@@ -2,6 +2,9 @@
2 * Copyright (c) 2014 MundoReader S.L. 2 * Copyright (c) 2014 MundoReader S.L.
3 * Author: Heiko Stuebner <heiko@sntech.de> 3 * Author: Heiko Stuebner <heiko@sntech.de>
4 * 4 *
5 * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
6 * Author: Xing Zheng <zhengxing@rock-chips.com>
7 *
5 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
@@ -19,6 +22,7 @@
19#include <linux/delay.h> 22#include <linux/delay.h>
20#include <linux/clk-provider.h> 23#include <linux/clk-provider.h>
21#include <linux/regmap.h> 24#include <linux/regmap.h>
25#include <linux/clk.h>
22#include "clk.h" 26#include "clk.h"
23 27
24#define PLL_MODE_MASK 0x3 28#define PLL_MODE_MASK 0x3
@@ -108,6 +112,252 @@ static int rockchip_pll_wait_lock(struct rockchip_clk_pll *pll)
108} 112}
109 113
110/** 114/**
115 * PLL used in RK3036
116 */
117
118#define RK3036_PLLCON(i) (i * 0x4)
119#define RK3036_PLLCON0_FBDIV_MASK 0xfff
120#define RK3036_PLLCON0_FBDIV_SHIFT 0
121#define RK3036_PLLCON0_POSTDIV1_MASK 0x7
122#define RK3036_PLLCON0_POSTDIV1_SHIFT 12
123#define RK3036_PLLCON1_REFDIV_MASK 0x3f
124#define RK3036_PLLCON1_REFDIV_SHIFT 0
125#define RK3036_PLLCON1_POSTDIV2_MASK 0x7
126#define RK3036_PLLCON1_POSTDIV2_SHIFT 6
127#define RK3036_PLLCON1_DSMPD_MASK 0x1
128#define RK3036_PLLCON1_DSMPD_SHIFT 12
129#define RK3036_PLLCON2_FRAC_MASK 0xffffff
130#define RK3036_PLLCON2_FRAC_SHIFT 0
131
132#define RK3036_PLLCON1_PWRDOWN (1 << 13)
133
134static void rockchip_rk3036_pll_get_params(struct rockchip_clk_pll *pll,
135 struct rockchip_pll_rate_table *rate)
136{
137 u32 pllcon;
138
139 pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(0));
140 rate->fbdiv = ((pllcon >> RK3036_PLLCON0_FBDIV_SHIFT)
141 & RK3036_PLLCON0_FBDIV_MASK);
142 rate->postdiv1 = ((pllcon >> RK3036_PLLCON0_POSTDIV1_SHIFT)
143 & RK3036_PLLCON0_POSTDIV1_MASK);
144
145 pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(1));
146 rate->refdiv = ((pllcon >> RK3036_PLLCON1_REFDIV_SHIFT)
147 & RK3036_PLLCON1_REFDIV_MASK);
148 rate->postdiv2 = ((pllcon >> RK3036_PLLCON1_POSTDIV2_SHIFT)
149 & RK3036_PLLCON1_POSTDIV2_MASK);
150 rate->dsmpd = ((pllcon >> RK3036_PLLCON1_DSMPD_SHIFT)
151 & RK3036_PLLCON1_DSMPD_MASK);
152
153 pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2));
154 rate->frac = ((pllcon >> RK3036_PLLCON2_FRAC_SHIFT)
155 & RK3036_PLLCON2_FRAC_MASK);
156}
157
158static unsigned long rockchip_rk3036_pll_recalc_rate(struct clk_hw *hw,
159 unsigned long prate)
160{
161 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
162 struct rockchip_pll_rate_table cur;
163 u64 rate64 = prate;
164
165 rockchip_rk3036_pll_get_params(pll, &cur);
166
167 rate64 *= cur.fbdiv;
168 do_div(rate64, cur.refdiv);
169
170 if (cur.dsmpd == 0) {
171 /* fractional mode */
172 u64 frac_rate64 = prate * cur.frac;
173
174 do_div(frac_rate64, cur.refdiv);
175 rate64 += frac_rate64 >> 24;
176 }
177
178 do_div(rate64, cur.postdiv1);
179 do_div(rate64, cur.postdiv2);
180
181 return (unsigned long)rate64;
182}
183
184static int rockchip_rk3036_pll_set_params(struct rockchip_clk_pll *pll,
185 const struct rockchip_pll_rate_table *rate)
186{
187 const struct clk_ops *pll_mux_ops = pll->pll_mux_ops;
188 struct clk_mux *pll_mux = &pll->pll_mux;
189 struct rockchip_pll_rate_table cur;
190 u32 pllcon;
191 int rate_change_remuxed = 0;
192 int cur_parent;
193 int ret;
194
195 pr_debug("%s: rate settings for %lu fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
196 __func__, rate->rate, rate->fbdiv, rate->postdiv1, rate->refdiv,
197 rate->postdiv2, rate->dsmpd, rate->frac);
198
199 rockchip_rk3036_pll_get_params(pll, &cur);
200 cur.rate = 0;
201
202 cur_parent = pll_mux_ops->get_parent(&pll_mux->hw);
203 if (cur_parent == PLL_MODE_NORM) {
204 pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_SLOW);
205 rate_change_remuxed = 1;
206 }
207
208 /* update pll values */
209 writel_relaxed(HIWORD_UPDATE(rate->fbdiv, RK3036_PLLCON0_FBDIV_MASK,
210 RK3036_PLLCON0_FBDIV_SHIFT) |
211 HIWORD_UPDATE(rate->postdiv1, RK3036_PLLCON0_POSTDIV1_MASK,
212 RK3036_PLLCON0_POSTDIV1_SHIFT),
213 pll->reg_base + RK3036_PLLCON(0));
214
215 writel_relaxed(HIWORD_UPDATE(rate->refdiv, RK3036_PLLCON1_REFDIV_MASK,
216 RK3036_PLLCON1_REFDIV_SHIFT) |
217 HIWORD_UPDATE(rate->postdiv2, RK3036_PLLCON1_POSTDIV2_MASK,
218 RK3036_PLLCON1_POSTDIV2_SHIFT) |
219 HIWORD_UPDATE(rate->dsmpd, RK3036_PLLCON1_DSMPD_MASK,
220 RK3036_PLLCON1_DSMPD_SHIFT),
221 pll->reg_base + RK3036_PLLCON(1));
222
223 /* GPLL CON2 is not HIWORD_MASK */
224 pllcon = readl_relaxed(pll->reg_base + RK3036_PLLCON(2));
225 pllcon &= ~(RK3036_PLLCON2_FRAC_MASK << RK3036_PLLCON2_FRAC_SHIFT);
226 pllcon |= rate->frac << RK3036_PLLCON2_FRAC_SHIFT;
227 writel_relaxed(pllcon, pll->reg_base + RK3036_PLLCON(2));
228
229 /* wait for the pll to lock */
230 ret = rockchip_pll_wait_lock(pll);
231 if (ret) {
232 pr_warn("%s: pll update unsucessful, trying to restore old params\n",
233 __func__);
234 rockchip_rk3036_pll_set_params(pll, &cur);
235 }
236
237 if (rate_change_remuxed)
238 pll_mux_ops->set_parent(&pll_mux->hw, PLL_MODE_NORM);
239
240 return ret;
241}
242
243static int rockchip_rk3036_pll_set_rate(struct clk_hw *hw, unsigned long drate,
244 unsigned long prate)
245{
246 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
247 const struct rockchip_pll_rate_table *rate;
248 unsigned long old_rate = rockchip_rk3036_pll_recalc_rate(hw, prate);
249 struct regmap *grf = rockchip_clk_get_grf();
250
251 if (IS_ERR(grf)) {
252 pr_debug("%s: grf regmap not available, aborting rate change\n",
253 __func__);
254 return PTR_ERR(grf);
255 }
256
257 pr_debug("%s: changing %s from %lu to %lu with a parent rate of %lu\n",
258 __func__, __clk_get_name(hw->clk), old_rate, drate, prate);
259
260 /* Get required rate settings from table */
261 rate = rockchip_get_pll_settings(pll, drate);
262 if (!rate) {
263 pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
264 drate, __clk_get_name(hw->clk));
265 return -EINVAL;
266 }
267
268 return rockchip_rk3036_pll_set_params(pll, rate);
269}
270
271static int rockchip_rk3036_pll_enable(struct clk_hw *hw)
272{
273 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
274
275 writel(HIWORD_UPDATE(0, RK3036_PLLCON1_PWRDOWN, 0),
276 pll->reg_base + RK3036_PLLCON(1));
277
278 return 0;
279}
280
281static void rockchip_rk3036_pll_disable(struct clk_hw *hw)
282{
283 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
284
285 writel(HIWORD_UPDATE(RK3036_PLLCON1_PWRDOWN,
286 RK3036_PLLCON1_PWRDOWN, 0),
287 pll->reg_base + RK3036_PLLCON(1));
288}
289
290static int rockchip_rk3036_pll_is_enabled(struct clk_hw *hw)
291{
292 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
293 u32 pllcon = readl(pll->reg_base + RK3036_PLLCON(1));
294
295 return !(pllcon & RK3036_PLLCON1_PWRDOWN);
296}
297
298static void rockchip_rk3036_pll_init(struct clk_hw *hw)
299{
300 struct rockchip_clk_pll *pll = to_rockchip_clk_pll(hw);
301 const struct rockchip_pll_rate_table *rate;
302 struct rockchip_pll_rate_table cur;
303 unsigned long drate;
304
305 if (!(pll->flags & ROCKCHIP_PLL_SYNC_RATE))
306 return;
307
308 drate = clk_hw_get_rate(hw);
309 rate = rockchip_get_pll_settings(pll, drate);
310
311 /* when no rate setting for the current rate, rely on clk_set_rate */
312 if (!rate)
313 return;
314
315 rockchip_rk3036_pll_get_params(pll, &cur);
316
317 pr_debug("%s: pll %s@%lu: Hz\n", __func__, __clk_get_name(hw->clk),
318 drate);
319 pr_debug("old - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
320 cur.fbdiv, cur.postdiv1, cur.refdiv, cur.postdiv2,
321 cur.dsmpd, cur.frac);
322 pr_debug("new - fbdiv: %d, postdiv1: %d, refdiv: %d, postdiv2: %d, dsmpd: %d, frac: %d\n",
323 rate->fbdiv, rate->postdiv1, rate->refdiv, rate->postdiv2,
324 rate->dsmpd, rate->frac);
325
326 if (rate->fbdiv != cur.fbdiv || rate->postdiv1 != cur.postdiv1 ||
327 rate->refdiv != cur.refdiv || rate->postdiv2 != cur.postdiv2 ||
328 rate->dsmpd != cur.dsmpd || rate->frac != cur.frac) {
329 struct clk *parent = clk_get_parent(hw->clk);
330
331 if (!parent) {
332 pr_warn("%s: parent of %s not available\n",
333 __func__, __clk_get_name(hw->clk));
334 return;
335 }
336
337 pr_debug("%s: pll %s: rate params do not match rate table, adjusting\n",
338 __func__, __clk_get_name(hw->clk));
339 rockchip_rk3036_pll_set_params(pll, rate);
340 }
341}
342
343static const struct clk_ops rockchip_rk3036_pll_clk_norate_ops = {
344 .recalc_rate = rockchip_rk3036_pll_recalc_rate,
345 .enable = rockchip_rk3036_pll_enable,
346 .disable = rockchip_rk3036_pll_disable,
347 .is_enabled = rockchip_rk3036_pll_is_enabled,
348};
349
350static const struct clk_ops rockchip_rk3036_pll_clk_ops = {
351 .recalc_rate = rockchip_rk3036_pll_recalc_rate,
352 .round_rate = rockchip_pll_round_rate,
353 .set_rate = rockchip_rk3036_pll_set_rate,
354 .enable = rockchip_rk3036_pll_enable,
355 .disable = rockchip_rk3036_pll_disable,
356 .is_enabled = rockchip_rk3036_pll_is_enabled,
357 .init = rockchip_rk3036_pll_init,
358};
359
360/**
111 * PLL used in RK3066, RK3188 and RK3288 361 * PLL used in RK3066, RK3188 and RK3288
112 */ 362 */
113 363
@@ -376,7 +626,7 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
376 pll_mux->lock = lock; 626 pll_mux->lock = lock;
377 pll_mux->hw.init = &init; 627 pll_mux->hw.init = &init;
378 628
379 if (pll_type == pll_rk3066) 629 if (pll_type == pll_rk3036 || pll_type == pll_rk3066)
380 pll_mux->flags |= CLK_MUX_HIWORD_MASK; 630 pll_mux->flags |= CLK_MUX_HIWORD_MASK;
381 631
382 /* the actual muxing is xin24m, pll-output, xin32k */ 632 /* the actual muxing is xin24m, pll-output, xin32k */
@@ -421,6 +671,12 @@ struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type,
421 } 671 }
422 672
423 switch (pll_type) { 673 switch (pll_type) {
674 case pll_rk3036:
675 if (!pll->rate_table)
676 init.ops = &rockchip_rk3036_pll_clk_norate_ops;
677 else
678 init.ops = &rockchip_rk3036_pll_clk_ops;
679 break;
424 case pll_rk3066: 680 case pll_rk3066:
425 if (!pll->rate_table) 681 if (!pll->rate_table)
426 init.ops = &rockchip_rk3066_pll_clk_norate_ops; 682 init.ops = &rockchip_rk3066_pll_clk_norate_ops;
diff --git a/drivers/clk/rockchip/clk-rk3036.c b/drivers/clk/rockchip/clk-rk3036.c
new file mode 100644
index 000000000000..75553af3dc39
--- /dev/null
+++ b/drivers/clk/rockchip/clk-rk3036.c
@@ -0,0 +1,478 @@
1/*
2 * Copyright (c) 2014 MundoReader S.L.
3 * Author: Heiko Stuebner <heiko@sntech.de>
4 *
5 * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
6 * Author: Xing Zheng <zhengxing@rock-chips.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/clk-provider.h>
20#include <linux/of.h>
21#include <linux/of_address.h>
22#include <linux/syscore_ops.h>
23#include <dt-bindings/clock/rk3036-cru.h>
24#include "clk.h"
25
26#define RK3036_GRF_SOC_STATUS0 0x14c
27
28enum rk3036_plls {
29 apll, dpll, gpll,
30};
31
32static struct rockchip_pll_rate_table rk3036_pll_rates[] = {
33 /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
34 RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
35 RK3036_PLL_RATE(1584000000, 1, 66, 1, 1, 1, 0),
36 RK3036_PLL_RATE(1560000000, 1, 65, 1, 1, 1, 0),
37 RK3036_PLL_RATE(1536000000, 1, 64, 1, 1, 1, 0),
38 RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
39 RK3036_PLL_RATE(1488000000, 1, 62, 1, 1, 1, 0),
40 RK3036_PLL_RATE(1464000000, 1, 61, 1, 1, 1, 0),
41 RK3036_PLL_RATE(1440000000, 1, 60, 1, 1, 1, 0),
42 RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
43 RK3036_PLL_RATE(1392000000, 1, 58, 1, 1, 1, 0),
44 RK3036_PLL_RATE(1368000000, 1, 57, 1, 1, 1, 0),
45 RK3036_PLL_RATE(1344000000, 1, 56, 1, 1, 1, 0),
46 RK3036_PLL_RATE(1320000000, 1, 55, 1, 1, 1, 0),
47 RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
48 RK3036_PLL_RATE(1272000000, 1, 53, 1, 1, 1, 0),
49 RK3036_PLL_RATE(1248000000, 1, 52, 1, 1, 1, 0),
50 RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
51 RK3036_PLL_RATE(1188000000, 2, 99, 1, 1, 1, 0),
52 RK3036_PLL_RATE(1104000000, 1, 46, 1, 1, 1, 0),
53 RK3036_PLL_RATE(1100000000, 12, 550, 1, 1, 1, 0),
54 RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
55 RK3036_PLL_RATE(1000000000, 6, 500, 2, 1, 1, 0),
56 RK3036_PLL_RATE( 984000000, 1, 82, 2, 1, 1, 0),
57 RK3036_PLL_RATE( 960000000, 1, 80, 2, 1, 1, 0),
58 RK3036_PLL_RATE( 936000000, 1, 78, 2, 1, 1, 0),
59 RK3036_PLL_RATE( 912000000, 1, 76, 2, 1, 1, 0),
60 RK3036_PLL_RATE( 900000000, 4, 300, 2, 1, 1, 0),
61 RK3036_PLL_RATE( 888000000, 1, 74, 2, 1, 1, 0),
62 RK3036_PLL_RATE( 864000000, 1, 72, 2, 1, 1, 0),
63 RK3036_PLL_RATE( 840000000, 1, 70, 2, 1, 1, 0),
64 RK3036_PLL_RATE( 816000000, 1, 68, 2, 1, 1, 0),
65 RK3036_PLL_RATE( 800000000, 6, 400, 2, 1, 1, 0),
66 RK3036_PLL_RATE( 700000000, 6, 350, 2, 1, 1, 0),
67 RK3036_PLL_RATE( 696000000, 1, 58, 2, 1, 1, 0),
68 RK3036_PLL_RATE( 600000000, 1, 75, 3, 1, 1, 0),
69 RK3036_PLL_RATE( 594000000, 2, 99, 2, 1, 1, 0),
70 RK3036_PLL_RATE( 504000000, 1, 63, 3, 1, 1, 0),
71 RK3036_PLL_RATE( 500000000, 6, 250, 2, 1, 1, 0),
72 RK3036_PLL_RATE( 408000000, 1, 68, 2, 2, 1, 0),
73 RK3036_PLL_RATE( 312000000, 1, 52, 2, 2, 1, 0),
74 RK3036_PLL_RATE( 216000000, 1, 72, 4, 2, 1, 0),
75 RK3036_PLL_RATE( 96000000, 1, 64, 4, 4, 1, 0),
76 { /* sentinel */ },
77};
78
79#define RK3036_DIV_CPU_MASK 0x1f
80#define RK3036_DIV_CPU_SHIFT 8
81
82#define RK3036_DIV_PERI_MASK 0xf
83#define RK3036_DIV_PERI_SHIFT 0
84#define RK3036_DIV_ACLK_MASK 0x7
85#define RK3036_DIV_ACLK_SHIFT 4
86#define RK3036_DIV_HCLK_MASK 0x3
87#define RK3036_DIV_HCLK_SHIFT 8
88#define RK3036_DIV_PCLK_MASK 0x7
89#define RK3036_DIV_PCLK_SHIFT 12
90
91#define RK3036_CLKSEL1(_core_periph_div) \
92 { \
93 .reg = RK2928_CLKSEL_CON(1), \
94 .val = HIWORD_UPDATE(_core_periph_div, RK3036_DIV_PERI_MASK, \
95 RK3036_DIV_PERI_SHIFT) \
96 }
97
98#define RK3036_CPUCLK_RATE(_prate, _core_periph_div) \
99 { \
100 .prate = _prate, \
101 .divs = { \
102 RK3036_CLKSEL1(_core_periph_div), \
103 }, \
104 }
105
106static struct rockchip_cpuclk_rate_table rk3036_cpuclk_rates[] __initdata = {
107 RK3036_CPUCLK_RATE(816000000, 4),
108 RK3036_CPUCLK_RATE(600000000, 4),
109 RK3036_CPUCLK_RATE(312000000, 4),
110};
111
112static const struct rockchip_cpuclk_reg_data rk3036_cpuclk_data = {
113 .core_reg = RK2928_CLKSEL_CON(0),
114 .div_core_shift = 0,
115 .div_core_mask = 0x1f,
116 .mux_core_shift = 7,
117};
118
119PNAME(mux_pll_p) = { "xin24m", "xin24m" };
120
121PNAME(mux_armclk_p) = { "apll", "gpll_armclk" };
122PNAME(mux_busclk_p) = { "apll", "dpll_cpu", "gpll_cpu" };
123PNAME(mux_ddrphy_p) = { "dpll_ddr", "gpll_ddr" };
124PNAME(mux_pll_src_3plls_p) = { "apll", "dpll", "gpll" };
125PNAME(mux_timer_p) = { "xin24m", "pclk_peri_src" };
126
127PNAME(mux_pll_src_apll_dpll_gpll_usb480m_p) = { "apll", "dpll", "gpll" "usb480m" };
128
129PNAME(mux_mmc_src_p) = { "apll", "dpll", "gpll", "xin24m" };
130PNAME(mux_i2s_pre_p) = { "i2s_src", "i2s_frac", "ext_i2s", "xin12m" };
131PNAME(mux_i2s_clkout_p) = { "i2s_pre", "xin12m" };
132PNAME(mux_spdif_p) = { "spdif_src", "spdif_frac", "xin12m" };
133PNAME(mux_uart0_p) = { "uart0_src", "uart0_frac", "xin24m" };
134PNAME(mux_uart1_p) = { "uart1_src", "uart1_frac", "xin24m" };
135PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" };
136PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" };
137PNAME(mux_dclk_p) = { "dclk_lcdc", "dclk_cru" };
138
139static struct rockchip_pll_clock rk3036_pll_clks[] __initdata = {
140 [apll] = PLL(pll_rk3036, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
141 RK2928_MODE_CON, 0, 5, 0, rk3036_pll_rates),
142 [dpll] = PLL(pll_rk3036, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(4),
143 RK2928_MODE_CON, 4, 4, 0, NULL),
144 [gpll] = PLL(pll_rk3036, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(12),
145 RK2928_MODE_CON, 12, 6, ROCKCHIP_PLL_SYNC_RATE, rk3036_pll_rates),
146};
147
148#define MFLAGS CLK_MUX_HIWORD_MASK
149#define DFLAGS CLK_DIVIDER_HIWORD_MASK
150#define GFLAGS (CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE)
151
152static struct rockchip_clk_branch rk3036_clk_branches[] __initdata = {
153 /*
154 * Clock-Architecture Diagram 1
155 */
156
157 GATE(0, "gpll_armclk", "gpll", CLK_IGNORE_UNUSED,
158 RK2928_CLKGATE_CON(0), 6, GFLAGS),
159
160 /*
161 * Clock-Architecture Diagram 2
162 */
163
164 GATE(0, "dpll_ddr", "dpll", CLK_IGNORE_UNUSED,
165 RK2928_CLKGATE_CON(0), 2, GFLAGS),
166 GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED,
167 RK2928_CLKGATE_CON(0), 8, GFLAGS),
168 COMPOSITE_NOGATE(0, "ddrphy2x", mux_ddrphy_p, CLK_IGNORE_UNUSED,
169 RK2928_CLKSEL_CON(26), 8, 1, MFLAGS, 0, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
170
171 COMPOSITE_NOMUX(0, "pclk_dbg", "armclk", CLK_IGNORE_UNUSED,
172 RK2928_CLKSEL_CON(1), 0, 4, DFLAGS | CLK_DIVIDER_READ_ONLY,
173 RK2928_CLKGATE_CON(0), 7, GFLAGS),
174 COMPOSITE_NOMUX(0, "aclk_core_pre", "armclk", CLK_IGNORE_UNUSED,
175 RK2928_CLKSEL_CON(1), 4, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
176 RK2928_CLKGATE_CON(0), 7, GFLAGS),
177
178 GATE(0, "dpll_cpu", "dpll", 0, RK2928_CLKGATE_CON(10), 8, GFLAGS),
179 GATE(0, "gpll_cpu", "gpll", 0, RK2928_CLKGATE_CON(0), 1, GFLAGS),
180 COMPOSITE_NOGATE(0, "aclk_cpu_src", mux_busclk_p, 0,
181 RK2928_CLKSEL_CON(0), 14, 2, MFLAGS, 8, 5, DFLAGS),
182 GATE(ACLK_CPU, "aclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
183 RK2928_CLKGATE_CON(0), 3, GFLAGS),
184 COMPOSITE_NOMUX(PCLK_CPU, "pclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
185 RK2928_CLKSEL_CON(1), 12, 3, DFLAGS | CLK_DIVIDER_READ_ONLY,
186 RK2928_CLKGATE_CON(0), 5, GFLAGS),
187 COMPOSITE_NOMUX(HCLK_CPU, "hclk_cpu", "aclk_cpu_src", CLK_IGNORE_UNUSED,
188 RK2928_CLKSEL_CON(1), 8, 2, DFLAGS | CLK_DIVIDER_READ_ONLY,
189 RK2928_CLKGATE_CON(0), 4, GFLAGS),
190
191 COMPOSITE(0, "aclk_peri_src", mux_pll_src_3plls_p, 0,
192 RK2928_CLKSEL_CON(10), 14, 2, MFLAGS, 0, 5, DFLAGS,
193 RK2928_CLKGATE_CON(2), 0, GFLAGS),
194
195 GATE(ACLK_PERI, "aclk_peri", "aclk_peri_src", 0,
196 RK2928_CLKGATE_CON(2), 1, GFLAGS),
197 DIV(0, "pclk_peri_src", "aclk_peri_src", CLK_IGNORE_UNUSED,
198 RK2928_CLKSEL_CON(10), 12, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
199 GATE(PCLK_PERI, "pclk_peri", "pclk_peri_src", 0,
200 RK2928_CLKGATE_CON(2), 3, GFLAGS),
201 DIV(0, "hclk_peri_src", "aclk_peri_src", CLK_IGNORE_UNUSED,
202 RK2928_CLKSEL_CON(10), 8, 2, DFLAGS | CLK_DIVIDER_POWER_OF_TWO),
203 GATE(HCLK_PERI, "hclk_peri", "hclk_peri_src", 0,
204 RK2928_CLKGATE_CON(2), 2, GFLAGS),
205
206 COMPOSITE_NODIV(SCLK_TIMER0, "sclk_timer0", mux_timer_p, CLK_IGNORE_UNUSED,
207 RK2928_CLKSEL_CON(2), 4, 1, DFLAGS,
208 RK2928_CLKGATE_CON(1), 0, GFLAGS),
209 COMPOSITE_NODIV(SCLK_TIMER1, "sclk_timer1", mux_timer_p, CLK_IGNORE_UNUSED,
210 RK2928_CLKSEL_CON(2), 5, 1, DFLAGS,
211 RK2928_CLKGATE_CON(1), 1, GFLAGS),
212 COMPOSITE_NODIV(SCLK_TIMER2, "sclk_timer2", mux_timer_p, CLK_IGNORE_UNUSED,
213 RK2928_CLKSEL_CON(2), 6, 1, DFLAGS,
214 RK2928_CLKGATE_CON(2), 4, GFLAGS),
215 COMPOSITE_NODIV(SCLK_TIMER3, "sclk_timer3", mux_timer_p, CLK_IGNORE_UNUSED,
216 RK2928_CLKSEL_CON(2), 7, 1, DFLAGS,
217 RK2928_CLKGATE_CON(2), 5, GFLAGS),
218
219 MUX(0, "uart_pll_clk", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
220 RK2928_CLKSEL_CON(13), 10, 2, MFLAGS),
221 COMPOSITE_NOMUX(0, "uart0_src", "uart_pll_clk", 0,
222 RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
223 RK2928_CLKGATE_CON(1), 8, GFLAGS),
224 COMPOSITE_NOMUX(0, "uart1_src", "uart_pll_clk", 0,
225 RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
226 RK2928_CLKGATE_CON(1), 8, GFLAGS),
227 COMPOSITE_NOMUX(0, "uart2_src", "uart_pll_clk", 0,
228 RK2928_CLKSEL_CON(13), 0, 7, DFLAGS,
229 RK2928_CLKGATE_CON(1), 8, GFLAGS),
230 COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
231 RK2928_CLKSEL_CON(17), 0,
232 RK2928_CLKGATE_CON(1), 9, GFLAGS),
233 COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
234 RK2928_CLKSEL_CON(18), 0,
235 RK2928_CLKGATE_CON(1), 11, GFLAGS),
236 COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
237 RK2928_CLKSEL_CON(19), 0,
238 RK2928_CLKGATE_CON(1), 13, GFLAGS),
239 MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
240 RK2928_CLKSEL_CON(13), 8, 2, MFLAGS),
241 MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
242 RK2928_CLKSEL_CON(14), 8, 2, MFLAGS),
243 MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
244 RK2928_CLKSEL_CON(15), 8, 2, MFLAGS),
245
246 COMPOSITE(0, "aclk_vcodec", mux_pll_src_3plls_p, 0,
247 RK2928_CLKSEL_CON(32), 14, 2, MFLAGS, 8, 5, DFLAGS,
248 RK2928_CLKGATE_CON(3), 11, GFLAGS),
249
250 COMPOSITE(0, "aclk_hvec", mux_pll_src_3plls_p, 0,
251 RK2928_CLKSEL_CON(20), 0, 2, MFLAGS, 2, 5, DFLAGS,
252 RK2928_CLKGATE_CON(10), 6, GFLAGS),
253
254 COMPOSITE(0, "aclk_disp1_pre", mux_pll_src_3plls_p, 0,
255 RK2928_CLKSEL_CON(31), 14, 2, MFLAGS, 8, 5, DFLAGS,
256 RK2928_CLKGATE_CON(1), 4, GFLAGS),
257 COMPOSITE(0, "hclk_disp_pre", mux_pll_src_3plls_p, 0,
258 RK2928_CLKSEL_CON(30), 14, 2, MFLAGS, 8, 5, DFLAGS,
259 RK2928_CLKGATE_CON(0), 11, GFLAGS),
260 COMPOSITE(SCLK_LCDC, "dclk_lcdc", mux_pll_src_3plls_p, 0,
261 RK2928_CLKSEL_CON(28), 0, 2, MFLAGS, 8, 8, DFLAGS,
262 RK2928_CLKGATE_CON(3), 2, GFLAGS),
263
264 COMPOSITE_NODIV(0, "sclk_sdmmc_src", mux_mmc_src_p, 0,
265 RK2928_CLKSEL_CON(12), 8, 2, DFLAGS,
266 RK2928_CLKGATE_CON(2), 11, GFLAGS),
267 DIV(SCLK_SDMMC, "sclk_sdmmc", "sclk_sdmmc_src", 0,
268 RK2928_CLKSEL_CON(11), 0, 7, DFLAGS),
269
270 COMPOSITE_NODIV(0, "sclk_sdio_src", mux_mmc_src_p, 0,
271 RK2928_CLKSEL_CON(12), 10, 2, DFLAGS,
272 RK2928_CLKGATE_CON(2), 13, GFLAGS),
273 DIV(SCLK_SDIO, "sclk_sdio", "sclk_sdio_src", 0,
274 RK2928_CLKSEL_CON(11), 8, 7, DFLAGS),
275
276 COMPOSITE(SCLK_EMMC, "sclk_emmc", mux_mmc_src_p, 0,
277 RK2928_CLKSEL_CON(12), 12, 2, MFLAGS, 0, 7, DFLAGS,
278 RK2928_CLKGATE_CON(2), 14, GFLAGS),
279
280 MMC(SCLK_SDMMC_DRV, "sdmmc_drv", "sclk_sdmmc", RK3036_SDMMC_CON0, 1),
281 MMC(SCLK_SDMMC_SAMPLE, "sdmmc_sample", "sclk_sdmmc", RK3036_SDMMC_CON1, 0),
282
283 MMC(SCLK_SDIO_DRV, "sdio_drv", "sclk_sdio", RK3036_SDIO_CON0, 1),
284 MMC(SCLK_SDIO_SAMPLE, "sdio_sample", "sclk_sdio", RK3036_SDIO_CON1, 0),
285
286 MMC(SCLK_EMMC_DRV, "emmc_drv", "sclk_emmc", RK3036_EMMC_CON0, 1),
287 MMC(SCLK_EMMC_SAMPLE, "emmc_sample", "sclk_emmc", RK3036_EMMC_CON1, 0),
288
289 COMPOSITE(0, "i2s_src", mux_pll_src_3plls_p, 0,
290 RK2928_CLKSEL_CON(3), 14, 2, MFLAGS, 0, 7, DFLAGS,
291 RK2928_CLKGATE_CON(0), 9, GFLAGS),
292 COMPOSITE_FRAC(0, "i2s_frac", "i2s_src", CLK_SET_RATE_PARENT,
293 RK2928_CLKSEL_CON(7), 0,
294 RK2928_CLKGATE_CON(0), 10, GFLAGS),
295 MUX(0, "i2s_pre", mux_i2s_pre_p, CLK_SET_RATE_PARENT,
296 RK2928_CLKSEL_CON(3), 8, 2, MFLAGS),
297 COMPOSITE_NODIV(SCLK_I2S_OUT, "i2s_clkout", mux_i2s_clkout_p, 0,
298 RK2928_CLKSEL_CON(3), 12, 1, MFLAGS,
299 RK2928_CLKGATE_CON(0), 13, GFLAGS),
300 GATE(SCLK_I2S, "sclk_i2s", "i2s_pre", CLK_SET_RATE_PARENT,
301 RK2928_CLKGATE_CON(0), 14, GFLAGS),
302
303 COMPOSITE(0, "spdif_src", mux_pll_src_3plls_p, 0,
304 RK2928_CLKSEL_CON(5), 10, 2, MFLAGS, 0, 7, DFLAGS,
305 RK2928_CLKGATE_CON(2), 10, GFLAGS),
306 COMPOSITE_FRAC(0, "spdif_frac", "spdif_src", 0,
307 RK2928_CLKSEL_CON(9), 0,
308 RK2928_CLKGATE_CON(2), 12, GFLAGS),
309 MUX(SCLK_SPDIF, "sclk_spdif", mux_spdif_p, 0,
310 RK2928_CLKSEL_CON(5), 8, 2, MFLAGS),
311
312 GATE(SCLK_OTGPHY0, "sclk_otgphy0", "xin12m", CLK_IGNORE_UNUSED,
313 RK2928_CLKGATE_CON(1), 5, GFLAGS),
314
315 COMPOSITE(SCLK_GPU, "sclk_gpu", mux_pll_src_3plls_p, 0,
316 RK2928_CLKSEL_CON(34), 8, 2, MFLAGS, 0, 5, DFLAGS,
317 RK2928_CLKGATE_CON(3), 13, GFLAGS),
318
319 COMPOSITE(SCLK_SPI, "sclk_spi", mux_pll_src_3plls_p, 0,
320 RK2928_CLKSEL_CON(25), 8, 2, MFLAGS, 0, 7, DFLAGS,
321 RK2928_CLKGATE_CON(2), 9, GFLAGS),
322
323 COMPOSITE(SCLK_NANDC, "sclk_nandc", mux_pll_src_3plls_p, 0,
324 RK2928_CLKSEL_CON(16), 8, 2, MFLAGS, 10, 5, DFLAGS,
325 RK2928_CLKGATE_CON(10), 4, GFLAGS),
326
327 COMPOSITE(SCLK_SFC, "sclk_sfc", mux_pll_src_apll_dpll_gpll_usb480m_p, 0,
328 RK2928_CLKSEL_CON(16), 0, 2, MFLAGS, 2, 5, DFLAGS,
329 RK2928_CLKGATE_CON(10), 5, GFLAGS),
330
331 COMPOSITE_NOGATE(0, "mac_pll_src", mux_pll_src_3plls_p, 0,
332 RK2928_CLKSEL_CON(21), 0, 2, MFLAGS, 4, 5, DFLAGS),
333 MUX(SCLK_MACREF, "mac_clk_ref", mux_mac_p, CLK_SET_RATE_PARENT,
334 RK2928_CLKSEL_CON(21), 3, 1, MFLAGS),
335
336 COMPOSITE_NOMUX(SCLK_MAC, "mac_clk", "mac_clk_ref", 0,
337 RK2928_CLKSEL_CON(21), 9, 5, DFLAGS,
338 RK2928_CLKGATE_CON(2), 6, GFLAGS),
339
340 MUX(SCLK_HDMI, "dclk_hdmi", mux_dclk_p, 0,
341 RK2928_CLKSEL_CON(31), 0, 1, MFLAGS),
342
343 /*
344 * Clock-Architecture Diagram 3
345 */
346
347 /* aclk_cpu gates */
348 GATE(0, "sclk_intmem", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 12, GFLAGS),
349 GATE(0, "aclk_strc_sys", "aclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 10, GFLAGS),
350
351 /* hclk_cpu gates */
352 GATE(HCLK_ROM, "hclk_rom", "hclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 6, GFLAGS),
353
354 /* pclk_cpu gates */
355 GATE(PCLK_GRF, "pclk_grf", "pclk_cpu", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 4, GFLAGS),
356 GATE(PCLK_DDRUPCTL, "pclk_ddrupctl", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 7, GFLAGS),
357 GATE(PCLK_ACODEC, "pclk_acodec", "pclk_cpu", 0, RK2928_CLKGATE_CON(5), 14, GFLAGS),
358 GATE(PCLK_HDMI, "pclk_hdmi", "pclk_cpu", 0, RK2928_CLKGATE_CON(3), 8, GFLAGS),
359
360 /* aclk_vio gates */
361 GATE(ACLK_VIO, "aclk_vio", "aclk_disp1_pre", 0, RK2928_CLKGATE_CON(6), 13, GFLAGS),
362 GATE(ACLK_LCDC, "aclk_lcdc", "aclk_disp1_pre", 0, RK2928_CLKGATE_CON(9), 6, GFLAGS),
363
364 GATE(HCLK_VIO_BUS, "hclk_vio_bus", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(6), 12, GFLAGS),
365 GATE(HCLK_LCDC, "hclk_lcdc", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(9), 5, GFLAGS),
366
367 /* hclk_video gates */
368 GATE(HCLK_VCODEC, "hclk_vcodec", "hclk_disp_pre", 0, RK2928_CLKGATE_CON(3), 12, GFLAGS),
369
370 /* xin24m gates */
371 GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK2928_CLKGATE_CON(10), 0, GFLAGS),
372 GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK2928_CLKGATE_CON(10), 1, GFLAGS),
373
374 /* aclk_peri gates */
375 GATE(0, "aclk_peri_axi_matrix", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 3, GFLAGS),
376 GATE(0, "aclk_cpu_peri", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 2, GFLAGS),
377 GATE(ACLK_DMAC2, "aclk_dmac2", "aclk_peri", 0, RK2928_CLKGATE_CON(5), 1, GFLAGS),
378 GATE(0, "aclk_peri_niu", "aclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 15, GFLAGS),
379
380 /* hclk_peri gates */
381 GATE(0, "hclk_peri_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 0, GFLAGS),
382 GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 13, GFLAGS),
383 GATE(0, "hclk_peri_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(9), 14, GFLAGS),
384 GATE(HCLK_NANDC, "hclk_nandc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 9, GFLAGS),
385 GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 10, GFLAGS),
386 GATE(HCLK_SDIO, "hclk_sdio", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 11, GFLAGS),
387 GATE(HCLK_EMMC, "hclk_emmc", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 0, GFLAGS),
388 GATE(HCLK_OTG0, "hclk_otg0", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 13, GFLAGS),
389 GATE(HCLK_OTG1, "hclk_otg1", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(7), 3, GFLAGS),
390 GATE(HCLK_I2S, "hclk_i2s", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 2, GFLAGS),
391 GATE(0, "hclk_sfc", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 14, GFLAGS),
392 GATE(0, "hclk_mac", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(3), 15, GFLAGS),
393
394 /* pclk_peri gates */
395 GATE(0, "pclk_peri_matrix", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 1, GFLAGS),
396 GATE(0, "pclk_efuse", "pclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 2, GFLAGS),
397 GATE(PCLK_TIMER, "pclk_timer", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 7, GFLAGS),
398 GATE(PCLK_PWM, "pclk_pwm", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 10, GFLAGS),
399 GATE(PCLK_SPI, "pclk_spi", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 12, GFLAGS),
400 GATE(PCLK_WDT, "pclk_wdt", "pclk_peri", 0, RK2928_CLKGATE_CON(7), 15, GFLAGS),
401 GATE(PCLK_UART0, "pclk_uart0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 0, GFLAGS),
402 GATE(PCLK_UART1, "pclk_uart1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 1, GFLAGS),
403 GATE(PCLK_UART2, "pclk_uart2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 2, GFLAGS),
404 GATE(PCLK_I2C0, "pclk_i2c0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 4, GFLAGS),
405 GATE(PCLK_I2C1, "pclk_i2c1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 5, GFLAGS),
406 GATE(PCLK_I2C2, "pclk_i2c2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 6, GFLAGS),
407 GATE(PCLK_GPIO0, "pclk_gpio0", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 9, GFLAGS),
408 GATE(PCLK_GPIO1, "pclk_gpio1", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 10, GFLAGS),
409 GATE(PCLK_GPIO2, "pclk_gpio2", "pclk_peri", 0, RK2928_CLKGATE_CON(8), 11, GFLAGS),
410};
411
412static const char *const rk3036_critical_clocks[] __initconst = {
413 "aclk_cpu",
414 "aclk_peri",
415 "hclk_peri",
416 "pclk_peri",
417};
418
419static void __init rk3036_clk_init(struct device_node *np)
420{
421 void __iomem *reg_base;
422 struct clk *clk;
423
424 reg_base = of_iomap(np, 0);
425 if (!reg_base) {
426 pr_err("%s: could not map cru region\n", __func__);
427 return;
428 }
429
430 rockchip_clk_init(np, reg_base, CLK_NR_CLKS);
431
432 /* xin12m is created by an cru-internal divider */
433 clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
434 if (IS_ERR(clk))
435 pr_warn("%s: could not register clock xin12m: %ld\n",
436 __func__, PTR_ERR(clk));
437
438 clk = clk_register_fixed_factor(NULL, "usb480m", "xin24m", 0, 20, 1);
439 if (IS_ERR(clk))
440 pr_warn("%s: could not register clock usb480m: %ld\n",
441 __func__, PTR_ERR(clk));
442
443 clk = clk_register_fixed_factor(NULL, "ddrphy", "ddrphy2x", 0, 1, 2);
444 if (IS_ERR(clk))
445 pr_warn("%s: could not register clock ddrphy: %ld\n",
446 __func__, PTR_ERR(clk));
447
448 clk = clk_register_fixed_factor(NULL, "hclk_vcodec_pre",
449 "aclk_vcodec", 0, 1, 4);
450 if (IS_ERR(clk))
451 pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n",
452 __func__, PTR_ERR(clk));
453
454 clk = clk_register_fixed_factor(NULL, "sclk_macref_out",
455 "hclk_peri_src", 0, 1, 2);
456 if (IS_ERR(clk))
457 pr_warn("%s: could not register clock sclk_macref_out: %ld\n",
458 __func__, PTR_ERR(clk));
459
460 rockchip_clk_register_plls(rk3036_pll_clks,
461 ARRAY_SIZE(rk3036_pll_clks),
462 RK3036_GRF_SOC_STATUS0);
463 rockchip_clk_register_branches(rk3036_clk_branches,
464 ARRAY_SIZE(rk3036_clk_branches));
465 rockchip_clk_protect_critical(rk3036_critical_clocks,
466 ARRAY_SIZE(rk3036_critical_clocks));
467
468 rockchip_clk_register_armclk(ARMCLK, "armclk",
469 mux_armclk_p, ARRAY_SIZE(mux_armclk_p),
470 &rk3036_cpuclk_data, rk3036_cpuclk_rates,
471 ARRAY_SIZE(rk3036_cpuclk_rates));
472
473 rockchip_register_softrst(np, 9, reg_base + RK2928_SOFTRST_CON(0),
474 ROCKCHIP_SOFTRST_HIWORD_MASK);
475
476 rockchip_register_restart_notifier(RK2928_GLB_SRST_FST);
477}
478CLK_OF_DECLARE(rk3036_cru, "rockchip,rk3036-cru", rk3036_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 9040878e3e2b..d613ad96ef70 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -295,7 +295,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
295 RK3288_CLKGATE_CON(0), 4, GFLAGS), 295 RK3288_CLKGATE_CON(0), 4, GFLAGS),
296 GATE(0, "c2c_host", "aclk_cpu_src", 0, 296 GATE(0, "c2c_host", "aclk_cpu_src", 0,
297 RK3288_CLKGATE_CON(13), 8, GFLAGS), 297 RK3288_CLKGATE_CON(13), 8, GFLAGS),
298 COMPOSITE_NOMUX(0, "crypto", "aclk_cpu_pre", 0, 298 COMPOSITE_NOMUX(SCLK_CRYPTO, "crypto", "aclk_cpu_pre", 0,
299 RK3288_CLKSEL_CON(26), 6, 2, DFLAGS, 299 RK3288_CLKSEL_CON(26), 6, 2, DFLAGS,
300 RK3288_CLKGATE_CON(5), 4, GFLAGS), 300 RK3288_CLKGATE_CON(5), 4, GFLAGS),
301 GATE(0, "aclk_bus_2pmu", "aclk_cpu_pre", CLK_IGNORE_UNUSED, 301 GATE(0, "aclk_bus_2pmu", "aclk_cpu_pre", CLK_IGNORE_UNUSED,
@@ -709,7 +709,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
709 GATE(SCLK_LCDC_PWM1, "sclk_lcdc_pwm1", "xin24m", 0, RK3288_CLKGATE_CON(13), 11, GFLAGS), 709 GATE(SCLK_LCDC_PWM1, "sclk_lcdc_pwm1", "xin24m", 0, RK3288_CLKGATE_CON(13), 11, GFLAGS),
710 GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS), 710 GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
711 GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS), 711 GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
712 GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS), 712 GATE(SCLK_MIPIDSI_24M, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
713 713
714 /* sclk_gpu gates */ 714 /* sclk_gpu gates */
715 GATE(ACLK_GPU, "aclk_gpu", "sclk_gpu", 0, RK3288_CLKGATE_CON(18), 0, GFLAGS), 715 GATE(ACLK_GPU, "aclk_gpu", "sclk_gpu", 0, RK3288_CLKGATE_CON(18), 0, GFLAGS),
@@ -783,10 +783,10 @@ static const char *const rk3288_critical_clocks[] __initconst = {
783 "pclk_pd_pmu", 783 "pclk_pd_pmu",
784}; 784};
785 785
786#ifdef CONFIG_PM_SLEEP
787static void __iomem *rk3288_cru_base; 786static void __iomem *rk3288_cru_base;
788 787
789/* Some CRU registers will be reset in maskrom when the system 788/*
789 * Some CRU registers will be reset in maskrom when the system
790 * wakes up from fastboot. 790 * wakes up from fastboot.
791 * So save them before suspend, restore them after resume. 791 * So save them before suspend, restore them after resume.
792 */ 792 */
@@ -840,33 +840,28 @@ static void rk3288_clk_resume(void)
840 } 840 }
841} 841}
842 842
843static void rk3288_clk_shutdown(void)
844{
845 writel_relaxed(0xf3030000, rk3288_cru_base + RK3288_MODE_CON);
846}
847
843static struct syscore_ops rk3288_clk_syscore_ops = { 848static struct syscore_ops rk3288_clk_syscore_ops = {
844 .suspend = rk3288_clk_suspend, 849 .suspend = rk3288_clk_suspend,
845 .resume = rk3288_clk_resume, 850 .resume = rk3288_clk_resume,
851 .shutdown = rk3288_clk_shutdown,
846}; 852};
847 853
848static void rk3288_clk_sleep_init(void __iomem *reg_base)
849{
850 rk3288_cru_base = reg_base;
851 register_syscore_ops(&rk3288_clk_syscore_ops);
852}
853
854#else /* CONFIG_PM_SLEEP */
855static void rk3288_clk_sleep_init(void __iomem *reg_base) {}
856#endif
857
858static void __init rk3288_clk_init(struct device_node *np) 854static void __init rk3288_clk_init(struct device_node *np)
859{ 855{
860 void __iomem *reg_base;
861 struct clk *clk; 856 struct clk *clk;
862 857
863 reg_base = of_iomap(np, 0); 858 rk3288_cru_base = of_iomap(np, 0);
864 if (!reg_base) { 859 if (!rk3288_cru_base) {
865 pr_err("%s: could not map cru region\n", __func__); 860 pr_err("%s: could not map cru region\n", __func__);
866 return; 861 return;
867 } 862 }
868 863
869 rockchip_clk_init(np, reg_base, CLK_NR_CLKS); 864 rockchip_clk_init(np, rk3288_cru_base, CLK_NR_CLKS);
870 865
871 /* xin12m is created by an cru-internal divider */ 866 /* xin12m is created by an cru-internal divider */
872 clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2); 867 clk = clk_register_fixed_factor(NULL, "xin12m", "xin24m", 0, 1, 2);
@@ -907,10 +902,11 @@ static void __init rk3288_clk_init(struct device_node *np)
907 &rk3288_cpuclk_data, rk3288_cpuclk_rates, 902 &rk3288_cpuclk_data, rk3288_cpuclk_rates,
908 ARRAY_SIZE(rk3288_cpuclk_rates)); 903 ARRAY_SIZE(rk3288_cpuclk_rates));
909 904
910 rockchip_register_softrst(np, 12, reg_base + RK3288_SOFTRST_CON(0), 905 rockchip_register_softrst(np, 12,
906 rk3288_cru_base + RK3288_SOFTRST_CON(0),
911 ROCKCHIP_SOFTRST_HIWORD_MASK); 907 ROCKCHIP_SOFTRST_HIWORD_MASK);
912 908
913 rockchip_register_restart_notifier(RK3288_GLB_SRST_FST); 909 rockchip_register_restart_notifier(RK3288_GLB_SRST_FST);
914 rk3288_clk_sleep_init(reg_base); 910 register_syscore_ops(&rk3288_clk_syscore_ops);
915} 911}
916CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); 912CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init);
diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c
index 7e6b783e6eee..1faf1602a3fc 100644
--- a/drivers/clk/rockchip/clk-rk3368.c
+++ b/drivers/clk/rockchip/clk-rk3368.c
@@ -184,13 +184,13 @@ static const struct rockchip_cpuclk_reg_data rk3368_cpuclkl_data = {
184 184
185#define RK3368_CLKSEL0(_offs, _aclkm) \ 185#define RK3368_CLKSEL0(_offs, _aclkm) \
186 { \ 186 { \
187 .reg = RK3288_CLKSEL_CON(0 + _offs), \ 187 .reg = RK3368_CLKSEL_CON(0 + _offs), \
188 .val = HIWORD_UPDATE(_aclkm, RK3368_DIV_ACLKM_MASK, \ 188 .val = HIWORD_UPDATE(_aclkm, RK3368_DIV_ACLKM_MASK, \
189 RK3368_DIV_ACLKM_SHIFT), \ 189 RK3368_DIV_ACLKM_SHIFT), \
190 } 190 }
191#define RK3368_CLKSEL1(_offs, _atclk, _pdbg) \ 191#define RK3368_CLKSEL1(_offs, _atclk, _pdbg) \
192 { \ 192 { \
193 .reg = RK3288_CLKSEL_CON(1 + _offs), \ 193 .reg = RK3368_CLKSEL_CON(1 + _offs), \
194 .val = HIWORD_UPDATE(_atclk, RK3368_DIV_ATCLK_MASK, \ 194 .val = HIWORD_UPDATE(_atclk, RK3368_DIV_ATCLK_MASK, \
195 RK3368_DIV_ATCLK_SHIFT) | \ 195 RK3368_DIV_ATCLK_SHIFT) | \
196 HIWORD_UPDATE(_pdbg, RK3368_DIV_PCLK_DBG_MASK, \ 196 HIWORD_UPDATE(_pdbg, RK3368_DIV_PCLK_DBG_MASK, \
@@ -819,6 +819,13 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = {
819}; 819};
820 820
821static const char *const rk3368_critical_clocks[] __initconst = { 821static const char *const rk3368_critical_clocks[] __initconst = {
822 "aclk_bus",
823 "aclk_peri",
824 /*
825 * pwm1 supplies vdd_logic on a lot of boards, is currently unhandled
826 * but needs to stay enabled there (including its parents) at all times.
827 */
828 "pclk_pwm1",
822 "pclk_pd_pmu", 829 "pclk_pd_pmu",
823}; 830};
824 831
diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
index dc8ecb2673b7..8d8f942ae7fc 100644
--- a/drivers/clk/rockchip/clk.h
+++ b/drivers/clk/rockchip/clk.h
@@ -2,6 +2,9 @@
2 * Copyright (c) 2014 MundoReader S.L. 2 * Copyright (c) 2014 MundoReader S.L.
3 * Author: Heiko Stuebner <heiko@sntech.de> 3 * Author: Heiko Stuebner <heiko@sntech.de>
4 * 4 *
5 * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
6 * Author: Xing Zheng <zhengxing@rock-chips.com>
7 *
5 * based on 8 * based on
6 * 9 *
7 * samsung/clk.h 10 * samsung/clk.h
@@ -30,7 +33,7 @@ struct clk;
30#define HIWORD_UPDATE(val, mask, shift) \ 33#define HIWORD_UPDATE(val, mask, shift) \
31 ((val) << (shift) | (mask) << ((shift) + 16)) 34 ((val) << (shift) | (mask) << ((shift) + 16))
32 35
33/* register positions shared by RK2928, RK3066 and RK3188 */ 36/* register positions shared by RK2928, RK3036, RK3066 and RK3188 */
34#define RK2928_PLL_CON(x) ((x) * 0x4) 37#define RK2928_PLL_CON(x) ((x) * 0x4)
35#define RK2928_MODE_CON 0x40 38#define RK2928_MODE_CON 0x40
36#define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44) 39#define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44)
@@ -40,6 +43,13 @@ struct clk;
40#define RK2928_SOFTRST_CON(x) ((x) * 0x4 + 0x110) 43#define RK2928_SOFTRST_CON(x) ((x) * 0x4 + 0x110)
41#define RK2928_MISC_CON 0x134 44#define RK2928_MISC_CON 0x134
42 45
46#define RK3036_SDMMC_CON0 0x144
47#define RK3036_SDMMC_CON1 0x148
48#define RK3036_SDIO_CON0 0x14c
49#define RK3036_SDIO_CON1 0x150
50#define RK3036_EMMC_CON0 0x154
51#define RK3036_EMMC_CON1 0x158
52
43#define RK3288_PLL_CON(x) RK2928_PLL_CON(x) 53#define RK3288_PLL_CON(x) RK2928_PLL_CON(x)
44#define RK3288_MODE_CON 0x50 54#define RK3288_MODE_CON 0x50
45#define RK3288_CLKSEL_CON(x) ((x) * 0x4 + 0x60) 55#define RK3288_CLKSEL_CON(x) ((x) * 0x4 + 0x60)
@@ -74,9 +84,22 @@ struct clk;
74#define RK3368_EMMC_CON1 0x41c 84#define RK3368_EMMC_CON1 0x41c
75 85
76enum rockchip_pll_type { 86enum rockchip_pll_type {
87 pll_rk3036,
77 pll_rk3066, 88 pll_rk3066,
78}; 89};
79 90
91#define RK3036_PLL_RATE(_rate, _refdiv, _fbdiv, _postdiv1, \
92 _postdiv2, _dsmpd, _frac) \
93{ \
94 .rate = _rate##U, \
95 .fbdiv = _fbdiv, \
96 .postdiv1 = _postdiv1, \
97 .refdiv = _refdiv, \
98 .postdiv2 = _postdiv2, \
99 .dsmpd = _dsmpd, \
100 .frac = _frac, \
101}
102
80#define RK3066_PLL_RATE(_rate, _nr, _nf, _no) \ 103#define RK3066_PLL_RATE(_rate, _nr, _nf, _no) \
81{ \ 104{ \
82 .rate = _rate##U, \ 105 .rate = _rate##U, \
@@ -101,6 +124,13 @@ struct rockchip_pll_rate_table {
101 unsigned int nf; 124 unsigned int nf;
102 unsigned int no; 125 unsigned int no;
103 unsigned int nb; 126 unsigned int nb;
127 /* for RK3036 */
128 unsigned int fbdiv;
129 unsigned int postdiv1;
130 unsigned int refdiv;
131 unsigned int postdiv2;
132 unsigned int dsmpd;
133 unsigned int frac;
104}; 134};
105 135
106/** 136/**