Commit 43486e4cd094eabdd514ed7a2376ca55655e506f
Committed by
Tom Rini
1 parent
1e031249a5
Exists in
v2017.01-smarct4x
and in
25 other branches
board: arm:: Add support for Broadcom BCM23550
Add support for the Broadcom BCM23550 board. Signed-off-by: Steve Rae <srae@broadcom.com>
Showing 20 changed files with 2283 additions and 0 deletions Side-by-side Diff
- arch/arm/Kconfig
- arch/arm/cpu/armv7/Makefile
- arch/arm/cpu/armv7/bcm235xx/Makefile
- arch/arm/cpu/armv7/bcm235xx/clk-bcm235xx.c
- arch/arm/cpu/armv7/bcm235xx/clk-bsc.c
- arch/arm/cpu/armv7/bcm235xx/clk-core.c
- arch/arm/cpu/armv7/bcm235xx/clk-core.h
- arch/arm/cpu/armv7/bcm235xx/clk-eth.c
- arch/arm/cpu/armv7/bcm235xx/clk-sdio.c
- arch/arm/cpu/armv7/bcm235xx/clk-usb-otg.c
- arch/arm/cpu/armv7/kona-common/Makefile
- arch/arm/cpu/armv7/kona-common/reset.S
- arch/arm/include/asm/arch-bcm235xx/gpio.h
- arch/arm/include/asm/arch-bcm235xx/sysmap.h
- board/broadcom/bcm23550_w1d/Kconfig
- board/broadcom/bcm23550_w1d/MAINTAINERS
- board/broadcom/bcm23550_w1d/Makefile
- board/broadcom/bcm23550_w1d/bcm23550_w1d.c
- configs/bcm23550_w1d_defconfig
- include/configs/bcm23550_w1d.h
arch/arm/Kconfig
... | ... | @@ -441,6 +441,10 @@ |
441 | 441 | select CPU_V7 |
442 | 442 | select SUPPORT_SPL |
443 | 443 | |
444 | +config TARGET_BCM23550_W1D | |
445 | + bool "Support bcm23550_w1d" | |
446 | + select CPU_V7 | |
447 | + | |
444 | 448 | config TARGET_BCM28155_AP |
445 | 449 | bool "Support bcm28155_ap" |
446 | 450 | select CPU_V7 |
... | ... | @@ -898,6 +902,7 @@ |
898 | 902 | source "board/armltd/vexpress/Kconfig" |
899 | 903 | source "board/armltd/vexpress64/Kconfig" |
900 | 904 | source "board/bluegiga/apx4devkit/Kconfig" |
905 | +source "board/broadcom/bcm23550_w1d/Kconfig" | |
901 | 906 | source "board/broadcom/bcm28155_ap/Kconfig" |
902 | 907 | source "board/broadcom/bcmcygnus/Kconfig" |
903 | 908 | source "board/broadcom/bcmnsp/Kconfig" |
arch/arm/cpu/armv7/Makefile
... | ... | @@ -38,6 +38,7 @@ |
38 | 38 | endif |
39 | 39 | |
40 | 40 | obj-$(if $(filter am33xx,$(SOC)),y) += am33xx/ |
41 | +obj-$(if $(filter bcm235xx,$(SOC)),y) += bcm235xx/ | |
41 | 42 | obj-$(if $(filter bcm281xx,$(SOC)),y) += bcm281xx/ |
42 | 43 | obj-$(if $(filter bcmcygnus,$(SOC)),y) += bcmcygnus/ |
43 | 44 | obj-$(if $(filter bcmnsp,$(SOC)),y) += bcmnsp/ |
arch/arm/cpu/armv7/bcm235xx/Makefile
arch/arm/cpu/armv7/bcm235xx/clk-bcm235xx.c
1 | +/* | |
2 | + * Copyright 2013 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +/* | |
8 | + * | |
9 | + * bcm235xx-specific clock tables | |
10 | + * | |
11 | + */ | |
12 | + | |
13 | +#include <common.h> | |
14 | +#include <asm/io.h> | |
15 | +#include <asm/errno.h> | |
16 | +#include <asm/arch/sysmap.h> | |
17 | +#include <asm/kona-common/clk.h> | |
18 | +#include "clk-core.h" | |
19 | + | |
20 | +#define CLOCK_1K 1000 | |
21 | +#define CLOCK_1M (CLOCK_1K * 1000) | |
22 | + | |
23 | +/* declare a reference clock */ | |
24 | +#define DECLARE_REF_CLK(clk_name, clk_parent, clk_rate, clk_div) \ | |
25 | +static struct refclk clk_name = { \ | |
26 | + .clk = { \ | |
27 | + .name = #clk_name, \ | |
28 | + .parent = clk_parent, \ | |
29 | + .rate = clk_rate, \ | |
30 | + .div = clk_div, \ | |
31 | + .ops = &ref_clk_ops, \ | |
32 | + }, \ | |
33 | +} | |
34 | + | |
35 | +/* | |
36 | + * Reference clocks | |
37 | + */ | |
38 | + | |
39 | +/* Declare a list of reference clocks */ | |
40 | +DECLARE_REF_CLK(ref_crystal, 0, 26 * CLOCK_1M, 1); | |
41 | +DECLARE_REF_CLK(var_96m, 0, 96 * CLOCK_1M, 1); | |
42 | +DECLARE_REF_CLK(ref_96m, 0, 96 * CLOCK_1M, 1); | |
43 | +DECLARE_REF_CLK(ref_312m, 0, 312 * CLOCK_1M, 0); | |
44 | +DECLARE_REF_CLK(ref_104m, &ref_312m.clk, 104 * CLOCK_1M, 3); | |
45 | +DECLARE_REF_CLK(ref_52m, &ref_104m.clk, 52 * CLOCK_1M, 2); | |
46 | +DECLARE_REF_CLK(ref_13m, &ref_52m.clk, 13 * CLOCK_1M, 4); | |
47 | +DECLARE_REF_CLK(var_312m, 0, 312 * CLOCK_1M, 0); | |
48 | +DECLARE_REF_CLK(var_104m, &var_312m.clk, 104 * CLOCK_1M, 3); | |
49 | +DECLARE_REF_CLK(var_52m, &var_104m.clk, 52 * CLOCK_1M, 2); | |
50 | +DECLARE_REF_CLK(var_13m, &var_52m.clk, 13 * CLOCK_1M, 4); | |
51 | + | |
52 | +struct refclk_lkup { | |
53 | + struct refclk *procclk; | |
54 | + const char *name; | |
55 | +}; | |
56 | + | |
57 | +/* Lookup table for string to clk tranlation */ | |
58 | +#define MKSTR(x) {&x, #x} | |
59 | +static struct refclk_lkup refclk_str_tbl[] = { | |
60 | + MKSTR(ref_crystal), MKSTR(var_96m), MKSTR(ref_96m), | |
61 | + MKSTR(ref_312m), MKSTR(ref_104m), MKSTR(ref_52m), | |
62 | + MKSTR(ref_13m), MKSTR(var_312m), MKSTR(var_104m), | |
63 | + MKSTR(var_52m), MKSTR(var_13m), | |
64 | +}; | |
65 | + | |
66 | +int refclk_entries = sizeof(refclk_str_tbl)/sizeof(refclk_str_tbl[0]); | |
67 | + | |
68 | +/* convert ref clock string to clock structure pointer */ | |
69 | +struct refclk *refclk_str_to_clk(const char *name) | |
70 | +{ | |
71 | + int i; | |
72 | + struct refclk_lkup *tblp = refclk_str_tbl; | |
73 | + for (i = 0; i < refclk_entries; i++, tblp++) { | |
74 | + if (!(strcmp(name, tblp->name))) | |
75 | + return tblp->procclk; | |
76 | + } | |
77 | + return NULL; | |
78 | +} | |
79 | + | |
80 | +/* frequency tables indexed by freq_id */ | |
81 | +unsigned long master_axi_freq_tbl[8] = { | |
82 | + 26 * CLOCK_1M, | |
83 | + 52 * CLOCK_1M, | |
84 | + 104 * CLOCK_1M, | |
85 | + 156 * CLOCK_1M, | |
86 | + 156 * CLOCK_1M, | |
87 | + 208 * CLOCK_1M, | |
88 | + 312 * CLOCK_1M, | |
89 | + 312 * CLOCK_1M | |
90 | +}; | |
91 | + | |
92 | +unsigned long master_ahb_freq_tbl[8] = { | |
93 | + 26 * CLOCK_1M, | |
94 | + 52 * CLOCK_1M, | |
95 | + 52 * CLOCK_1M, | |
96 | + 52 * CLOCK_1M, | |
97 | + 78 * CLOCK_1M, | |
98 | + 104 * CLOCK_1M, | |
99 | + 104 * CLOCK_1M, | |
100 | + 156 * CLOCK_1M | |
101 | +}; | |
102 | + | |
103 | +unsigned long slave_axi_freq_tbl[8] = { | |
104 | + 26 * CLOCK_1M, | |
105 | + 52 * CLOCK_1M, | |
106 | + 78 * CLOCK_1M, | |
107 | + 104 * CLOCK_1M, | |
108 | + 156 * CLOCK_1M, | |
109 | + 156 * CLOCK_1M | |
110 | +}; | |
111 | + | |
112 | +unsigned long slave_apb_freq_tbl[8] = { | |
113 | + 26 * CLOCK_1M, | |
114 | + 26 * CLOCK_1M, | |
115 | + 39 * CLOCK_1M, | |
116 | + 52 * CLOCK_1M, | |
117 | + 52 * CLOCK_1M, | |
118 | + 78 * CLOCK_1M | |
119 | +}; | |
120 | + | |
121 | +unsigned long esub_freq_tbl[8] = { | |
122 | + 78 * CLOCK_1M, | |
123 | + 156 * CLOCK_1M, | |
124 | + 156 * CLOCK_1M, | |
125 | + 156 * CLOCK_1M, | |
126 | + 208 * CLOCK_1M, | |
127 | + 208 * CLOCK_1M, | |
128 | + 208 * CLOCK_1M | |
129 | +}; | |
130 | + | |
131 | +static struct bus_clk_data bsc1_apb_data = { | |
132 | + .gate = HW_SW_GATE_AUTO(0x0458, 16, 0, 1), | |
133 | +}; | |
134 | + | |
135 | +static struct bus_clk_data bsc2_apb_data = { | |
136 | + .gate = HW_SW_GATE_AUTO(0x045c, 16, 0, 1), | |
137 | +}; | |
138 | + | |
139 | +static struct bus_clk_data bsc3_apb_data = { | |
140 | + .gate = HW_SW_GATE_AUTO(0x0484, 16, 0, 1), | |
141 | +}; | |
142 | + | |
143 | +/* * Master CCU clocks */ | |
144 | +static struct peri_clk_data sdio1_data = { | |
145 | + .gate = HW_SW_GATE(0x0358, 18, 2, 3), | |
146 | + .clocks = CLOCKS("ref_crystal", | |
147 | + "var_52m", | |
148 | + "ref_52m", | |
149 | + "var_96m", | |
150 | + "ref_96m"), | |
151 | + .sel = SELECTOR(0x0a28, 0, 3), | |
152 | + .div = DIVIDER(0x0a28, 4, 14), | |
153 | + .trig = TRIGGER(0x0afc, 9), | |
154 | +}; | |
155 | + | |
156 | +static struct peri_clk_data sdio2_data = { | |
157 | + .gate = HW_SW_GATE(0x035c, 18, 2, 3), | |
158 | + .clocks = CLOCKS("ref_crystal", | |
159 | + "var_52m", | |
160 | + "ref_52m", | |
161 | + "var_96m", | |
162 | + "ref_96m"), | |
163 | + .sel = SELECTOR(0x0a2c, 0, 3), | |
164 | + .div = DIVIDER(0x0a2c, 4, 14), | |
165 | + .trig = TRIGGER(0x0afc, 10), | |
166 | +}; | |
167 | + | |
168 | +static struct peri_clk_data sdio3_data = { | |
169 | + .gate = HW_SW_GATE(0x0364, 18, 2, 3), | |
170 | + .clocks = CLOCKS("ref_crystal", | |
171 | + "var_52m", | |
172 | + "ref_52m", | |
173 | + "var_96m", | |
174 | + "ref_96m"), | |
175 | + .sel = SELECTOR(0x0a34, 0, 3), | |
176 | + .div = DIVIDER(0x0a34, 4, 14), | |
177 | + .trig = TRIGGER(0x0afc, 12), | |
178 | +}; | |
179 | + | |
180 | +static struct peri_clk_data sdio4_data = { | |
181 | + .gate = HW_SW_GATE(0x0360, 18, 2, 3), | |
182 | + .clocks = CLOCKS("ref_crystal", | |
183 | + "var_52m", | |
184 | + "ref_52m", | |
185 | + "var_96m", | |
186 | + "ref_96m"), | |
187 | + .sel = SELECTOR(0x0a30, 0, 3), | |
188 | + .div = DIVIDER(0x0a30, 4, 14), | |
189 | + .trig = TRIGGER(0x0afc, 11), | |
190 | +}; | |
191 | + | |
192 | +static struct peri_clk_data sdio1_sleep_data = { | |
193 | + .clocks = CLOCKS("ref_32k"), | |
194 | + .gate = SW_ONLY_GATE(0x0358, 20, 4), | |
195 | +}; | |
196 | + | |
197 | +static struct peri_clk_data sdio2_sleep_data = { | |
198 | + .clocks = CLOCKS("ref_32k"), | |
199 | + .gate = SW_ONLY_GATE(0x035c, 20, 4), | |
200 | +}; | |
201 | + | |
202 | +static struct peri_clk_data sdio3_sleep_data = { | |
203 | + .clocks = CLOCKS("ref_32k"), | |
204 | + .gate = SW_ONLY_GATE(0x0364, 20, 4), | |
205 | +}; | |
206 | + | |
207 | +static struct peri_clk_data sdio4_sleep_data = { | |
208 | + .clocks = CLOCKS("ref_32k"), | |
209 | + .gate = SW_ONLY_GATE(0x0360, 20, 4), | |
210 | +}; | |
211 | + | |
212 | +static struct bus_clk_data usb_otg_ahb_data = { | |
213 | + .gate = HW_SW_GATE_AUTO(0x0348, 16, 0, 1), | |
214 | +}; | |
215 | + | |
216 | +static struct bus_clk_data sdio1_ahb_data = { | |
217 | + .gate = HW_SW_GATE_AUTO(0x0358, 16, 0, 1), | |
218 | +}; | |
219 | + | |
220 | +static struct bus_clk_data sdio2_ahb_data = { | |
221 | + .gate = HW_SW_GATE_AUTO(0x035c, 16, 0, 1), | |
222 | +}; | |
223 | + | |
224 | +static struct bus_clk_data sdio3_ahb_data = { | |
225 | + .gate = HW_SW_GATE_AUTO(0x0364, 16, 0, 1), | |
226 | +}; | |
227 | + | |
228 | +static struct bus_clk_data sdio4_ahb_data = { | |
229 | + .gate = HW_SW_GATE_AUTO(0x0360, 16, 0, 1), | |
230 | +}; | |
231 | + | |
232 | +/* * Slave CCU clocks */ | |
233 | +static struct peri_clk_data bsc1_data = { | |
234 | + .gate = HW_SW_GATE(0x0458, 18, 2, 3), | |
235 | + .clocks = CLOCKS("ref_crystal", | |
236 | + "var_104m", | |
237 | + "ref_104m", | |
238 | + "var_13m", | |
239 | + "ref_13m"), | |
240 | + .sel = SELECTOR(0x0a64, 0, 3), | |
241 | + .trig = TRIGGER(0x0afc, 23), | |
242 | +}; | |
243 | + | |
244 | +static struct peri_clk_data bsc2_data = { | |
245 | + .gate = HW_SW_GATE(0x045c, 18, 2, 3), | |
246 | + .clocks = CLOCKS("ref_crystal", | |
247 | + "var_104m", | |
248 | + "ref_104m", | |
249 | + "var_13m", | |
250 | + "ref_13m"), | |
251 | + .sel = SELECTOR(0x0a68, 0, 3), | |
252 | + .trig = TRIGGER(0x0afc, 24), | |
253 | +}; | |
254 | + | |
255 | +static struct peri_clk_data bsc3_data = { | |
256 | + .gate = HW_SW_GATE(0x0484, 18, 2, 3), | |
257 | + .clocks = CLOCKS("ref_crystal", | |
258 | + "var_104m", | |
259 | + "ref_104m", | |
260 | + "var_13m", | |
261 | + "ref_13m"), | |
262 | + .sel = SELECTOR(0x0a84, 0, 3), | |
263 | + .trig = TRIGGER(0x0b00, 2), | |
264 | +}; | |
265 | + | |
266 | +/* | |
267 | + * CCU clocks | |
268 | + */ | |
269 | + | |
270 | +static struct ccu_clock kpm_ccu_clk = { | |
271 | + .clk = { | |
272 | + .name = "kpm_ccu_clk", | |
273 | + .ops = &ccu_clk_ops, | |
274 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
275 | + }, | |
276 | + .num_policy_masks = 1, | |
277 | + .policy_freq_offset = 0x00000008, | |
278 | + .freq_bit_shift = 8, | |
279 | + .policy_ctl_offset = 0x0000000c, | |
280 | + .policy0_mask_offset = 0x00000010, | |
281 | + .policy1_mask_offset = 0x00000014, | |
282 | + .policy2_mask_offset = 0x00000018, | |
283 | + .policy3_mask_offset = 0x0000001c, | |
284 | + .lvm_en_offset = 0x00000034, | |
285 | + .freq_id = 2, | |
286 | + .freq_tbl = master_axi_freq_tbl, | |
287 | +}; | |
288 | + | |
289 | +static struct ccu_clock kps_ccu_clk = { | |
290 | + .clk = { | |
291 | + .name = "kps_ccu_clk", | |
292 | + .ops = &ccu_clk_ops, | |
293 | + .ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, | |
294 | + }, | |
295 | + .num_policy_masks = 2, | |
296 | + .policy_freq_offset = 0x00000008, | |
297 | + .freq_bit_shift = 8, | |
298 | + .policy_ctl_offset = 0x0000000c, | |
299 | + .policy0_mask_offset = 0x00000010, | |
300 | + .policy1_mask_offset = 0x00000014, | |
301 | + .policy2_mask_offset = 0x00000018, | |
302 | + .policy3_mask_offset = 0x0000001c, | |
303 | + .policy0_mask2_offset = 0x00000048, | |
304 | + .policy1_mask2_offset = 0x0000004c, | |
305 | + .policy2_mask2_offset = 0x00000050, | |
306 | + .policy3_mask2_offset = 0x00000054, | |
307 | + .lvm_en_offset = 0x00000034, | |
308 | + .freq_id = 2, | |
309 | + .freq_tbl = slave_axi_freq_tbl, | |
310 | +}; | |
311 | + | |
312 | +#ifdef CONFIG_BCM_SF2_ETH | |
313 | +static struct ccu_clock esub_ccu_clk = { | |
314 | + .clk = { | |
315 | + .name = "esub_ccu_clk", | |
316 | + .ops = &ccu_clk_ops, | |
317 | + .ccu_clk_mgr_base = ESUB_CLK_BASE_ADDR, | |
318 | + }, | |
319 | + .num_policy_masks = 1, | |
320 | + .policy_freq_offset = 0x00000008, | |
321 | + .freq_bit_shift = 8, | |
322 | + .policy_ctl_offset = 0x0000000c, | |
323 | + .policy0_mask_offset = 0x00000010, | |
324 | + .policy1_mask_offset = 0x00000014, | |
325 | + .policy2_mask_offset = 0x00000018, | |
326 | + .policy3_mask_offset = 0x0000001c, | |
327 | + .lvm_en_offset = 0x00000034, | |
328 | + .freq_id = 2, | |
329 | + .freq_tbl = esub_freq_tbl, | |
330 | +}; | |
331 | +#endif | |
332 | + | |
333 | +/* | |
334 | + * Bus clocks | |
335 | + */ | |
336 | + | |
337 | +/* KPM bus clocks */ | |
338 | +static struct bus_clock usb_otg_ahb_clk = { | |
339 | + .clk = { | |
340 | + .name = "usb_otg_ahb_clk", | |
341 | + .parent = &kpm_ccu_clk.clk, | |
342 | + .ops = &bus_clk_ops, | |
343 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
344 | + }, | |
345 | + .freq_tbl = master_ahb_freq_tbl, | |
346 | + .data = &usb_otg_ahb_data, | |
347 | +}; | |
348 | + | |
349 | +static struct bus_clock sdio1_ahb_clk = { | |
350 | + .clk = { | |
351 | + .name = "sdio1_ahb_clk", | |
352 | + .parent = &kpm_ccu_clk.clk, | |
353 | + .ops = &bus_clk_ops, | |
354 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
355 | + }, | |
356 | + .freq_tbl = master_ahb_freq_tbl, | |
357 | + .data = &sdio1_ahb_data, | |
358 | +}; | |
359 | + | |
360 | +static struct bus_clock sdio2_ahb_clk = { | |
361 | + .clk = { | |
362 | + .name = "sdio2_ahb_clk", | |
363 | + .parent = &kpm_ccu_clk.clk, | |
364 | + .ops = &bus_clk_ops, | |
365 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
366 | + }, | |
367 | + .freq_tbl = master_ahb_freq_tbl, | |
368 | + .data = &sdio2_ahb_data, | |
369 | +}; | |
370 | + | |
371 | +static struct bus_clock sdio3_ahb_clk = { | |
372 | + .clk = { | |
373 | + .name = "sdio3_ahb_clk", | |
374 | + .parent = &kpm_ccu_clk.clk, | |
375 | + .ops = &bus_clk_ops, | |
376 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
377 | + }, | |
378 | + .freq_tbl = master_ahb_freq_tbl, | |
379 | + .data = &sdio3_ahb_data, | |
380 | +}; | |
381 | + | |
382 | +static struct bus_clock sdio4_ahb_clk = { | |
383 | + .clk = { | |
384 | + .name = "sdio4_ahb_clk", | |
385 | + .parent = &kpm_ccu_clk.clk, | |
386 | + .ops = &bus_clk_ops, | |
387 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
388 | + }, | |
389 | + .freq_tbl = master_ahb_freq_tbl, | |
390 | + .data = &sdio4_ahb_data, | |
391 | +}; | |
392 | + | |
393 | +static struct bus_clock bsc1_apb_clk = { | |
394 | + .clk = { | |
395 | + .name = "bsc1_apb_clk", | |
396 | + .parent = &kps_ccu_clk.clk, | |
397 | + .ops = &bus_clk_ops, | |
398 | + .ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, | |
399 | + }, | |
400 | + .freq_tbl = slave_apb_freq_tbl, | |
401 | + .data = &bsc1_apb_data, | |
402 | +}; | |
403 | + | |
404 | +static struct bus_clock bsc2_apb_clk = { | |
405 | + .clk = { | |
406 | + .name = "bsc2_apb_clk", | |
407 | + .parent = &kps_ccu_clk.clk, | |
408 | + .ops = &bus_clk_ops, | |
409 | + .ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, | |
410 | + }, | |
411 | + .freq_tbl = slave_apb_freq_tbl, | |
412 | + .data = &bsc2_apb_data, | |
413 | +}; | |
414 | + | |
415 | +static struct bus_clock bsc3_apb_clk = { | |
416 | + .clk = { | |
417 | + .name = "bsc3_apb_clk", | |
418 | + .parent = &kps_ccu_clk.clk, | |
419 | + .ops = &bus_clk_ops, | |
420 | + .ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, | |
421 | + }, | |
422 | + .freq_tbl = slave_apb_freq_tbl, | |
423 | + .data = &bsc3_apb_data, | |
424 | +}; | |
425 | + | |
426 | +/* KPM peripheral */ | |
427 | +static struct peri_clock sdio1_clk = { | |
428 | + .clk = { | |
429 | + .name = "sdio1_clk", | |
430 | + .parent = &ref_52m.clk, | |
431 | + .ops = &peri_clk_ops, | |
432 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
433 | + }, | |
434 | + .data = &sdio1_data, | |
435 | +}; | |
436 | + | |
437 | +static struct peri_clock sdio2_clk = { | |
438 | + .clk = { | |
439 | + .name = "sdio2_clk", | |
440 | + .parent = &ref_52m.clk, | |
441 | + .ops = &peri_clk_ops, | |
442 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
443 | + }, | |
444 | + .data = &sdio2_data, | |
445 | +}; | |
446 | + | |
447 | +static struct peri_clock sdio3_clk = { | |
448 | + .clk = { | |
449 | + .name = "sdio3_clk", | |
450 | + .parent = &ref_52m.clk, | |
451 | + .ops = &peri_clk_ops, | |
452 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
453 | + }, | |
454 | + .data = &sdio3_data, | |
455 | +}; | |
456 | + | |
457 | +static struct peri_clock sdio4_clk = { | |
458 | + .clk = { | |
459 | + .name = "sdio4_clk", | |
460 | + .parent = &ref_52m.clk, | |
461 | + .ops = &peri_clk_ops, | |
462 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
463 | + }, | |
464 | + .data = &sdio4_data, | |
465 | +}; | |
466 | + | |
467 | +static struct peri_clock sdio1_sleep_clk = { | |
468 | + .clk = { | |
469 | + .name = "sdio1_sleep_clk", | |
470 | + .parent = &kpm_ccu_clk.clk, | |
471 | + .ops = &bus_clk_ops, | |
472 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
473 | + }, | |
474 | + .data = &sdio1_sleep_data, | |
475 | +}; | |
476 | + | |
477 | +static struct peri_clock sdio2_sleep_clk = { | |
478 | + .clk = { | |
479 | + .name = "sdio2_sleep_clk", | |
480 | + .parent = &kpm_ccu_clk.clk, | |
481 | + .ops = &bus_clk_ops, | |
482 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
483 | + }, | |
484 | + .data = &sdio2_sleep_data, | |
485 | +}; | |
486 | + | |
487 | +static struct peri_clock sdio3_sleep_clk = { | |
488 | + .clk = { | |
489 | + .name = "sdio3_sleep_clk", | |
490 | + .parent = &kpm_ccu_clk.clk, | |
491 | + .ops = &bus_clk_ops, | |
492 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
493 | + }, | |
494 | + .data = &sdio3_sleep_data, | |
495 | +}; | |
496 | + | |
497 | +static struct peri_clock sdio4_sleep_clk = { | |
498 | + .clk = { | |
499 | + .name = "sdio4_sleep_clk", | |
500 | + .parent = &kpm_ccu_clk.clk, | |
501 | + .ops = &bus_clk_ops, | |
502 | + .ccu_clk_mgr_base = KONA_MST_CLK_BASE_ADDR, | |
503 | + }, | |
504 | + .data = &sdio4_sleep_data, | |
505 | +}; | |
506 | + | |
507 | +/* KPS peripheral clock */ | |
508 | +static struct peri_clock bsc1_clk = { | |
509 | + .clk = { | |
510 | + .name = "bsc1_clk", | |
511 | + .parent = &ref_13m.clk, | |
512 | + .rate = 13 * CLOCK_1M, | |
513 | + .div = 1, | |
514 | + .ops = &peri_clk_ops, | |
515 | + .ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, | |
516 | + }, | |
517 | + .data = &bsc1_data, | |
518 | +}; | |
519 | + | |
520 | +static struct peri_clock bsc2_clk = { | |
521 | + .clk = { | |
522 | + .name = "bsc2_clk", | |
523 | + .parent = &ref_13m.clk, | |
524 | + .rate = 13 * CLOCK_1M, | |
525 | + .div = 1, | |
526 | + .ops = &peri_clk_ops, | |
527 | + .ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, | |
528 | + }, | |
529 | + .data = &bsc2_data, | |
530 | +}; | |
531 | + | |
532 | +static struct peri_clock bsc3_clk = { | |
533 | + .clk = { | |
534 | + .name = "bsc3_clk", | |
535 | + .parent = &ref_13m.clk, | |
536 | + .rate = 13 * CLOCK_1M, | |
537 | + .div = 1, | |
538 | + .ops = &peri_clk_ops, | |
539 | + .ccu_clk_mgr_base = KONA_SLV_CLK_BASE_ADDR, | |
540 | + }, | |
541 | + .data = &bsc3_data, | |
542 | +}; | |
543 | + | |
544 | +/* public table for registering clocks */ | |
545 | +struct clk_lookup arch_clk_tbl[] = { | |
546 | + /* Peripheral clocks */ | |
547 | + CLK_LK(sdio1), | |
548 | + CLK_LK(sdio2), | |
549 | + CLK_LK(sdio3), | |
550 | + CLK_LK(sdio4), | |
551 | + CLK_LK(sdio1_sleep), | |
552 | + CLK_LK(sdio2_sleep), | |
553 | + CLK_LK(sdio3_sleep), | |
554 | + CLK_LK(sdio4_sleep), | |
555 | + CLK_LK(bsc1), | |
556 | + CLK_LK(bsc2), | |
557 | + CLK_LK(bsc3), | |
558 | + /* Bus clocks */ | |
559 | + CLK_LK(usb_otg_ahb), | |
560 | + CLK_LK(sdio1_ahb), | |
561 | + CLK_LK(sdio2_ahb), | |
562 | + CLK_LK(sdio3_ahb), | |
563 | + CLK_LK(sdio4_ahb), | |
564 | + CLK_LK(bsc1_apb), | |
565 | + CLK_LK(bsc2_apb), | |
566 | + CLK_LK(bsc3_apb), | |
567 | +#ifdef CONFIG_BCM_SF2_ETH | |
568 | + CLK_LK(esub_ccu), | |
569 | +#endif | |
570 | +}; | |
571 | + | |
572 | +/* public array size */ | |
573 | +unsigned int arch_clk_tbl_array_size = ARRAY_SIZE(arch_clk_tbl); |
arch/arm/cpu/armv7/bcm235xx/clk-bsc.c
1 | +/* | |
2 | + * Copyright 2013 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#include <common.h> | |
8 | +#include <asm/io.h> | |
9 | +#include <asm/errno.h> | |
10 | +#include <asm/arch/sysmap.h> | |
11 | +#include <asm/kona-common/clk.h> | |
12 | +#include "clk-core.h" | |
13 | + | |
14 | +/* Enable appropriate clocks for a BSC/I2C port */ | |
15 | +int clk_bsc_enable(void *base) | |
16 | +{ | |
17 | + int ret; | |
18 | + char *bscstr, *apbstr; | |
19 | + | |
20 | + switch ((u32) base) { | |
21 | + case PMU_BSC_BASE_ADDR: | |
22 | + /* PMU clock is always enabled */ | |
23 | + return 0; | |
24 | + case BSC1_BASE_ADDR: | |
25 | + bscstr = "bsc1_clk"; | |
26 | + apbstr = "bsc1_apb_clk"; | |
27 | + break; | |
28 | + case BSC2_BASE_ADDR: | |
29 | + bscstr = "bsc2_clk"; | |
30 | + apbstr = "bsc2_apb_clk"; | |
31 | + break; | |
32 | + case BSC3_BASE_ADDR: | |
33 | + bscstr = "bsc3_clk"; | |
34 | + apbstr = "bsc3_apb_clk"; | |
35 | + break; | |
36 | + default: | |
37 | + printf("%s: base 0x%p not found\n", __func__, base); | |
38 | + return -EINVAL; | |
39 | + } | |
40 | + | |
41 | + /* Note that the bus clock must be enabled first */ | |
42 | + | |
43 | + ret = clk_get_and_enable(apbstr); | |
44 | + if (ret) | |
45 | + return ret; | |
46 | + | |
47 | + ret = clk_get_and_enable(bscstr); | |
48 | + if (ret) | |
49 | + return ret; | |
50 | + | |
51 | + return 0; | |
52 | +} |
arch/arm/cpu/armv7/bcm235xx/clk-core.c
1 | +/* | |
2 | + * Copyright 2013 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +/* | |
8 | + * | |
9 | + * bcm235xx architecture clock framework | |
10 | + * | |
11 | + */ | |
12 | + | |
13 | +#include <common.h> | |
14 | +#include <asm/io.h> | |
15 | +#include <asm/errno.h> | |
16 | +#include <bitfield.h> | |
17 | +#include <asm/arch/sysmap.h> | |
18 | +#include <asm/kona-common/clk.h> | |
19 | +#include "clk-core.h" | |
20 | + | |
21 | +#define CLK_WR_ACCESS_PASSWORD 0x00a5a501 | |
22 | +#define WR_ACCESS_OFFSET 0 /* common to all clock blocks */ | |
23 | +#define POLICY_CTL_GO 1 /* Load and refresh policy masks */ | |
24 | +#define POLICY_CTL_GO_ATL 4 /* Active Load */ | |
25 | + | |
26 | +/* Helper function */ | |
27 | +int clk_get_and_enable(char *clkstr) | |
28 | +{ | |
29 | + int ret = 0; | |
30 | + struct clk *c; | |
31 | + | |
32 | + debug("%s: %s\n", __func__, clkstr); | |
33 | + | |
34 | + c = clk_get(clkstr); | |
35 | + if (c) { | |
36 | + ret = clk_enable(c); | |
37 | + if (ret) | |
38 | + return ret; | |
39 | + } else { | |
40 | + printf("%s: Couldn't find %s\n", __func__, clkstr); | |
41 | + return -EINVAL; | |
42 | + } | |
43 | + return ret; | |
44 | +} | |
45 | + | |
46 | +/* | |
47 | + * Poll a register in a CCU's address space, returning when the | |
48 | + * specified bit in that register's value is set (or clear). Delay | |
49 | + * a microsecond after each read of the register. Returns true if | |
50 | + * successful, or false if we gave up trying. | |
51 | + * | |
52 | + * Caller must ensure the CCU lock is held. | |
53 | + */ | |
54 | +#define CLK_GATE_DELAY_USEC 2000 | |
55 | +static inline int wait_bit(void *base, u32 offset, u32 bit, bool want) | |
56 | +{ | |
57 | + unsigned int tries; | |
58 | + u32 bit_mask = 1 << bit; | |
59 | + | |
60 | + for (tries = 0; tries < CLK_GATE_DELAY_USEC; tries++) { | |
61 | + u32 val; | |
62 | + bool bit_val; | |
63 | + | |
64 | + val = readl(base + offset); | |
65 | + bit_val = (val & bit_mask) ? 1 : 0; | |
66 | + if (bit_val == want) | |
67 | + return 0; /* success */ | |
68 | + udelay(1); | |
69 | + } | |
70 | + | |
71 | + debug("%s: timeout on addr 0x%p, waiting for bit %d to go to %d\n", | |
72 | + __func__, base + offset, bit, want); | |
73 | + | |
74 | + return -ETIMEDOUT; | |
75 | +} | |
76 | + | |
77 | +/* Enable a peripheral clock */ | |
78 | +static int peri_clk_enable(struct clk *c, int enable) | |
79 | +{ | |
80 | + int ret = 0; | |
81 | + u32 reg; | |
82 | + struct peri_clock *peri_clk = to_peri_clk(c); | |
83 | + struct peri_clk_data *cd = peri_clk->data; | |
84 | + struct bcm_clk_gate *gate = &cd->gate; | |
85 | + void *base = (void *)c->ccu_clk_mgr_base; | |
86 | + | |
87 | + | |
88 | + debug("%s: %s\n", __func__, c->name); | |
89 | + | |
90 | + clk_get_rate(c); /* Make sure rate and sel are filled in */ | |
91 | + | |
92 | + /* enable access */ | |
93 | + writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET); | |
94 | + | |
95 | + if (enable) { | |
96 | + debug("%s %s set rate %lu div %lu sel %d parent %lu\n", | |
97 | + __func__, c->name, c->rate, c->div, c->sel, | |
98 | + c->parent->rate); | |
99 | + | |
100 | + /* | |
101 | + * clkgate - only software controllable gates are | |
102 | + * supported by u-boot which includes all clocks | |
103 | + * that matter. This avoids bringing in a lot of extra | |
104 | + * complexity as done in the kernel framework. | |
105 | + */ | |
106 | + if (gate_exists(gate)) { | |
107 | + reg = readl(base + cd->gate.offset); | |
108 | + reg |= (1 << cd->gate.en_bit); | |
109 | + writel(reg, base + cd->gate.offset); | |
110 | + } | |
111 | + | |
112 | + /* div and pll select */ | |
113 | + if (divider_exists(&cd->div)) { | |
114 | + reg = readl(base + cd->div.offset); | |
115 | + bitfield_replace(reg, cd->div.shift, cd->div.width, | |
116 | + c->div - 1); | |
117 | + writel(reg, base + cd->div.offset); | |
118 | + } | |
119 | + | |
120 | + /* frequency selector */ | |
121 | + if (selector_exists(&cd->sel)) { | |
122 | + reg = readl(base + cd->sel.offset); | |
123 | + bitfield_replace(reg, cd->sel.shift, cd->sel.width, | |
124 | + c->sel); | |
125 | + writel(reg, base + cd->sel.offset); | |
126 | + } | |
127 | + | |
128 | + /* trigger */ | |
129 | + if (trigger_exists(&cd->trig)) { | |
130 | + writel((1 << cd->trig.bit), base + cd->trig.offset); | |
131 | + | |
132 | + /* wait for trigger status bit to go to 0 */ | |
133 | + ret = wait_bit(base, cd->trig.offset, cd->trig.bit, 0); | |
134 | + if (ret) | |
135 | + return ret; | |
136 | + } | |
137 | + | |
138 | + /* wait for running (status_bit = 1) */ | |
139 | + ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 1); | |
140 | + if (ret) | |
141 | + return ret; | |
142 | + } else { | |
143 | + debug("%s disable clock %s\n", __func__, c->name); | |
144 | + | |
145 | + /* clkgate */ | |
146 | + reg = readl(base + cd->gate.offset); | |
147 | + reg &= ~(1 << cd->gate.en_bit); | |
148 | + writel(reg, base + cd->gate.offset); | |
149 | + | |
150 | + /* wait for stop (status_bit = 0) */ | |
151 | + ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, 0); | |
152 | + } | |
153 | + | |
154 | + /* disable access */ | |
155 | + writel(0, base + WR_ACCESS_OFFSET); | |
156 | + | |
157 | + return ret; | |
158 | +} | |
159 | + | |
160 | +/* Set the rate of a peripheral clock */ | |
161 | +static int peri_clk_set_rate(struct clk *c, unsigned long rate) | |
162 | +{ | |
163 | + int ret = 0; | |
164 | + int i; | |
165 | + unsigned long diff; | |
166 | + unsigned long new_rate = 0, div = 1; | |
167 | + struct peri_clock *peri_clk = to_peri_clk(c); | |
168 | + struct peri_clk_data *cd = peri_clk->data; | |
169 | + const char **clock; | |
170 | + | |
171 | + debug("%s: %s\n", __func__, c->name); | |
172 | + diff = rate; | |
173 | + | |
174 | + i = 0; | |
175 | + for (clock = cd->clocks; *clock; clock++, i++) { | |
176 | + struct refclk *ref = refclk_str_to_clk(*clock); | |
177 | + if (!ref) { | |
178 | + printf("%s: Lookup of %s failed\n", __func__, *clock); | |
179 | + return -EINVAL; | |
180 | + } | |
181 | + | |
182 | + /* round to the new rate */ | |
183 | + div = ref->clk.rate / rate; | |
184 | + if (div == 0) | |
185 | + div = 1; | |
186 | + | |
187 | + new_rate = ref->clk.rate / div; | |
188 | + | |
189 | + /* get the min diff */ | |
190 | + if (abs(new_rate - rate) < diff) { | |
191 | + diff = abs(new_rate - rate); | |
192 | + c->sel = i; | |
193 | + c->parent = &ref->clk; | |
194 | + c->rate = new_rate; | |
195 | + c->div = div; | |
196 | + } | |
197 | + } | |
198 | + | |
199 | + debug("%s %s set rate %lu div %lu sel %d parent %lu\n", __func__, | |
200 | + c->name, c->rate, c->div, c->sel, c->parent->rate); | |
201 | + return ret; | |
202 | +} | |
203 | + | |
204 | +/* Get the rate of a peripheral clock */ | |
205 | +static unsigned long peri_clk_get_rate(struct clk *c) | |
206 | +{ | |
207 | + struct peri_clock *peri_clk = to_peri_clk(c); | |
208 | + struct peri_clk_data *cd = peri_clk->data; | |
209 | + void *base = (void *)c->ccu_clk_mgr_base; | |
210 | + int div = 1; | |
211 | + const char **clock; | |
212 | + struct refclk *ref; | |
213 | + u32 reg; | |
214 | + | |
215 | + debug("%s: %s\n", __func__, c->name); | |
216 | + if (selector_exists(&cd->sel)) { | |
217 | + reg = readl(base + cd->sel.offset); | |
218 | + c->sel = bitfield_extract(reg, cd->sel.shift, cd->sel.width); | |
219 | + } else { | |
220 | + /* | |
221 | + * For peri clocks that don't have a selector, the single | |
222 | + * reference clock will always exist at index 0. | |
223 | + */ | |
224 | + c->sel = 0; | |
225 | + } | |
226 | + | |
227 | + if (divider_exists(&cd->div)) { | |
228 | + reg = readl(base + cd->div.offset); | |
229 | + div = bitfield_extract(reg, cd->div.shift, cd->div.width); | |
230 | + div += 1; | |
231 | + } | |
232 | + | |
233 | + clock = cd->clocks; | |
234 | + ref = refclk_str_to_clk(clock[c->sel]); | |
235 | + if (!ref) { | |
236 | + printf("%s: Can't lookup %s\n", __func__, clock[c->sel]); | |
237 | + return 0; | |
238 | + } | |
239 | + | |
240 | + c->parent = &ref->clk; | |
241 | + c->div = div; | |
242 | + c->rate = c->parent->rate / c->div; | |
243 | + debug("%s parent rate %lu div %d sel %d rate %lu\n", __func__, | |
244 | + c->parent->rate, div, c->sel, c->rate); | |
245 | + | |
246 | + return c->rate; | |
247 | +} | |
248 | + | |
249 | +/* Peripheral clock operations */ | |
250 | +struct clk_ops peri_clk_ops = { | |
251 | + .enable = peri_clk_enable, | |
252 | + .set_rate = peri_clk_set_rate, | |
253 | + .get_rate = peri_clk_get_rate, | |
254 | +}; | |
255 | + | |
256 | +/* Enable a CCU clock */ | |
257 | +static int ccu_clk_enable(struct clk *c, int enable) | |
258 | +{ | |
259 | + struct ccu_clock *ccu_clk = to_ccu_clk(c); | |
260 | + void *base = (void *)c->ccu_clk_mgr_base; | |
261 | + int ret = 0; | |
262 | + u32 reg; | |
263 | + | |
264 | + debug("%s: %s\n", __func__, c->name); | |
265 | + if (!enable) | |
266 | + return -EINVAL; /* CCU clock cannot shutdown */ | |
267 | + | |
268 | + /* enable access */ | |
269 | + writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET); | |
270 | + | |
271 | + /* config enable for policy engine */ | |
272 | + writel(1, base + ccu_clk->lvm_en_offset); | |
273 | + | |
274 | + /* wait for bit to go to 0 */ | |
275 | + ret = wait_bit(base, ccu_clk->lvm_en_offset, 0, 0); | |
276 | + if (ret) | |
277 | + return ret; | |
278 | + | |
279 | + /* freq ID */ | |
280 | + if (!ccu_clk->freq_bit_shift) | |
281 | + ccu_clk->freq_bit_shift = 8; | |
282 | + | |
283 | + /* Set frequency id for each of the 4 policies */ | |
284 | + reg = ccu_clk->freq_id | | |
285 | + (ccu_clk->freq_id << (ccu_clk->freq_bit_shift)) | | |
286 | + (ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 2)) | | |
287 | + (ccu_clk->freq_id << (ccu_clk->freq_bit_shift * 3)); | |
288 | + writel(reg, base + ccu_clk->policy_freq_offset); | |
289 | + | |
290 | + /* enable all clock mask */ | |
291 | + writel(0x7fffffff, base + ccu_clk->policy0_mask_offset); | |
292 | + writel(0x7fffffff, base + ccu_clk->policy1_mask_offset); | |
293 | + writel(0x7fffffff, base + ccu_clk->policy2_mask_offset); | |
294 | + writel(0x7fffffff, base + ccu_clk->policy3_mask_offset); | |
295 | + | |
296 | + if (ccu_clk->num_policy_masks == 2) { | |
297 | + writel(0x7fffffff, base + ccu_clk->policy0_mask2_offset); | |
298 | + writel(0x7fffffff, base + ccu_clk->policy1_mask2_offset); | |
299 | + writel(0x7fffffff, base + ccu_clk->policy2_mask2_offset); | |
300 | + writel(0x7fffffff, base + ccu_clk->policy3_mask2_offset); | |
301 | + } | |
302 | + | |
303 | + /* start policy engine */ | |
304 | + reg = readl(base + ccu_clk->policy_ctl_offset); | |
305 | + reg |= (POLICY_CTL_GO + POLICY_CTL_GO_ATL); | |
306 | + writel(reg, base + ccu_clk->policy_ctl_offset); | |
307 | + | |
308 | + /* wait till started */ | |
309 | + ret = wait_bit(base, ccu_clk->policy_ctl_offset, 0, 0); | |
310 | + if (ret) | |
311 | + return ret; | |
312 | + | |
313 | + /* disable access */ | |
314 | + writel(0, base + WR_ACCESS_OFFSET); | |
315 | + | |
316 | + return ret; | |
317 | +} | |
318 | + | |
319 | +/* Get the CCU clock rate */ | |
320 | +static unsigned long ccu_clk_get_rate(struct clk *c) | |
321 | +{ | |
322 | + struct ccu_clock *ccu_clk = to_ccu_clk(c); | |
323 | + debug("%s: %s\n", __func__, c->name); | |
324 | + c->rate = ccu_clk->freq_tbl[ccu_clk->freq_id]; | |
325 | + return c->rate; | |
326 | +} | |
327 | + | |
328 | +/* CCU clock operations */ | |
329 | +struct clk_ops ccu_clk_ops = { | |
330 | + .enable = ccu_clk_enable, | |
331 | + .get_rate = ccu_clk_get_rate, | |
332 | +}; | |
333 | + | |
334 | +/* Enable a bus clock */ | |
335 | +static int bus_clk_enable(struct clk *c, int enable) | |
336 | +{ | |
337 | + struct bus_clock *bus_clk = to_bus_clk(c); | |
338 | + struct bus_clk_data *cd = bus_clk->data; | |
339 | + void *base = (void *)c->ccu_clk_mgr_base; | |
340 | + int ret = 0; | |
341 | + u32 reg; | |
342 | + | |
343 | + debug("%s: %s\n", __func__, c->name); | |
344 | + /* enable access */ | |
345 | + writel(CLK_WR_ACCESS_PASSWORD, base + WR_ACCESS_OFFSET); | |
346 | + | |
347 | + /* enable gating */ | |
348 | + reg = readl(base + cd->gate.offset); | |
349 | + if (!!(reg & (1 << cd->gate.status_bit)) == !!enable) | |
350 | + debug("%s already %s\n", c->name, | |
351 | + enable ? "enabled" : "disabled"); | |
352 | + else { | |
353 | + int want = (enable) ? 1 : 0; | |
354 | + reg |= (1 << cd->gate.hw_sw_sel_bit); | |
355 | + | |
356 | + if (enable) | |
357 | + reg |= (1 << cd->gate.en_bit); | |
358 | + else | |
359 | + reg &= ~(1 << cd->gate.en_bit); | |
360 | + | |
361 | + writel(reg, base + cd->gate.offset); | |
362 | + ret = wait_bit(base, cd->gate.offset, cd->gate.status_bit, | |
363 | + want); | |
364 | + if (ret) | |
365 | + return ret; | |
366 | + } | |
367 | + | |
368 | + /* disable access */ | |
369 | + writel(0, base + WR_ACCESS_OFFSET); | |
370 | + | |
371 | + return ret; | |
372 | +} | |
373 | + | |
374 | +/* Get the rate of a bus clock */ | |
375 | +static unsigned long bus_clk_get_rate(struct clk *c) | |
376 | +{ | |
377 | + struct bus_clock *bus_clk = to_bus_clk(c); | |
378 | + struct ccu_clock *ccu_clk; | |
379 | + | |
380 | + debug("%s: %s\n", __func__, c->name); | |
381 | + ccu_clk = to_ccu_clk(c->parent); | |
382 | + | |
383 | + c->rate = bus_clk->freq_tbl[ccu_clk->freq_id]; | |
384 | + c->div = ccu_clk->freq_tbl[ccu_clk->freq_id] / c->rate; | |
385 | + return c->rate; | |
386 | +} | |
387 | + | |
388 | +/* Bus clock operations */ | |
389 | +struct clk_ops bus_clk_ops = { | |
390 | + .enable = bus_clk_enable, | |
391 | + .get_rate = bus_clk_get_rate, | |
392 | +}; | |
393 | + | |
394 | +/* Enable a reference clock */ | |
395 | +static int ref_clk_enable(struct clk *c, int enable) | |
396 | +{ | |
397 | + debug("%s: %s\n", __func__, c->name); | |
398 | + return 0; | |
399 | +} | |
400 | + | |
401 | +/* Reference clock operations */ | |
402 | +struct clk_ops ref_clk_ops = { | |
403 | + .enable = ref_clk_enable, | |
404 | +}; | |
405 | + | |
406 | +/* | |
407 | + * clk.h implementation follows | |
408 | + */ | |
409 | + | |
410 | +/* Initialize the clock framework */ | |
411 | +int clk_init(void) | |
412 | +{ | |
413 | + debug("%s:\n", __func__); | |
414 | + return 0; | |
415 | +} | |
416 | + | |
417 | +/* Get a clock handle, give a name string */ | |
418 | +struct clk *clk_get(const char *con_id) | |
419 | +{ | |
420 | + int i; | |
421 | + struct clk_lookup *clk_tblp; | |
422 | + | |
423 | + debug("%s: %s\n", __func__, con_id); | |
424 | + | |
425 | + clk_tblp = arch_clk_tbl; | |
426 | + for (i = 0; i < arch_clk_tbl_array_size; i++, clk_tblp++) { | |
427 | + if (clk_tblp->con_id) { | |
428 | + if (!con_id || strcmp(clk_tblp->con_id, con_id)) | |
429 | + continue; | |
430 | + return clk_tblp->clk; | |
431 | + } | |
432 | + } | |
433 | + return NULL; | |
434 | +} | |
435 | + | |
436 | +/* Enable a clock */ | |
437 | +int clk_enable(struct clk *c) | |
438 | +{ | |
439 | + int ret = 0; | |
440 | + | |
441 | + debug("%s: %s\n", __func__, c->name); | |
442 | + if (!c->ops || !c->ops->enable) | |
443 | + return -1; | |
444 | + | |
445 | + /* enable parent clock first */ | |
446 | + if (c->parent) | |
447 | + ret = clk_enable(c->parent); | |
448 | + | |
449 | + if (ret) | |
450 | + return ret; | |
451 | + | |
452 | + if (!c->use_cnt) { | |
453 | + c->use_cnt++; | |
454 | + ret = c->ops->enable(c, 1); | |
455 | + } | |
456 | + | |
457 | + return ret; | |
458 | +} | |
459 | + | |
460 | +/* Disable a clock */ | |
461 | +void clk_disable(struct clk *c) | |
462 | +{ | |
463 | + debug("%s: %s\n", __func__, c->name); | |
464 | + if (!c->ops || !c->ops->enable) | |
465 | + return; | |
466 | + | |
467 | + if (c->use_cnt) { | |
468 | + c->use_cnt--; | |
469 | + c->ops->enable(c, 0); | |
470 | + } | |
471 | + | |
472 | + /* disable parent */ | |
473 | + if (c->parent) | |
474 | + clk_disable(c->parent); | |
475 | +} | |
476 | + | |
477 | +/* Get the clock rate */ | |
478 | +unsigned long clk_get_rate(struct clk *c) | |
479 | +{ | |
480 | + unsigned long rate; | |
481 | + | |
482 | + debug("%s: %s\n", __func__, c->name); | |
483 | + if (!c || !c->ops || !c->ops->get_rate) | |
484 | + return 0; | |
485 | + | |
486 | + rate = c->ops->get_rate(c); | |
487 | + debug("%s: rate = %ld\n", __func__, rate); | |
488 | + return rate; | |
489 | +} | |
490 | + | |
491 | +/* Set the clock rate */ | |
492 | +int clk_set_rate(struct clk *c, unsigned long rate) | |
493 | +{ | |
494 | + int ret; | |
495 | + | |
496 | + debug("%s: %s rate=%ld\n", __func__, c->name, rate); | |
497 | + if (!c || !c->ops || !c->ops->set_rate) | |
498 | + return -EINVAL; | |
499 | + | |
500 | + if (c->use_cnt) | |
501 | + return -EINVAL; | |
502 | + | |
503 | + ret = c->ops->set_rate(c, rate); | |
504 | + | |
505 | + return ret; | |
506 | +} | |
507 | + | |
508 | +/* Not required for this arch */ | |
509 | +/* | |
510 | +long clk_round_rate(struct clk *clk, unsigned long rate); | |
511 | +int clk_set_parent(struct clk *clk, struct clk *parent); | |
512 | +struct clk *clk_get_parent(struct clk *clk); | |
513 | +*/ |
arch/arm/cpu/armv7/bcm235xx/clk-core.h
1 | +/* | |
2 | + * Copyright 2013 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#include <linux/stddef.h> | |
8 | + | |
9 | +#ifdef CONFIG_CLK_DEBUG | |
10 | +#undef writel | |
11 | +#undef readl | |
12 | +static inline void writel(u32 val, void *addr) | |
13 | +{ | |
14 | + printf("Write [0x%p] = 0x%08x\n", addr, val); | |
15 | + *(u32 *)addr = val; | |
16 | +} | |
17 | + | |
18 | +static inline u32 readl(void *addr) | |
19 | +{ | |
20 | + u32 val = *(u32 *)addr; | |
21 | + printf("Read [0x%p] = 0x%08x\n", addr, val); | |
22 | + return val; | |
23 | +} | |
24 | +#endif | |
25 | + | |
26 | +struct clk; | |
27 | + | |
28 | +struct clk_lookup { | |
29 | + const char *dev_id; | |
30 | + const char *con_id; | |
31 | + struct clk *clk; | |
32 | +}; | |
33 | + | |
34 | +extern struct clk_lookup arch_clk_tbl[]; | |
35 | +extern unsigned int arch_clk_tbl_array_size; | |
36 | + | |
37 | +/** | |
38 | + * struct clk_ops - standard clock operations | |
39 | + * @enable: enable/disable clock, see clk_enable() and clk_disable() | |
40 | + * @set_rate: set the clock rate, see clk_set_rate(). | |
41 | + * @get_rate: get the clock rate, see clk_get_rate(). | |
42 | + * @round_rate: round a given clock rate, see clk_round_rate(). | |
43 | + * @set_parent: set the clock's parent, see clk_set_parent(). | |
44 | + * | |
45 | + * Group the common clock implementations together so that we | |
46 | + * don't have to keep setting the same fiels again. We leave | |
47 | + * enable in struct clk. | |
48 | + * | |
49 | + */ | |
50 | +struct clk_ops { | |
51 | + int (*enable)(struct clk *c, int enable); | |
52 | + int (*set_rate)(struct clk *c, unsigned long rate); | |
53 | + unsigned long (*get_rate)(struct clk *c); | |
54 | + unsigned long (*round_rate)(struct clk *c, unsigned long rate); | |
55 | + int (*set_parent)(struct clk *c, struct clk *parent); | |
56 | +}; | |
57 | + | |
58 | +struct clk { | |
59 | + struct clk *parent; | |
60 | + const char *name; | |
61 | + int use_cnt; | |
62 | + unsigned long rate; /* in HZ */ | |
63 | + | |
64 | + /* programmable divider. 0 means fixed ratio to parent clock */ | |
65 | + unsigned long div; | |
66 | + | |
67 | + struct clk_src *src; | |
68 | + struct clk_ops *ops; | |
69 | + | |
70 | + unsigned long ccu_clk_mgr_base; | |
71 | + int sel; | |
72 | +}; | |
73 | + | |
74 | +struct refclk *refclk_str_to_clk(const char *name); | |
75 | + | |
76 | +/* The common clock framework uses u8 to represent a parent index */ | |
77 | +#define PARENT_COUNT_MAX ((u32)U8_MAX) | |
78 | + | |
79 | +#define BAD_CLK_INDEX U8_MAX /* Can't ever be valid */ | |
80 | +#define BAD_CLK_NAME ((const char *)-1) | |
81 | + | |
82 | +#define BAD_SCALED_DIV_VALUE U64_MAX | |
83 | + | |
84 | +/* | |
85 | + * Utility macros for object flag management. If possible, flags | |
86 | + * should be defined such that 0 is the desired default value. | |
87 | + */ | |
88 | +#define FLAG(type, flag) BCM_CLK_ ## type ## _FLAGS_ ## flag | |
89 | +#define FLAG_SET(obj, type, flag) ((obj)->flags |= FLAG(type, flag)) | |
90 | +#define FLAG_CLEAR(obj, type, flag) ((obj)->flags &= ~(FLAG(type, flag))) | |
91 | +#define FLAG_FLIP(obj, type, flag) ((obj)->flags ^= FLAG(type, flag)) | |
92 | +#define FLAG_TEST(obj, type, flag) (!!((obj)->flags & FLAG(type, flag))) | |
93 | + | |
94 | +/* Clock field state tests */ | |
95 | + | |
96 | +#define gate_exists(gate) FLAG_TEST(gate, GATE, EXISTS) | |
97 | +#define gate_is_enabled(gate) FLAG_TEST(gate, GATE, ENABLED) | |
98 | +#define gate_is_hw_controllable(gate) FLAG_TEST(gate, GATE, HW) | |
99 | +#define gate_is_sw_controllable(gate) FLAG_TEST(gate, GATE, SW) | |
100 | +#define gate_is_sw_managed(gate) FLAG_TEST(gate, GATE, SW_MANAGED) | |
101 | +#define gate_is_no_disable(gate) FLAG_TEST(gate, GATE, NO_DISABLE) | |
102 | + | |
103 | +#define gate_flip_enabled(gate) FLAG_FLIP(gate, GATE, ENABLED) | |
104 | + | |
105 | +#define divider_exists(div) FLAG_TEST(div, DIV, EXISTS) | |
106 | +#define divider_is_fixed(div) FLAG_TEST(div, DIV, FIXED) | |
107 | +#define divider_has_fraction(div) (!divider_is_fixed(div) && \ | |
108 | + (div)->frac_width > 0) | |
109 | + | |
110 | +#define selector_exists(sel) ((sel)->width != 0) | |
111 | +#define trigger_exists(trig) FLAG_TEST(trig, TRIG, EXISTS) | |
112 | + | |
113 | +/* Clock type, used to tell common block what it's part of */ | |
114 | +enum bcm_clk_type { | |
115 | + bcm_clk_none, /* undefined clock type */ | |
116 | + bcm_clk_bus, | |
117 | + bcm_clk_core, | |
118 | + bcm_clk_peri | |
119 | +}; | |
120 | + | |
121 | +/* | |
122 | + * Gating control and status is managed by a 32-bit gate register. | |
123 | + * | |
124 | + * There are several types of gating available: | |
125 | + * - (no gate) | |
126 | + * A clock with no gate is assumed to be always enabled. | |
127 | + * - hardware-only gating (auto-gating) | |
128 | + * Enabling or disabling clocks with this type of gate is | |
129 | + * managed automatically by the hardware. Such clocks can be | |
130 | + * considered by the software to be enabled. The current status | |
131 | + * of auto-gated clocks can be read from the gate status bit. | |
132 | + * - software-only gating | |
133 | + * Auto-gating is not available for this type of clock. | |
134 | + * Instead, software manages whether it's enabled by setting or | |
135 | + * clearing the enable bit. The current gate status of a gate | |
136 | + * under software control can be read from the gate status bit. | |
137 | + * To ensure a change to the gating status is complete, the | |
138 | + * status bit can be polled to verify that the gate has entered | |
139 | + * the desired state. | |
140 | + * - selectable hardware or software gating | |
141 | + * Gating for this type of clock can be configured to be either | |
142 | + * under software or hardware control. Which type is in use is | |
143 | + * determined by the hw_sw_sel bit of the gate register. | |
144 | + */ | |
145 | +struct bcm_clk_gate { | |
146 | + u32 offset; /* gate register offset */ | |
147 | + u32 status_bit; /* 0: gate is disabled; 0: gatge is enabled */ | |
148 | + u32 en_bit; /* 0: disable; 1: enable */ | |
149 | + u32 hw_sw_sel_bit; /* 0: hardware gating; 1: software gating */ | |
150 | + u32 flags; /* BCM_CLK_GATE_FLAGS_* below */ | |
151 | +}; | |
152 | + | |
153 | +/* | |
154 | + * Gate flags: | |
155 | + * HW means this gate can be auto-gated | |
156 | + * SW means the state of this gate can be software controlled | |
157 | + * NO_DISABLE means this gate is (only) enabled if under software control | |
158 | + * SW_MANAGED means the status of this gate is under software control | |
159 | + * ENABLED means this software-managed gate is *supposed* to be enabled | |
160 | + */ | |
161 | +#define BCM_CLK_GATE_FLAGS_EXISTS ((u32)1 << 0) /* Gate is valid */ | |
162 | +#define BCM_CLK_GATE_FLAGS_HW ((u32)1 << 1) /* Can auto-gate */ | |
163 | +#define BCM_CLK_GATE_FLAGS_SW ((u32)1 << 2) /* Software control */ | |
164 | +#define BCM_CLK_GATE_FLAGS_NO_DISABLE ((u32)1 << 3) /* HW or enabled */ | |
165 | +#define BCM_CLK_GATE_FLAGS_SW_MANAGED ((u32)1 << 4) /* SW now in control */ | |
166 | +#define BCM_CLK_GATE_FLAGS_ENABLED ((u32)1 << 5) /* If SW_MANAGED */ | |
167 | + | |
168 | +/* | |
169 | + * Gate initialization macros. | |
170 | + * | |
171 | + * Any gate initially under software control will be enabled. | |
172 | + */ | |
173 | + | |
174 | +/* A hardware/software gate initially under software control */ | |
175 | +#define HW_SW_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \ | |
176 | + { \ | |
177 | + .offset = (_offset), \ | |
178 | + .status_bit = (_status_bit), \ | |
179 | + .en_bit = (_en_bit), \ | |
180 | + .hw_sw_sel_bit = (_hw_sw_sel_bit), \ | |
181 | + .flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \ | |
182 | + FLAG(GATE, SW_MANAGED)|FLAG(GATE, ENABLED)| \ | |
183 | + FLAG(GATE, EXISTS), \ | |
184 | + } | |
185 | + | |
186 | +/* A hardware/software gate initially under hardware control */ | |
187 | +#define HW_SW_GATE_AUTO(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \ | |
188 | + { \ | |
189 | + .offset = (_offset), \ | |
190 | + .status_bit = (_status_bit), \ | |
191 | + .en_bit = (_en_bit), \ | |
192 | + .hw_sw_sel_bit = (_hw_sw_sel_bit), \ | |
193 | + .flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \ | |
194 | + FLAG(GATE, EXISTS), \ | |
195 | + } | |
196 | + | |
197 | +/* A hardware-or-enabled gate (enabled if not under hardware control) */ | |
198 | +#define HW_ENABLE_GATE(_offset, _status_bit, _en_bit, _hw_sw_sel_bit) \ | |
199 | + { \ | |
200 | + .offset = (_offset), \ | |
201 | + .status_bit = (_status_bit), \ | |
202 | + .en_bit = (_en_bit), \ | |
203 | + .hw_sw_sel_bit = (_hw_sw_sel_bit), \ | |
204 | + .flags = FLAG(GATE, HW)|FLAG(GATE, SW)| \ | |
205 | + FLAG(GATE, NO_DISABLE)|FLAG(GATE, EXISTS), \ | |
206 | + } | |
207 | + | |
208 | +/* A software-only gate */ | |
209 | +#define SW_ONLY_GATE(_offset, _status_bit, _en_bit) \ | |
210 | + { \ | |
211 | + .offset = (_offset), \ | |
212 | + .status_bit = (_status_bit), \ | |
213 | + .en_bit = (_en_bit), \ | |
214 | + .flags = FLAG(GATE, SW)|FLAG(GATE, SW_MANAGED)| \ | |
215 | + FLAG(GATE, ENABLED)|FLAG(GATE, EXISTS), \ | |
216 | + } | |
217 | + | |
218 | +/* A hardware-only gate */ | |
219 | +#define HW_ONLY_GATE(_offset, _status_bit) \ | |
220 | + { \ | |
221 | + .offset = (_offset), \ | |
222 | + .status_bit = (_status_bit), \ | |
223 | + .flags = FLAG(GATE, HW)|FLAG(GATE, EXISTS), \ | |
224 | + } | |
225 | + | |
226 | +/* | |
227 | + * Each clock can have zero, one, or two dividers which change the | |
228 | + * output rate of the clock. Each divider can be either fixed or | |
229 | + * variable. If there are two dividers, they are the "pre-divider" | |
230 | + * and the "regular" or "downstream" divider. If there is only one, | |
231 | + * there is no pre-divider. | |
232 | + * | |
233 | + * A fixed divider is any non-zero (positive) value, and it | |
234 | + * indicates how the input rate is affected by the divider. | |
235 | + * | |
236 | + * The value of a variable divider is maintained in a sub-field of a | |
237 | + * 32-bit divider register. The position of the field in the | |
238 | + * register is defined by its offset and width. The value recorded | |
239 | + * in this field is always 1 less than the value it represents. | |
240 | + * | |
241 | + * In addition, a variable divider can indicate that some subset | |
242 | + * of its bits represent a "fractional" part of the divider. Such | |
243 | + * bits comprise the low-order portion of the divider field, and can | |
244 | + * be viewed as representing the portion of the divider that lies to | |
245 | + * the right of the decimal point. Most variable dividers have zero | |
246 | + * fractional bits. Variable dividers with non-zero fraction width | |
247 | + * still record a value 1 less than the value they represent; the | |
248 | + * added 1 does *not* affect the low-order bit in this case, it | |
249 | + * affects the bits above the fractional part only. (Often in this | |
250 | + * code a divider field value is distinguished from the value it | |
251 | + * represents by referring to the latter as a "divisor".) | |
252 | + * | |
253 | + * In order to avoid dealing with fractions, divider arithmetic is | |
254 | + * performed using "scaled" values. A scaled value is one that's | |
255 | + * been left-shifted by the fractional width of a divider. Dividing | |
256 | + * a scaled value by a scaled divisor produces the desired quotient | |
257 | + * without loss of precision and without any other special handling | |
258 | + * for fractions. | |
259 | + * | |
260 | + * The recorded value of a variable divider can be modified. To | |
261 | + * modify either divider (or both), a clock must be enabled (i.e., | |
262 | + * using its gate). In addition, a trigger register (described | |
263 | + * below) must be used to commit the change, and polled to verify | |
264 | + * the change is complete. | |
265 | + */ | |
266 | +struct bcm_clk_div { | |
267 | + union { | |
268 | + struct { /* variable divider */ | |
269 | + u32 offset; /* divider register offset */ | |
270 | + u32 shift; /* field shift */ | |
271 | + u32 width; /* field width */ | |
272 | + u32 frac_width; /* field fraction width */ | |
273 | + | |
274 | + u64 scaled_div; /* scaled divider value */ | |
275 | + }; | |
276 | + u32 fixed; /* non-zero fixed divider value */ | |
277 | + }; | |
278 | + u32 flags; /* BCM_CLK_DIV_FLAGS_* below */ | |
279 | +}; | |
280 | + | |
281 | +/* | |
282 | + * Divider flags: | |
283 | + * EXISTS means this divider exists | |
284 | + * FIXED means it is a fixed-rate divider | |
285 | + */ | |
286 | +#define BCM_CLK_DIV_FLAGS_EXISTS ((u32)1 << 0) /* Divider is valid */ | |
287 | +#define BCM_CLK_DIV_FLAGS_FIXED ((u32)1 << 1) /* Fixed-value */ | |
288 | + | |
289 | +/* Divider initialization macros */ | |
290 | + | |
291 | +/* A fixed (non-zero) divider */ | |
292 | +#define FIXED_DIVIDER(_value) \ | |
293 | + { \ | |
294 | + .fixed = (_value), \ | |
295 | + .flags = FLAG(DIV, EXISTS)|FLAG(DIV, FIXED), \ | |
296 | + } | |
297 | + | |
298 | +/* A divider with an integral divisor */ | |
299 | +#define DIVIDER(_offset, _shift, _width) \ | |
300 | + { \ | |
301 | + .offset = (_offset), \ | |
302 | + .shift = (_shift), \ | |
303 | + .width = (_width), \ | |
304 | + .scaled_div = BAD_SCALED_DIV_VALUE, \ | |
305 | + .flags = FLAG(DIV, EXISTS), \ | |
306 | + } | |
307 | + | |
308 | +/* A divider whose divisor has an integer and fractional part */ | |
309 | +#define FRAC_DIVIDER(_offset, _shift, _width, _frac_width) \ | |
310 | + { \ | |
311 | + .offset = (_offset), \ | |
312 | + .shift = (_shift), \ | |
313 | + .width = (_width), \ | |
314 | + .frac_width = (_frac_width), \ | |
315 | + .scaled_div = BAD_SCALED_DIV_VALUE, \ | |
316 | + .flags = FLAG(DIV, EXISTS), \ | |
317 | + } | |
318 | + | |
319 | +/* | |
320 | + * Clocks may have multiple "parent" clocks. If there is more than | |
321 | + * one, a selector must be specified to define which of the parent | |
322 | + * clocks is currently in use. The selected clock is indicated in a | |
323 | + * sub-field of a 32-bit selector register. The range of | |
324 | + * representable selector values typically exceeds the number of | |
325 | + * available parent clocks. Occasionally the reset value of a | |
326 | + * selector field is explicitly set to a (specific) value that does | |
327 | + * not correspond to a defined input clock. | |
328 | + * | |
329 | + * We register all known parent clocks with the common clock code | |
330 | + * using a packed array (i.e., no empty slots) of (parent) clock | |
331 | + * names, and refer to them later using indexes into that array. | |
332 | + * We maintain an array of selector values indexed by common clock | |
333 | + * index values in order to map between these common clock indexes | |
334 | + * and the selector values used by the hardware. | |
335 | + * | |
336 | + * Like dividers, a selector can be modified, but to do so a clock | |
337 | + * must be enabled, and a trigger must be used to commit the change. | |
338 | + */ | |
339 | +struct bcm_clk_sel { | |
340 | + u32 offset; /* selector register offset */ | |
341 | + u32 shift; /* field shift */ | |
342 | + u32 width; /* field width */ | |
343 | + | |
344 | + u32 parent_count; /* number of entries in parent_sel[] */ | |
345 | + u32 *parent_sel; /* array of parent selector values */ | |
346 | + u8 clk_index; /* current selected index in parent_sel[] */ | |
347 | +}; | |
348 | + | |
349 | +/* Selector initialization macro */ | |
350 | +#define SELECTOR(_offset, _shift, _width) \ | |
351 | + { \ | |
352 | + .offset = (_offset), \ | |
353 | + .shift = (_shift), \ | |
354 | + .width = (_width), \ | |
355 | + .clk_index = BAD_CLK_INDEX, \ | |
356 | + } | |
357 | + | |
358 | +/* | |
359 | + * Making changes to a variable divider or a selector for a clock | |
360 | + * requires the use of a trigger. A trigger is defined by a single | |
361 | + * bit within a register. To signal a change, a 1 is written into | |
362 | + * that bit. To determine when the change has been completed, that | |
363 | + * trigger bit is polled; the read value will be 1 while the change | |
364 | + * is in progress, and 0 when it is complete. | |
365 | + * | |
366 | + * Occasionally a clock will have more than one trigger. In this | |
367 | + * case, the "pre-trigger" will be used when changing a clock's | |
368 | + * selector and/or its pre-divider. | |
369 | + */ | |
370 | +struct bcm_clk_trig { | |
371 | + u32 offset; /* trigger register offset */ | |
372 | + u32 bit; /* trigger bit */ | |
373 | + u32 flags; /* BCM_CLK_TRIG_FLAGS_* below */ | |
374 | +}; | |
375 | + | |
376 | +/* | |
377 | + * Trigger flags: | |
378 | + * EXISTS means this trigger exists | |
379 | + */ | |
380 | +#define BCM_CLK_TRIG_FLAGS_EXISTS ((u32)1 << 0) /* Trigger is valid */ | |
381 | + | |
382 | +/* Trigger initialization macro */ | |
383 | +#define TRIGGER(_offset, _bit) \ | |
384 | + { \ | |
385 | + .offset = (_offset), \ | |
386 | + .bit = (_bit), \ | |
387 | + .flags = FLAG(TRIG, EXISTS), \ | |
388 | + } | |
389 | + | |
390 | +struct bus_clk_data { | |
391 | + struct bcm_clk_gate gate; | |
392 | +}; | |
393 | + | |
394 | +struct core_clk_data { | |
395 | + struct bcm_clk_gate gate; | |
396 | +}; | |
397 | + | |
398 | +struct peri_clk_data { | |
399 | + struct bcm_clk_gate gate; | |
400 | + struct bcm_clk_trig pre_trig; | |
401 | + struct bcm_clk_div pre_div; | |
402 | + struct bcm_clk_trig trig; | |
403 | + struct bcm_clk_div div; | |
404 | + struct bcm_clk_sel sel; | |
405 | + const char *clocks[]; /* must be last; use CLOCKS() to declare */ | |
406 | +}; | |
407 | +#define CLOCKS(...) { __VA_ARGS__, NULL, } | |
408 | +#define NO_CLOCKS { NULL, } /* Must use of no parent clocks */ | |
409 | + | |
410 | +struct refclk { | |
411 | + struct clk clk; | |
412 | +}; | |
413 | + | |
414 | +struct peri_clock { | |
415 | + struct clk clk; | |
416 | + struct peri_clk_data *data; | |
417 | +}; | |
418 | + | |
419 | +struct ccu_clock { | |
420 | + struct clk clk; | |
421 | + | |
422 | + int num_policy_masks; | |
423 | + unsigned long policy_freq_offset; | |
424 | + int freq_bit_shift; /* 8 for most CCUs */ | |
425 | + unsigned long policy_ctl_offset; | |
426 | + unsigned long policy0_mask_offset; | |
427 | + unsigned long policy1_mask_offset; | |
428 | + unsigned long policy2_mask_offset; | |
429 | + unsigned long policy3_mask_offset; | |
430 | + unsigned long policy0_mask2_offset; | |
431 | + unsigned long policy1_mask2_offset; | |
432 | + unsigned long policy2_mask2_offset; | |
433 | + unsigned long policy3_mask2_offset; | |
434 | + unsigned long lvm_en_offset; | |
435 | + | |
436 | + int freq_id; | |
437 | + unsigned long *freq_tbl; | |
438 | +}; | |
439 | + | |
440 | +struct bus_clock { | |
441 | + struct clk clk; | |
442 | + struct bus_clk_data *data; | |
443 | + unsigned long *freq_tbl; | |
444 | +}; | |
445 | + | |
446 | +struct ref_clock { | |
447 | + struct clk clk; | |
448 | +}; | |
449 | + | |
450 | +static inline int is_same_clock(struct clk *a, struct clk *b) | |
451 | +{ | |
452 | + return a == b; | |
453 | +} | |
454 | + | |
455 | +#define to_clk(p) (&((p)->clk)) | |
456 | +#define name_to_clk(name) (&((name##_clk).clk)) | |
457 | +/* declare a struct clk_lookup */ | |
458 | +#define CLK_LK(name) \ | |
459 | +{.con_id = __stringify(name##_clk), .clk = name_to_clk(name),} | |
460 | + | |
461 | +static inline struct refclk *to_refclk(struct clk *clock) | |
462 | +{ | |
463 | + return container_of(clock, struct refclk, clk); | |
464 | +} | |
465 | + | |
466 | +static inline struct peri_clock *to_peri_clk(struct clk *clock) | |
467 | +{ | |
468 | + return container_of(clock, struct peri_clock, clk); | |
469 | +} | |
470 | + | |
471 | +static inline struct ccu_clock *to_ccu_clk(struct clk *clock) | |
472 | +{ | |
473 | + return container_of(clock, struct ccu_clock, clk); | |
474 | +} | |
475 | + | |
476 | +static inline struct bus_clock *to_bus_clk(struct clk *clock) | |
477 | +{ | |
478 | + return container_of(clock, struct bus_clock, clk); | |
479 | +} | |
480 | + | |
481 | +static inline struct ref_clock *to_ref_clk(struct clk *clock) | |
482 | +{ | |
483 | + return container_of(clock, struct ref_clock, clk); | |
484 | +} | |
485 | + | |
486 | +extern struct clk_ops peri_clk_ops; | |
487 | +extern struct clk_ops ccu_clk_ops; | |
488 | +extern struct clk_ops bus_clk_ops; | |
489 | +extern struct clk_ops ref_clk_ops; | |
490 | + | |
491 | +int clk_get_and_enable(char *clkstr); |
arch/arm/cpu/armv7/bcm235xx/clk-eth.c
1 | +/* | |
2 | + * Copyright 2014 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#include <common.h> | |
8 | +#include <asm/io.h> | |
9 | +#include <asm/errno.h> | |
10 | +#include <asm/arch/sysmap.h> | |
11 | +#include <asm/kona-common/clk.h> | |
12 | +#include "clk-core.h" | |
13 | + | |
14 | +#define WR_ACCESS_ADDR ESUB_CLK_BASE_ADDR | |
15 | +#define WR_ACCESS_PASSWORD 0xA5A500 | |
16 | + | |
17 | +#define PLLE_POST_RESETB_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C00) | |
18 | + | |
19 | +#define PLLE_RESETB_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C58) | |
20 | +#define PLLE_RESETB_I_PLL_RESETB_PLLE_MASK 0x00010000 | |
21 | +#define PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK 0x00000001 | |
22 | + | |
23 | +#define PLL_LOCK_ADDR (ESUB_CLK_BASE_ADDR + 0x00000C38) | |
24 | +#define PLL_LOCK_PLL_LOCK_PLLE_MASK 0x00000001 | |
25 | + | |
26 | +#define ESW_SYS_DIV_ADDR (ESUB_CLK_BASE_ADDR + 0x00000A04) | |
27 | +#define ESW_SYS_DIV_PLL_SELECT_MASK 0x00000300 | |
28 | +#define ESW_SYS_DIV_DIV_MASK 0x0000001C | |
29 | +#define ESW_SYS_DIV_PLL_VAR_208M_CLK_SELECT 0x00000100 | |
30 | +#define ESW_SYS_DIV_DIV_SELECT 0x4 | |
31 | +#define ESW_SYS_DIV_TRIGGER_MASK 0x00000001 | |
32 | + | |
33 | +#define ESUB_AXI_DIV_DEBUG_ADDR (ESUB_CLK_BASE_ADDR + 0x00000E04) | |
34 | +#define ESUB_AXI_DIV_DEBUG_PLL_SELECT_MASK 0x0000001C | |
35 | +#define ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK 0x00000040 | |
36 | +#define ESUB_AXI_DIV_DEBUG_PLL_VAR_208M_CLK_SELECT 0x0 | |
37 | +#define ESUB_AXI_DIV_DEBUG_TRIGGER_MASK 0x00000001 | |
38 | + | |
39 | +#define PLL_MAX_RETRY 100 | |
40 | + | |
41 | +/* Enable appropriate clocks for Ethernet */ | |
42 | +int clk_eth_enable(void) | |
43 | +{ | |
44 | + int rc = -1; | |
45 | + int retry_count = 0; | |
46 | + rc = clk_get_and_enable("esub_ccu_clk"); | |
47 | + | |
48 | + /* Enable Access to CCU registers */ | |
49 | + writel((1 | WR_ACCESS_PASSWORD), WR_ACCESS_ADDR); | |
50 | + | |
51 | + writel(readl(PLLE_POST_RESETB_ADDR) & | |
52 | + ~PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK, | |
53 | + PLLE_POST_RESETB_ADDR); | |
54 | + | |
55 | + /* Take PLL out of reset and put into normal mode */ | |
56 | + writel(readl(PLLE_RESETB_ADDR) | PLLE_RESETB_I_PLL_RESETB_PLLE_MASK, | |
57 | + PLLE_RESETB_ADDR); | |
58 | + | |
59 | + /* Wait for PLL lock */ | |
60 | + rc = -1; | |
61 | + while (retry_count < PLL_MAX_RETRY) { | |
62 | + udelay(100); | |
63 | + if (readl(PLL_LOCK_ADDR) & PLL_LOCK_PLL_LOCK_PLLE_MASK) { | |
64 | + rc = 0; | |
65 | + break; | |
66 | + } | |
67 | + retry_count++; | |
68 | + } | |
69 | + | |
70 | + if (rc == -1) { | |
71 | + printf("%s: ETH-PLL lock timeout, Ethernet is not enabled!\n", | |
72 | + __func__); | |
73 | + return -1; | |
74 | + } | |
75 | + | |
76 | + writel(readl(PLLE_POST_RESETB_ADDR) | | |
77 | + PLLE_POST_RESETB_I_POST_RESETB_PLLE_MASK, | |
78 | + PLLE_POST_RESETB_ADDR); | |
79 | + | |
80 | + /* Switch esw_sys_clk to use 104MHz(208MHz/2) clock */ | |
81 | + writel((readl(ESW_SYS_DIV_ADDR) & | |
82 | + ~(ESW_SYS_DIV_PLL_SELECT_MASK | ESW_SYS_DIV_DIV_MASK)) | | |
83 | + ESW_SYS_DIV_PLL_VAR_208M_CLK_SELECT | ESW_SYS_DIV_DIV_SELECT, | |
84 | + ESW_SYS_DIV_ADDR); | |
85 | + | |
86 | + writel(readl(ESW_SYS_DIV_ADDR) | ESW_SYS_DIV_TRIGGER_MASK, | |
87 | + ESW_SYS_DIV_ADDR); | |
88 | + | |
89 | + /* Wait for trigger complete */ | |
90 | + rc = -1; | |
91 | + retry_count = 0; | |
92 | + while (retry_count < PLL_MAX_RETRY) { | |
93 | + udelay(100); | |
94 | + if (!(readl(ESW_SYS_DIV_ADDR) & ESW_SYS_DIV_TRIGGER_MASK)) { | |
95 | + rc = 0; | |
96 | + break; | |
97 | + } | |
98 | + retry_count++; | |
99 | + } | |
100 | + | |
101 | + if (rc == -1) { | |
102 | + printf("%s: SYS CLK Trigger timeout, Ethernet is not enabled!\n", | |
103 | + __func__); | |
104 | + return -1; | |
105 | + } | |
106 | + | |
107 | + /* switch Esub AXI clock to 208MHz */ | |
108 | + writel((readl(ESUB_AXI_DIV_DEBUG_ADDR) & | |
109 | + ~(ESUB_AXI_DIV_DEBUG_PLL_SELECT_MASK | | |
110 | + ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK | | |
111 | + ESUB_AXI_DIV_DEBUG_TRIGGER_MASK)) | | |
112 | + ESUB_AXI_DIV_DEBUG_PLL_VAR_208M_CLK_SELECT | | |
113 | + ESUB_AXI_DIV_DEBUG_PLL_SELECT_OVERRIDE_MASK, | |
114 | + ESUB_AXI_DIV_DEBUG_ADDR); | |
115 | + | |
116 | + writel(readl(ESUB_AXI_DIV_DEBUG_ADDR) | | |
117 | + ESUB_AXI_DIV_DEBUG_TRIGGER_MASK, | |
118 | + ESUB_AXI_DIV_DEBUG_ADDR); | |
119 | + | |
120 | + /* Wait for trigger complete */ | |
121 | + rc = -1; | |
122 | + retry_count = 0; | |
123 | + while (retry_count < PLL_MAX_RETRY) { | |
124 | + udelay(100); | |
125 | + if (!(readl(ESUB_AXI_DIV_DEBUG_ADDR) & | |
126 | + ESUB_AXI_DIV_DEBUG_TRIGGER_MASK)) { | |
127 | + rc = 0; | |
128 | + break; | |
129 | + } | |
130 | + retry_count++; | |
131 | + } | |
132 | + | |
133 | + if (rc == -1) { | |
134 | + printf("%s: AXI CLK Trigger timeout, Ethernet is not enabled!\n", | |
135 | + __func__); | |
136 | + return -1; | |
137 | + } | |
138 | + | |
139 | + /* Disable Access to CCU registers */ | |
140 | + writel(WR_ACCESS_PASSWORD, WR_ACCESS_ADDR); | |
141 | + | |
142 | + return rc; | |
143 | +} |
arch/arm/cpu/armv7/bcm235xx/clk-sdio.c
1 | +/* | |
2 | + * Copyright 2013 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#include <common.h> | |
8 | +#include <asm/io.h> | |
9 | +#include <asm/errno.h> | |
10 | +#include <asm/arch/sysmap.h> | |
11 | +#include <asm/kona-common/clk.h> | |
12 | +#include "clk-core.h" | |
13 | + | |
14 | +/* Enable appropriate clocks for an SDIO port */ | |
15 | +int clk_sdio_enable(void *base, u32 rate, u32 *actual_ratep) | |
16 | +{ | |
17 | + int ret; | |
18 | + struct clk *c; | |
19 | + | |
20 | + char *clkstr; | |
21 | + char *slpstr; | |
22 | + char *ahbstr; | |
23 | + | |
24 | + switch ((u32) base) { | |
25 | + case CONFIG_SYS_SDIO_BASE0: | |
26 | + clkstr = CONFIG_SYS_SDIO0 "_clk"; | |
27 | + ahbstr = CONFIG_SYS_SDIO0 "_ahb_clk"; | |
28 | + slpstr = CONFIG_SYS_SDIO0 "_sleep_clk"; | |
29 | + break; | |
30 | + case CONFIG_SYS_SDIO_BASE1: | |
31 | + clkstr = CONFIG_SYS_SDIO1 "_clk"; | |
32 | + ahbstr = CONFIG_SYS_SDIO1 "_ahb_clk"; | |
33 | + slpstr = CONFIG_SYS_SDIO1 "_sleep_clk"; | |
34 | + break; | |
35 | + case CONFIG_SYS_SDIO_BASE2: | |
36 | + clkstr = CONFIG_SYS_SDIO2 "_clk"; | |
37 | + ahbstr = CONFIG_SYS_SDIO2 "_ahb_clk"; | |
38 | + slpstr = CONFIG_SYS_SDIO2 "_sleep_clk"; | |
39 | + break; | |
40 | + case CONFIG_SYS_SDIO_BASE3: | |
41 | + clkstr = CONFIG_SYS_SDIO3 "_clk"; | |
42 | + ahbstr = CONFIG_SYS_SDIO3 "_ahb_clk"; | |
43 | + slpstr = CONFIG_SYS_SDIO3 "_sleep_clk"; | |
44 | + break; | |
45 | + default: | |
46 | + printf("%s: base 0x%p not found\n", __func__, base); | |
47 | + return -EINVAL; | |
48 | + } | |
49 | + | |
50 | + ret = clk_get_and_enable(ahbstr); | |
51 | + if (ret) | |
52 | + return ret; | |
53 | + | |
54 | + ret = clk_get_and_enable(slpstr); | |
55 | + if (ret) | |
56 | + return ret; | |
57 | + | |
58 | + c = clk_get(clkstr); | |
59 | + if (c) { | |
60 | + ret = clk_set_rate(c, rate); | |
61 | + if (ret) | |
62 | + return ret; | |
63 | + | |
64 | + ret = clk_enable(c); | |
65 | + if (ret) | |
66 | + return ret; | |
67 | + } else { | |
68 | + printf("%s: Couldn't find %s\n", __func__, clkstr); | |
69 | + return -EINVAL; | |
70 | + } | |
71 | + *actual_ratep = rate; | |
72 | + return 0; | |
73 | +} |
arch/arm/cpu/armv7/bcm235xx/clk-usb-otg.c
1 | +/* | |
2 | + * Copyright 2014 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#include <common.h> | |
8 | +#include <asm/errno.h> | |
9 | +#include <asm/arch/sysmap.h> | |
10 | +#include "clk-core.h" | |
11 | + | |
12 | +/* Enable appropriate clocks for the USB OTG port */ | |
13 | +int clk_usb_otg_enable(void *base) | |
14 | +{ | |
15 | + char *ahbstr; | |
16 | + | |
17 | + switch ((u32) base) { | |
18 | + case HSOTG_BASE_ADDR: | |
19 | + ahbstr = "usb_otg_ahb_clk"; | |
20 | + break; | |
21 | + default: | |
22 | + printf("%s: base 0x%p not found\n", __func__, base); | |
23 | + return -EINVAL; | |
24 | + } | |
25 | + | |
26 | + return clk_get_and_enable(ahbstr); | |
27 | +} |
arch/arm/cpu/armv7/kona-common/Makefile
arch/arm/cpu/armv7/kona-common/reset.S
1 | +/* | |
2 | + * Copyright 2013 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +.globl reset_cpu | |
8 | +reset_cpu: | |
9 | + ldr r1, =0x35001f00 | |
10 | + ldr r2, [r1] | |
11 | + ldr r4, =0x80000000 | |
12 | + and r4, r2, r4 | |
13 | + ldr r3, =0xA5A500 | |
14 | + orr r4, r4, r3 | |
15 | + orr r4, r4, #0x1 | |
16 | + | |
17 | + str r4, [r1] | |
18 | + | |
19 | + ldr r1, =0x35001f04 | |
20 | + ldr r2, [r1] | |
21 | + ldr r4, =0x80000000 | |
22 | + and r4, r2, r4 | |
23 | + str r4, [r1] | |
24 | + | |
25 | +_loop_forever: | |
26 | + b _loop_forever |
arch/arm/include/asm/arch-bcm235xx/gpio.h
1 | +/* | |
2 | + * Copyright 2013 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#ifndef __ARCH_BCM235XX_GPIO_H | |
8 | +#define __ARCH_BCM235XX_GPIO_H | |
9 | + | |
10 | +/* | |
11 | + * Empty file - cmd_gpio.c requires this. The implementation | |
12 | + * is in drivers/gpio/kona_gpio.c instead of inlined here. | |
13 | + */ | |
14 | + | |
15 | +#endif |
arch/arm/include/asm/arch-bcm235xx/sysmap.h
1 | +/* | |
2 | + * Copyright 2013 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#ifndef __ARCH_BCM235XX_SYSMAP_H | |
8 | + | |
9 | +#define BSC1_BASE_ADDR 0x3e016000 | |
10 | +#define BSC2_BASE_ADDR 0x3e017000 | |
11 | +#define BSC3_BASE_ADDR 0x3e018000 | |
12 | +#define GPIO2_BASE_ADDR 0x35003000 | |
13 | +#define HSOTG_BASE_ADDR 0x3f120000 | |
14 | +#define HSOTG_CTRL_BASE_ADDR 0x3f130000 | |
15 | +#define KONA_MST_CLK_BASE_ADDR 0x3f001000 | |
16 | +#define KONA_SLV_CLK_BASE_ADDR 0x3e011000 | |
17 | +#define PMU_BSC_BASE_ADDR 0x3500d000 | |
18 | +#define SDIO1_BASE_ADDR 0x3f180000 | |
19 | +#define SDIO2_BASE_ADDR 0x3f190000 | |
20 | +#define SDIO3_BASE_ADDR 0x3f1a0000 | |
21 | +#define SDIO4_BASE_ADDR 0x3f1b0000 | |
22 | +#define TIMER_BASE_ADDR 0x3e00d000 | |
23 | + | |
24 | +#define HSOTG_DCTL_OFFSET 0x00000804 | |
25 | +#define HSOTG_DCTL_SFTDISCON_MASK 0x00000002 | |
26 | + | |
27 | +#define HSOTG_CTRL_PHY_P1CTL_OFFSET 0x00000008 | |
28 | +#define HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK 0x00000002 | |
29 | +#define HSOTG_CTRL_PHY_P1CTL_NON_DRIVING_MASK 0x00000001 | |
30 | + | |
31 | +#endif |
board/broadcom/bcm23550_w1d/Kconfig
board/broadcom/bcm23550_w1d/MAINTAINERS
board/broadcom/bcm23550_w1d/Makefile
board/broadcom/bcm23550_w1d/bcm23550_w1d.c
1 | +/* | |
2 | + * Copyright 2013 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#include <common.h> | |
8 | +#include <asm/io.h> | |
9 | +#include <asm/mach-types.h> | |
10 | +#include <mmc.h> | |
11 | +#include <asm/kona-common/kona_sdhci.h> | |
12 | +#include <asm/kona-common/clk.h> | |
13 | +#include <asm/arch/sysmap.h> | |
14 | + | |
15 | +#include <usb.h> | |
16 | +#include <usb/dwc2_udc.h> | |
17 | +#include <g_dnl.h> | |
18 | + | |
19 | +#define SECWATCHDOG_SDOGCR_OFFSET 0x00000000 | |
20 | +#define SECWATCHDOG_SDOGCR_EN_SHIFT 27 | |
21 | +#define SECWATCHDOG_SDOGCR_SRSTEN_SHIFT 26 | |
22 | +#define SECWATCHDOG_SDOGCR_CLKS_SHIFT 20 | |
23 | +#define SECWATCHDOG_SDOGCR_LD_SHIFT 0 | |
24 | + | |
25 | +#ifndef CONFIG_USB_SERIALNO | |
26 | +#define CONFIG_USB_SERIALNO "1234567890" | |
27 | +#endif | |
28 | + | |
29 | +DECLARE_GLOBAL_DATA_PTR; | |
30 | + | |
31 | +/* | |
32 | + * board_init - early hardware init | |
33 | + */ | |
34 | +int board_init(void) | |
35 | +{ | |
36 | + printf("Relocation Offset is: %08lx\n", gd->reloc_off); | |
37 | + | |
38 | + /* adress of boot parameters */ | |
39 | + gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100; | |
40 | + | |
41 | + clk_init(); | |
42 | + | |
43 | + return 0; | |
44 | +} | |
45 | + | |
46 | +/* | |
47 | + * misc_init_r - miscellaneous platform dependent initializations | |
48 | + */ | |
49 | +int misc_init_r(void) | |
50 | +{ | |
51 | + return 0; | |
52 | +} | |
53 | + | |
54 | +/* | |
55 | + * dram_init - sets uboots idea of sdram size | |
56 | + */ | |
57 | +int dram_init(void) | |
58 | +{ | |
59 | + gd->ram_size = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, | |
60 | + CONFIG_SYS_SDRAM_SIZE); | |
61 | + return 0; | |
62 | +} | |
63 | + | |
64 | +/* This is called after dram_init() so use get_ram_size result */ | |
65 | +void dram_init_banksize(void) | |
66 | +{ | |
67 | + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; | |
68 | + gd->bd->bi_dram[0].size = gd->ram_size; | |
69 | +} | |
70 | + | |
71 | +#ifdef CONFIG_KONA_SDHCI | |
72 | +/* | |
73 | + * mmc_init - Initializes mmc | |
74 | + */ | |
75 | +int board_mmc_init(bd_t *bis) | |
76 | +{ | |
77 | + int ret = 0; | |
78 | + | |
79 | + /* Register eMMC - SDIO2 */ | |
80 | + ret = kona_sdhci_init(1, 400000, 0); | |
81 | + if (ret) | |
82 | + return ret; | |
83 | + | |
84 | + /* Register SD Card - SDIO4 kona_mmc_init assumes 0 based index */ | |
85 | + ret = kona_sdhci_init(3, 400000, 0); | |
86 | + return ret; | |
87 | +} | |
88 | +#endif | |
89 | + | |
90 | +#ifdef CONFIG_USB_GADGET | |
91 | +static struct dwc2_plat_otg_data bcm_otg_data = { | |
92 | + .regs_otg = HSOTG_BASE_ADDR | |
93 | +}; | |
94 | + | |
95 | +int board_usb_init(int index, enum usb_init_type init) | |
96 | +{ | |
97 | + debug("%s: performing dwc2_udc_probe\n", __func__); | |
98 | + return dwc2_udc_probe(&bcm_otg_data); | |
99 | +} | |
100 | + | |
101 | +int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) | |
102 | +{ | |
103 | + debug("%s\n", __func__); | |
104 | + if (!getenv("serial#")) | |
105 | + g_dnl_set_serialnumber(CONFIG_USB_SERIALNO); | |
106 | + return 0; | |
107 | +} | |
108 | + | |
109 | +int g_dnl_get_board_bcd_device_number(int gcnum) | |
110 | +{ | |
111 | + debug("%s\n", __func__); | |
112 | + return 1; | |
113 | +} | |
114 | + | |
115 | +int board_usb_cleanup(int index, enum usb_init_type init) | |
116 | +{ | |
117 | + debug("%s\n", __func__); | |
118 | + return 0; | |
119 | +} | |
120 | +#endif |
configs/bcm23550_w1d_defconfig
1 | +CONFIG_ARM=y | |
2 | +CONFIG_TARGET_BCM23550_W1D=y | |
3 | +CONFIG_HUSH_PARSER=y | |
4 | +CONFIG_CMD_BOOTZ=y | |
5 | +# CONFIG_CMD_IMLS is not set | |
6 | +CONFIG_CMD_ASKENV=y | |
7 | +# CONFIG_CMD_FLASH is not set | |
8 | +CONFIG_CMD_MMC=y | |
9 | +CONFIG_CMD_I2C=y | |
10 | +CONFIG_CMD_GPIO=y | |
11 | +# CONFIG_CMD_SETEXPR is not set | |
12 | +# CONFIG_CMD_NET is not set | |
13 | +# CONFIG_CMD_NFS is not set | |
14 | +CONFIG_CMD_CACHE=y | |
15 | +CONFIG_CMD_FAT=y | |
16 | +CONFIG_SYS_NS16550=y | |
17 | +CONFIG_USB=y | |
18 | +CONFIG_USB_GADGET=y | |
19 | +CONFIG_USB_GADGET_DWC2_OTG=y | |
20 | +CONFIG_USB_GADGET_DOWNLOAD=y | |
21 | +CONFIG_G_DNL_MANUFACTURER="Broadcom Corporation" | |
22 | +CONFIG_G_DNL_VENDOR_NUM=0x18d1 | |
23 | +CONFIG_G_DNL_PRODUCT_NUM=0x0d02 | |
24 | +CONFIG_OF_LIBFDT=y |
include/configs/bcm23550_w1d.h
1 | +/* | |
2 | + * Copyright 2013 Broadcom Corporation. | |
3 | + * | |
4 | + * SPDX-License-Identifier: GPL-2.0+ | |
5 | + */ | |
6 | + | |
7 | +#ifndef __BCM23550_W1D_H | |
8 | +#define __BCM23550_W1D_H | |
9 | + | |
10 | +#include <linux/sizes.h> | |
11 | +#include <asm/arch/sysmap.h> | |
12 | + | |
13 | +/* CPU, chip, mach, etc */ | |
14 | +#define CONFIG_KONA | |
15 | +#define CONFIG_SKIP_LOWLEVEL_INIT | |
16 | +#define CONFIG_KONA_RESET_S | |
17 | + | |
18 | +/* | |
19 | + * Memory configuration | |
20 | + */ | |
21 | +#define CONFIG_SYS_TEXT_BASE 0x9f000000 | |
22 | + | |
23 | +#define CONFIG_SYS_SDRAM_BASE 0x80000000 | |
24 | +#define CONFIG_SYS_SDRAM_SIZE 0x20000000 | |
25 | +#define CONFIG_NR_DRAM_BANKS 1 | |
26 | + | |
27 | +#define CONFIG_SYS_MALLOC_LEN SZ_4M /* see armv7/start.S. */ | |
28 | +#define CONFIG_STACKSIZE SZ_256K | |
29 | + | |
30 | +/* GPIO Driver */ | |
31 | +#define CONFIG_KONA_GPIO | |
32 | + | |
33 | +/* MMC/SD Driver */ | |
34 | +#define CONFIG_SDHCI | |
35 | +#define CONFIG_MMC_SDMA | |
36 | +#define CONFIG_KONA_SDHCI | |
37 | +#define CONFIG_MMC | |
38 | +#define CONFIG_GENERIC_MMC | |
39 | + | |
40 | +#define CONFIG_SYS_SDIO_BASE0 SDIO1_BASE_ADDR | |
41 | +#define CONFIG_SYS_SDIO_BASE1 SDIO2_BASE_ADDR | |
42 | +#define CONFIG_SYS_SDIO_BASE2 SDIO3_BASE_ADDR | |
43 | +#define CONFIG_SYS_SDIO_BASE3 SDIO4_BASE_ADDR | |
44 | +#define CONFIG_SYS_SDIO0_MAX_CLK 48000000 | |
45 | +#define CONFIG_SYS_SDIO1_MAX_CLK 48000000 | |
46 | +#define CONFIG_SYS_SDIO2_MAX_CLK 48000000 | |
47 | +#define CONFIG_SYS_SDIO3_MAX_CLK 48000000 | |
48 | +#define CONFIG_SYS_SDIO0 "sdio1" | |
49 | +#define CONFIG_SYS_SDIO1 "sdio2" | |
50 | +#define CONFIG_SYS_SDIO2 "sdio3" | |
51 | +#define CONFIG_SYS_SDIO3 "sdio4" | |
52 | + | |
53 | +/* I2C Driver */ | |
54 | +#define CONFIG_SYS_I2C | |
55 | +#define CONFIG_SYS_I2C_KONA | |
56 | +#define CONFIG_SYS_SPD_BUS_NUM 3 /* Start with PMU bus */ | |
57 | +#define CONFIG_SYS_MAX_I2C_BUS 4 | |
58 | +#define CONFIG_SYS_I2C_BASE0 BSC1_BASE_ADDR | |
59 | +#define CONFIG_SYS_I2C_BASE1 BSC2_BASE_ADDR | |
60 | +#define CONFIG_SYS_I2C_BASE2 BSC3_BASE_ADDR | |
61 | +#define CONFIG_SYS_I2C_BASE3 PMU_BSC_BASE_ADDR | |
62 | + | |
63 | +/* Timer Driver */ | |
64 | +#define CONFIG_SYS_TIMER_RATE 32000 | |
65 | +#define CONFIG_SYS_TIMER_COUNTER (TIMER_BASE_ADDR + 4) /* STCLO offset */ | |
66 | + | |
67 | +/* Init functions */ | |
68 | +#define CONFIG_MISC_INIT_R /* board's misc_init_r function */ | |
69 | + | |
70 | +/* Some commands use this as the default load address */ | |
71 | +#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_SDRAM_BASE | |
72 | + | |
73 | +/* No mtest functions as recommended */ | |
74 | + | |
75 | +/* | |
76 | + * This is the initial SP which is used only briefly for relocating the u-boot | |
77 | + * image to the top of SDRAM. After relocation u-boot moves the stack to the | |
78 | + * proper place. | |
79 | + */ | |
80 | +#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_TEXT_BASE | |
81 | + | |
82 | +/* Serial Info */ | |
83 | +#define CONFIG_SYS_NS16550_SERIAL | |
84 | +/* Post pad 3 bytes after each reg addr */ | |
85 | +#define CONFIG_SYS_NS16550_REG_SIZE (-4) | |
86 | +#define CONFIG_SYS_NS16550_CLK 13000000 | |
87 | +#define CONFIG_CONS_INDEX 1 | |
88 | +#define CONFIG_SYS_NS16550_COM1 0x3e000000 | |
89 | + | |
90 | +#define CONFIG_BAUDRATE 115200 | |
91 | + | |
92 | +/* must fit into GPT:u-boot-env partition */ | |
93 | +#define CONFIG_ENV_IS_IN_MMC | |
94 | +#define CONFIG_SYS_MMC_ENV_DEV 0 | |
95 | +#define CONFIG_ENV_OFFSET (0x00011a00 * 512) | |
96 | +#define CONFIG_ENV_SIZE (8 * 512) | |
97 | + | |
98 | +#define CONFIG_SYS_NO_FLASH /* Not using NAND/NOR unmanaged flash */ | |
99 | + | |
100 | +/* console configuration */ | |
101 | +#define CONFIG_SYS_CBSIZE 1024 /* Console buffer size */ | |
102 | +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \ | |
103 | + sizeof(CONFIG_SYS_PROMPT) + 16) /* Printbuffer size */ | |
104 | +#define CONFIG_SYS_MAXARGS 64 | |
105 | +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE | |
106 | + | |
107 | +/* | |
108 | + * One partition type must be defined for part.c | |
109 | + * This is necessary for the fatls command to work on an SD card | |
110 | + * for example. | |
111 | + */ | |
112 | +#define CONFIG_DOS_PARTITION | |
113 | +#define CONFIG_EFI_PARTITION | |
114 | + | |
115 | +/* version string, parser, etc */ | |
116 | +#define CONFIG_VERSION_VARIABLE | |
117 | +#define CONFIG_AUTO_COMPLETE | |
118 | +#define CONFIG_CMDLINE_EDITING | |
119 | +#define CONFIG_SYS_LONGHELP | |
120 | + | |
121 | +#define CONFIG_CRC32_VERIFY | |
122 | +#define CONFIG_MX_CYCLIC | |
123 | + | |
124 | +/* Initial upstream - boot to cmd prompt only */ | |
125 | +#define CONFIG_BOOTCOMMAND "" | |
126 | + | |
127 | +/* Commands */ | |
128 | +#define CONFIG_FAT_WRITE | |
129 | + | |
130 | +/* Fastboot and USB OTG */ | |
131 | +#define CONFIG_USB_FUNCTION_FASTBOOT | |
132 | +#define CONFIG_CMD_FASTBOOT | |
133 | +#define CONFIG_FASTBOOT_FLASH | |
134 | +#define CONFIG_FASTBOOT_FLASH_MMC_DEV 0 | |
135 | +#define CONFIG_SYS_CACHELINE_SIZE 64 | |
136 | +#define CONFIG_FASTBOOT_BUF_SIZE 0x1d000000 | |
137 | +#define CONFIG_FASTBOOT_BUF_ADDR CONFIG_SYS_SDRAM_BASE | |
138 | +#undef CONFIG_USB_GADGET_VBUS_DRAW | |
139 | +#define CONFIG_USB_GADGET_VBUS_DRAW 0 | |
140 | +#define CONFIG_USB_GADGET_DWC2_PHY_8_BIT | |
141 | +#define CONFIG_USB_GADGET_BCM_UDC_OTG_PHY | |
142 | +#define CONFIG_USBID_ADDR 0x34052c46 | |
143 | + | |
144 | +#define CONFIG_SYS_ICACHE_OFF | |
145 | +#define CONFIG_SYS_DCACHE_OFF | |
146 | +#define CONFIG_SYS_L2CACHE_OFF | |
147 | + | |
148 | +#endif /* __BCM23550_W1D_H */ |