diff options
Diffstat (limited to 'arch/sh/kernel/cpu/sh4a/clock-sh7786.c')
-rw-r--r-- | arch/sh/kernel/cpu/sh4a/clock-sh7786.c | 314 |
1 files changed, 223 insertions, 91 deletions
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c index a0e8869071ac..42e403be9076 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7786.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7786.c | |||
@@ -3,11 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SH7786 support for the clock framework | 4 | * SH7786 support for the clock framework |
5 | * | 5 | * |
6 | * Copyright (C) 2008, 2009 Renesas Solutions Corp. | 6 | * Copyright (C) 2010 Paul Mundt |
7 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
8 | * | ||
9 | * Based on SH7785 | ||
10 | * Copyright (C) 2007 Paul Mundt | ||
11 | * | 7 | * |
12 | * This file is subject to the terms and conditions of the GNU General Public | 8 | * This file is subject to the terms and conditions of the GNU General Public |
13 | * License. See the file "COPYING" in the main directory of this archive | 9 | * License. See the file "COPYING" in the main directory of this archive |
@@ -15,127 +11,263 @@ | |||
15 | */ | 11 | */ |
16 | #include <linux/init.h> | 12 | #include <linux/init.h> |
17 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/clk.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/clkdev.h> | ||
18 | #include <asm/clock.h> | 17 | #include <asm/clock.h> |
19 | #include <asm/freq.h> | 18 | #include <asm/freq.h> |
20 | #include <asm/io.h> | ||
21 | 19 | ||
22 | static int ifc_divisors[] = { 1, 2, 4, 1 }; | 20 | /* |
23 | static int sfc_divisors[] = { 1, 1, 4, 1 }; | 21 | * Default rate for the root input clock, reset this with clk_set_rate() |
24 | static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 1, | 22 | * from the platform code. |
25 | 24, 32, 1, 1, 1, 1, 1, 1 }; | 23 | */ |
26 | static int mfc_divisors[] = { 1, 1, 4, 1 }; | 24 | static struct clk extal_clk = { |
27 | static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 16, 1, | 25 | .rate = 33333333, |
28 | 24, 32, 1, 48, 1, 1, 1, 1 }; | 26 | }; |
29 | 27 | ||
30 | static void master_clk_init(struct clk *clk) | 28 | static unsigned long pll_recalc(struct clk *clk) |
31 | { | 29 | { |
32 | clk->rate *= pfc_divisors[ctrl_inl(FRQMR1) & 0x000f]; | 30 | int multiplier; |
33 | } | ||
34 | 31 | ||
35 | static struct clk_ops sh7786_master_clk_ops = { | 32 | /* |
36 | .init = master_clk_init, | 33 | * Clock modes 0, 1, and 2 use an x64 multiplier against PLL1, |
37 | }; | 34 | * while modes 3, 4, and 5 use an x32. |
35 | */ | ||
36 | multiplier = (sh_mv.mv_mode_pins() & 0xf) < 3 ? 64 : 32; | ||
38 | 37 | ||
39 | static unsigned long module_clk_recalc(struct clk *clk) | 38 | return clk->parent->rate * multiplier; |
40 | { | ||
41 | int idx = (ctrl_inl(FRQMR1) & 0x000f); | ||
42 | return clk->parent->rate / pfc_divisors[idx]; | ||
43 | } | 39 | } |
44 | 40 | ||
45 | static struct clk_ops sh7786_module_clk_ops = { | 41 | static struct clk_ops pll_clk_ops = { |
46 | .recalc = module_clk_recalc, | 42 | .recalc = pll_recalc, |
47 | }; | 43 | }; |
48 | 44 | ||
49 | static unsigned long bus_clk_recalc(struct clk *clk) | 45 | static struct clk pll_clk = { |
50 | { | 46 | .ops = &pll_clk_ops, |
51 | int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f); | 47 | .parent = &extal_clk, |
52 | return clk->parent->rate / bfc_divisors[idx]; | 48 | .flags = CLK_ENABLE_ON_INIT, |
53 | } | 49 | }; |
54 | 50 | ||
55 | static struct clk_ops sh7786_bus_clk_ops = { | 51 | static struct clk *clks[] = { |
56 | .recalc = bus_clk_recalc, | 52 | &extal_clk, |
53 | &pll_clk, | ||
57 | }; | 54 | }; |
58 | 55 | ||
59 | static unsigned long cpu_clk_recalc(struct clk *clk) | 56 | static unsigned int div2[] = { 1, 2, 4, 6, 8, 12, 16, 18, |
60 | { | 57 | 24, 32, 36, 48 }; |
61 | int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003); | ||
62 | return clk->parent->rate / ifc_divisors[idx]; | ||
63 | } | ||
64 | 58 | ||
65 | static struct clk_ops sh7786_cpu_clk_ops = { | 59 | static struct clk_div_mult_table div4_div_mult_table = { |
66 | .recalc = cpu_clk_recalc, | 60 | .divisors = div2, |
61 | .nr_divisors = ARRAY_SIZE(div2), | ||
67 | }; | 62 | }; |
68 | 63 | ||
69 | static struct clk_ops *sh7786_clk_ops[] = { | 64 | static struct clk_div4_table div4_table = { |
70 | &sh7786_master_clk_ops, | 65 | .div_mult_table = &div4_div_mult_table, |
71 | &sh7786_module_clk_ops, | ||
72 | &sh7786_bus_clk_ops, | ||
73 | &sh7786_cpu_clk_ops, | ||
74 | }; | 66 | }; |
75 | 67 | ||
76 | void __init arch_init_clk_ops(struct clk_ops **ops, int idx) | 68 | enum { DIV4_I, DIV4_SH, DIV4_B, DIV4_DDR, DIV4_DU, DIV4_P, DIV4_NR }; |
77 | { | ||
78 | if (idx < ARRAY_SIZE(sh7786_clk_ops)) | ||
79 | *ops = sh7786_clk_ops[idx]; | ||
80 | } | ||
81 | 69 | ||
82 | static unsigned long shyway_clk_recalc(struct clk *clk) | 70 | #define DIV4(_bit, _mask, _flags) \ |
83 | { | 71 | SH_CLK_DIV4(&pll_clk, FRQMR1, _bit, _mask, _flags) |
84 | int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003); | ||
85 | return clk->parent->rate / sfc_divisors[idx]; | ||
86 | } | ||
87 | 72 | ||
88 | static struct clk_ops sh7786_shyway_clk_ops = { | 73 | struct clk div4_clks[DIV4_NR] = { |
89 | .recalc = shyway_clk_recalc, | 74 | [DIV4_P] = DIV4(0, 0x0b40, 0), |
75 | [DIV4_DU] = DIV4(4, 0x0010, 0), | ||
76 | [DIV4_DDR] = DIV4(12, 0x0002, CLK_ENABLE_ON_INIT), | ||
77 | [DIV4_B] = DIV4(16, 0x0360, CLK_ENABLE_ON_INIT), | ||
78 | [DIV4_SH] = DIV4(20, 0x0002, CLK_ENABLE_ON_INIT), | ||
79 | [DIV4_I] = DIV4(28, 0x0006, CLK_ENABLE_ON_INIT), | ||
90 | }; | 80 | }; |
91 | 81 | ||
92 | static struct clk sh7786_shyway_clk = { | 82 | #define MSTPCR0 0xffc40030 |
93 | .name = "shyway_clk", | 83 | #define MSTPCR1 0xffc40034 |
94 | .flags = CLK_ENABLE_ON_INIT, | ||
95 | .ops = &sh7786_shyway_clk_ops, | ||
96 | }; | ||
97 | 84 | ||
98 | static unsigned long ddr_clk_recalc(struct clk *clk) | 85 | enum { MSTP029, MSTP028, MSTP027, MSTP026, MSTP025, MSTP024, |
99 | { | 86 | MSTP023, MSTP022, MSTP021, MSTP020, MSTP017, MSTP016, |
100 | int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003); | 87 | MSTP015, MSTP014, MSTP011, MSTP010, MSTP009, MSTP008, |
101 | return clk->parent->rate / mfc_divisors[idx]; | 88 | MSTP005, MSTP004, MSTP002, |
102 | } | 89 | MSTP112, MSTP110, MSTP109, MSTP108, |
90 | MSTP105, MSTP104, MSTP103, MSTP102, | ||
91 | MSTP_NR }; | ||
103 | 92 | ||
104 | static struct clk_ops sh7786_ddr_clk_ops = { | 93 | static struct clk mstp_clks[MSTP_NR] = { |
105 | .recalc = ddr_clk_recalc, | 94 | /* MSTPCR0 */ |
106 | }; | 95 | [MSTP029] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 29, 0), |
96 | [MSTP028] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 28, 0), | ||
97 | [MSTP027] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 27, 0), | ||
98 | [MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0), | ||
99 | [MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0), | ||
100 | [MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0), | ||
101 | [MSTP023] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 23, 0), | ||
102 | [MSTP022] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 22, 0), | ||
103 | [MSTP021] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 21, 0), | ||
104 | [MSTP020] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 20, 0), | ||
105 | [MSTP017] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 17, 0), | ||
106 | [MSTP016] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 16, 0), | ||
107 | [MSTP015] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0), | ||
108 | [MSTP014] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 14, 0), | ||
109 | [MSTP011] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 11, 0), | ||
110 | [MSTP010] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 10, 0), | ||
111 | [MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0), | ||
112 | [MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0), | ||
113 | [MSTP005] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 5, 0), | ||
114 | [MSTP004] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 4, 0), | ||
115 | [MSTP002] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 2, 0), | ||
107 | 116 | ||
108 | static struct clk sh7786_ddr_clk = { | 117 | /* MSTPCR1 */ |
109 | .name = "ddr_clk", | 118 | [MSTP112] = SH_CLK_MSTP32(NULL, MSTPCR1, 12, 0), |
110 | .flags = CLK_ENABLE_ON_INIT, | 119 | [MSTP110] = SH_CLK_MSTP32(NULL, MSTPCR1, 10, 0), |
111 | .ops = &sh7786_ddr_clk_ops, | 120 | [MSTP109] = SH_CLK_MSTP32(NULL, MSTPCR1, 9, 0), |
121 | [MSTP108] = SH_CLK_MSTP32(NULL, MSTPCR1, 8, 0), | ||
122 | [MSTP105] = SH_CLK_MSTP32(NULL, MSTPCR1, 5, 0), | ||
123 | [MSTP104] = SH_CLK_MSTP32(NULL, MSTPCR1, 4, 0), | ||
124 | [MSTP103] = SH_CLK_MSTP32(NULL, MSTPCR1, 3, 0), | ||
125 | [MSTP102] = SH_CLK_MSTP32(NULL, MSTPCR1, 2, 0), | ||
112 | }; | 126 | }; |
113 | 127 | ||
114 | /* | 128 | #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } |
115 | * Additional SH7786-specific on-chip clocks that aren't already part of the | 129 | |
116 | * clock framework | 130 | static struct clk_lookup lookups[] = { |
117 | */ | 131 | /* main clocks */ |
118 | static struct clk *sh7786_onchip_clocks[] = { | 132 | CLKDEV_CON_ID("extal", &extal_clk), |
119 | &sh7786_shyway_clk, | 133 | CLKDEV_CON_ID("pll_clk", &pll_clk), |
120 | &sh7786_ddr_clk, | 134 | |
135 | /* DIV4 clocks */ | ||
136 | CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]), | ||
137 | CLKDEV_CON_ID("du_clk", &div4_clks[DIV4_DU]), | ||
138 | CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_DDR]), | ||
139 | CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]), | ||
140 | CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_SH]), | ||
141 | CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]), | ||
142 | |||
143 | /* MSTP32 clocks */ | ||
144 | { | ||
145 | /* SCIF5 */ | ||
146 | .dev_id = "sh-sci.5", | ||
147 | .con_id = "sci_fck", | ||
148 | .clk = &mstp_clks[MSTP029], | ||
149 | }, { | ||
150 | /* SCIF4 */ | ||
151 | .dev_id = "sh-sci.4", | ||
152 | .con_id = "sci_fck", | ||
153 | .clk = &mstp_clks[MSTP028], | ||
154 | }, { | ||
155 | /* SCIF3 */ | ||
156 | .dev_id = "sh-sci.3", | ||
157 | .con_id = "sci_fck", | ||
158 | .clk = &mstp_clks[MSTP027], | ||
159 | }, { | ||
160 | /* SCIF2 */ | ||
161 | .dev_id = "sh-sci.2", | ||
162 | .con_id = "sci_fck", | ||
163 | .clk = &mstp_clks[MSTP026], | ||
164 | }, { | ||
165 | /* SCIF1 */ | ||
166 | .dev_id = "sh-sci.1", | ||
167 | .con_id = "sci_fck", | ||
168 | .clk = &mstp_clks[MSTP025], | ||
169 | }, { | ||
170 | /* SCIF0 */ | ||
171 | .dev_id = "sh-sci.0", | ||
172 | .con_id = "sci_fck", | ||
173 | .clk = &mstp_clks[MSTP024], | ||
174 | }, | ||
175 | CLKDEV_CON_ID("ssi3_fck", &mstp_clks[MSTP023]), | ||
176 | CLKDEV_CON_ID("ssi2_fck", &mstp_clks[MSTP022]), | ||
177 | CLKDEV_CON_ID("ssi1_fck", &mstp_clks[MSTP021]), | ||
178 | CLKDEV_CON_ID("ssi0_fck", &mstp_clks[MSTP020]), | ||
179 | CLKDEV_CON_ID("hac1_fck", &mstp_clks[MSTP017]), | ||
180 | CLKDEV_CON_ID("hac0_fck", &mstp_clks[MSTP016]), | ||
181 | CLKDEV_CON_ID("i2c1_fck", &mstp_clks[MSTP015]), | ||
182 | CLKDEV_CON_ID("i2c0_fck", &mstp_clks[MSTP014]), | ||
183 | { | ||
184 | /* TMU0 */ | ||
185 | .dev_id = "sh_tmu.0", | ||
186 | .con_id = "tmu_fck", | ||
187 | .clk = &mstp_clks[MSTP008], | ||
188 | }, { | ||
189 | /* TMU1 */ | ||
190 | .dev_id = "sh_tmu.1", | ||
191 | .con_id = "tmu_fck", | ||
192 | .clk = &mstp_clks[MSTP008], | ||
193 | }, { | ||
194 | /* TMU2 */ | ||
195 | .dev_id = "sh_tmu.2", | ||
196 | .con_id = "tmu_fck", | ||
197 | .clk = &mstp_clks[MSTP008], | ||
198 | }, { | ||
199 | /* TMU3 */ | ||
200 | .dev_id = "sh_tmu.3", | ||
201 | .con_id = "tmu_fck", | ||
202 | .clk = &mstp_clks[MSTP009], | ||
203 | }, { | ||
204 | /* TMU4 */ | ||
205 | .dev_id = "sh_tmu.4", | ||
206 | .con_id = "tmu_fck", | ||
207 | .clk = &mstp_clks[MSTP009], | ||
208 | }, { | ||
209 | /* TMU5 */ | ||
210 | .dev_id = "sh_tmu.5", | ||
211 | .con_id = "tmu_fck", | ||
212 | .clk = &mstp_clks[MSTP009], | ||
213 | }, { | ||
214 | /* TMU6 */ | ||
215 | .dev_id = "sh_tmu.6", | ||
216 | .con_id = "tmu_fck", | ||
217 | .clk = &mstp_clks[MSTP010], | ||
218 | }, { | ||
219 | /* TMU7 */ | ||
220 | .dev_id = "sh_tmu.7", | ||
221 | .con_id = "tmu_fck", | ||
222 | .clk = &mstp_clks[MSTP010], | ||
223 | }, { | ||
224 | /* TMU8 */ | ||
225 | .dev_id = "sh_tmu.8", | ||
226 | .con_id = "tmu_fck", | ||
227 | .clk = &mstp_clks[MSTP010], | ||
228 | }, { | ||
229 | /* TMU9 */ | ||
230 | .dev_id = "sh_tmu.9", | ||
231 | .con_id = "tmu_fck", | ||
232 | .clk = &mstp_clks[MSTP011], | ||
233 | }, { | ||
234 | /* TMU10 */ | ||
235 | .dev_id = "sh_tmu.10", | ||
236 | .con_id = "tmu_fck", | ||
237 | .clk = &mstp_clks[MSTP011], | ||
238 | }, { | ||
239 | /* TMU11 */ | ||
240 | .dev_id = "sh_tmu.11", | ||
241 | .con_id = "tmu_fck", | ||
242 | .clk = &mstp_clks[MSTP011], | ||
243 | }, | ||
244 | CLKDEV_CON_ID("sdif1_fck", &mstp_clks[MSTP005]), | ||
245 | CLKDEV_CON_ID("sdif0_fck", &mstp_clks[MSTP004]), | ||
246 | CLKDEV_CON_ID("hspi_fck", &mstp_clks[MSTP002]), | ||
247 | CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP112]), | ||
248 | CLKDEV_CON_ID("pcie2_fck", &mstp_clks[MSTP110]), | ||
249 | CLKDEV_CON_ID("pcie1_fck", &mstp_clks[MSTP109]), | ||
250 | CLKDEV_CON_ID("pcie0_fck", &mstp_clks[MSTP108]), | ||
251 | CLKDEV_CON_ID("dmac_11_6_fck", &mstp_clks[MSTP105]), | ||
252 | CLKDEV_CON_ID("dmac_5_0_fck", &mstp_clks[MSTP104]), | ||
253 | CLKDEV_CON_ID("du_fck", &mstp_clks[MSTP103]), | ||
254 | CLKDEV_CON_ID("ether_fck", &mstp_clks[MSTP102]), | ||
121 | }; | 255 | }; |
122 | 256 | ||
123 | int __init arch_clk_init(void) | 257 | int __init arch_clk_init(void) |
124 | { | 258 | { |
125 | struct clk *clk; | ||
126 | int i, ret = 0; | 259 | int i, ret = 0; |
127 | 260 | ||
128 | cpg_clk_init(); | 261 | for (i = 0; i < ARRAY_SIZE(clks); i++) |
129 | 262 | ret |= clk_register(clks[i]); | |
130 | clk = clk_get(NULL, "master_clk"); | 263 | for (i = 0; i < ARRAY_SIZE(lookups); i++) |
131 | for (i = 0; i < ARRAY_SIZE(sh7786_onchip_clocks); i++) { | 264 | clkdev_add(&lookups[i]); |
132 | struct clk *clkp = sh7786_onchip_clocks[i]; | ||
133 | |||
134 | clkp->parent = clk; | ||
135 | ret |= clk_register(clkp); | ||
136 | } | ||
137 | 265 | ||
138 | clk_put(clk); | 266 | if (!ret) |
267 | ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks), | ||
268 | &div4_table); | ||
269 | if (!ret) | ||
270 | ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); | ||
139 | 271 | ||
140 | return ret; | 272 | return ret; |
141 | } | 273 | } |