blob: 8ccd84ca600d875559665ed2067464d57dd5756e [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Alexey Brodkin67482f52016-11-25 16:23:43 +03002/*
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03003 * Copyright (C) 2018 Synopsys, Inc. All rights reserved.
4 * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
Alexey Brodkin67482f52016-11-25 16:23:43 +03005 */
6
7#include <common.h>
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03008#include <config.h>
Simon Glass9edefc22019-11-14 12:57:37 -07009#include <cpu_func.h>
Simon Glass168068f2019-08-01 09:46:47 -060010#include <env.h>
Simon Glass52559322019-11-14 12:57:46 -070011#include <init.h>
Simon Glass36bf4462019-11-14 12:57:42 -070012#include <irq_func.h>
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +030013#include <linux/printk.h>
14#include <linux/kernel.h>
15#include <linux/io.h>
16#include <asm/arcregs.h>
17#include <fdt_support.h>
Alexey Brodkin67482f52016-11-25 16:23:43 +030018#include <dwmmc.h>
19#include <malloc.h>
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +030020#include <usb.h>
21
22#include "clk-lib.h"
23#include "env-lib.h"
Alexey Brodkin67482f52016-11-25 16:23:43 +030024
25DECLARE_GLOBAL_DATA_PTR;
26
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +030027#define ALL_CPU_MASK GENMASK(NR_CPUS - 1, 0)
28#define MASTER_CPU_ID 0
29#define APERTURE_SHIFT 28
30#define NO_CCM 0x10
31#define SLAVE_CPU_READY 0x12345678
32#define BOOTSTAGE_1 1 /* after SP, FP setup, before HW init */
33#define BOOTSTAGE_2 2 /* after HW init, before self halt */
34#define BOOTSTAGE_3 3 /* after self halt */
35#define BOOTSTAGE_4 4 /* before app launch */
36#define BOOTSTAGE_5 5 /* after app launch, unreachable */
Alexey Brodkin67482f52016-11-25 16:23:43 +030037
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +030038#define RESET_VECTOR_ADDR 0x0
39
40#define CREG_BASE (ARC_PERIPHERAL_BASE + 0x1000)
41#define CREG_CPU_START (CREG_BASE + 0x400)
42#define CREG_CPU_START_MASK 0xF
Eugeniy Paltsev4b4da7f2020-01-16 19:22:32 +030043#define CREG_CPU_START_POL BIT(4)
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +030044
Eugeniy Paltseva8eb9b22020-04-29 21:36:44 +030045#define CREG_CORE_BOOT_IMAGE GENMASK(5, 4)
46
Eugeniy Paltsev25998ae2020-04-24 23:11:10 +030047#define CREG_CPU_0_ENTRY (CREG_BASE + 0x404)
48
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +030049#define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xA000)
50#define SDIO_UHS_REG_EXT (SDIO_BASE + 0x108)
51#define SDIO_UHS_REG_EXT_DIV_2 (2 << 30)
52
53/* Uncached access macros */
54#define arc_read_uncached_32(ptr) \
55({ \
56 unsigned int __ret; \
57 __asm__ __volatile__( \
58 " ld.di %0, [%1] \n" \
59 : "=r"(__ret) \
60 : "r"(ptr)); \
61 __ret; \
62})
63
64#define arc_write_uncached_32(ptr, data)\
65({ \
66 __asm__ __volatile__( \
67 " st.di %0, [%1] \n" \
68 : \
69 : "r"(data), "r"(ptr)); \
70})
71
72struct hsdk_env_core_ctl {
73 u32_env entry[NR_CPUS];
74 u32_env iccm[NR_CPUS];
75 u32_env dccm[NR_CPUS];
76};
77
78struct hsdk_env_common_ctl {
79 bool halt_on_boot;
80 u32_env core_mask;
81 u32_env cpu_freq;
82 u32_env axi_freq;
83 u32_env tun_freq;
84 u32_env nvlim;
85 u32_env icache;
86 u32_env dcache;
Eugeniy Paltsev6917a9d2020-03-23 21:50:03 +030087 u32_env csm_location;
Eugeniy Paltsev1d897d12020-03-23 20:46:35 +030088 u32_env l2_cache;
Eugeniy Paltsev32ac4ee2020-03-25 12:35:49 +030089 u32_env haps_apb;
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +030090};
91
92/*
93 * Uncached cross-cpu structure. All CPUs must access to this structure fields
94 * only with arc_read_uncached_32() / arc_write_uncached_32() accessors (which
95 * implement ld.di / st.di instructions). Simultaneous cached and uncached
96 * access to this area will lead to data loss.
97 * We flush all data caches in board_early_init_r() as we don't want to have
98 * any dirty line in L1d$ or SL$ in this area.
99 */
100struct hsdk_cross_cpu {
101 /* slave CPU ready flag */
102 u32 ready_flag;
103 /* address of the area, which can be used for stack by slave CPU */
104 u32 stack_ptr;
105 /* slave CPU status - bootstage number */
106 s32 status[NR_CPUS];
107
108 /*
109 * Slave CPU data - it is copy of corresponding fields in
110 * hsdk_env_core_ctl and hsdk_env_common_ctl structures which are
111 * required for slave CPUs initialization.
112 * This fields can be populated by copying from hsdk_env_core_ctl
113 * and hsdk_env_common_ctl structures with sync_cross_cpu_data()
114 * function.
115 */
116 u32 entry[NR_CPUS];
117 u32 iccm[NR_CPUS];
118 u32 dccm[NR_CPUS];
119
120 u32 core_mask;
121 u32 icache;
122 u32 dcache;
123
124 u8 cache_padding[ARCH_DMA_MINALIGN];
125} __aligned(ARCH_DMA_MINALIGN);
126
127/* Place for slave CPUs temporary stack */
128static u32 slave_stack[256 * NR_CPUS] __aligned(ARCH_DMA_MINALIGN);
129
130static struct hsdk_env_common_ctl env_common = {};
131static struct hsdk_env_core_ctl env_core = {};
132static struct hsdk_cross_cpu cross_cpu_data;
133
134static const struct env_map_common env_map_common[] = {
135 { "core_mask", ENV_HEX, true, 0x1, 0xF, &env_common.core_mask },
136 { "non_volatile_limit", ENV_HEX, true, 0, 0xF, &env_common.nvlim },
137 { "icache_ena", ENV_HEX, true, 0, 1, &env_common.icache },
138 { "dcache_ena", ENV_HEX, true, 0, 1, &env_common.dcache },
Eugeniy Paltsev1d897d12020-03-23 20:46:35 +0300139#if defined(CONFIG_BOARD_HSDK_4XD)
140 { "l2_cache_ena", ENV_HEX, true, 0, 1, &env_common.l2_cache },
Eugeniy Paltsev6917a9d2020-03-23 21:50:03 +0300141 { "csm_location", ENV_HEX, true, 0, NO_CCM, &env_common.csm_location },
Eugeniy Paltsev32ac4ee2020-03-25 12:35:49 +0300142 { "haps_apb_location", ENV_HEX, true, 0, 1, &env_common.haps_apb },
Eugeniy Paltsev1d897d12020-03-23 20:46:35 +0300143#endif /* CONFIG_BOARD_HSDK_4XD */
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300144 {}
145};
146
147static const struct env_map_common env_map_clock[] = {
148 { "cpu_freq", ENV_DEC, false, 100, 1000, &env_common.cpu_freq },
149 { "axi_freq", ENV_DEC, false, 200, 800, &env_common.axi_freq },
150 { "tun_freq", ENV_DEC, false, 0, 150, &env_common.tun_freq },
151 {}
152};
153
154static const struct env_map_percpu env_map_core[] = {
155 { "core_iccm", ENV_HEX, true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.iccm },
156 { "core_dccm", ENV_HEX, true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.dccm },
157 {}
158};
159
160static const struct env_map_common env_map_mask[] = {
161 { "core_mask", ENV_HEX, false, 0x1, 0xF, &env_common.core_mask },
162 {}
163};
164
165static const struct env_map_percpu env_map_go[] = {
166 { "core_entry", ENV_HEX, true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry },
167 {}
168};
169
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +0300170enum board_type {
171 T_BOARD_NONE,
172 T_BOARD_HSDK,
173 T_BOARD_HSDK_4XD
174};
175
176static inline enum board_type get_board_type_runtime(void)
177{
178 u32 arc_id = read_aux_reg(ARC_AUX_IDENTITY) & 0xFF;
179
180 if (arc_id == 0x52)
181 return T_BOARD_HSDK;
182 else if (arc_id == 0x54)
183 return T_BOARD_HSDK_4XD;
184 else
185 return T_BOARD_NONE;
186}
187
188static inline enum board_type get_board_type_config(void)
189{
190 if (IS_ENABLED(CONFIG_BOARD_HSDK))
191 return T_BOARD_HSDK;
192 else if (IS_ENABLED(CONFIG_BOARD_HSDK_4XD))
193 return T_BOARD_HSDK_4XD;
194 else
195 return T_BOARD_NONE;
196}
197
198static bool is_board_match_runtime(enum board_type type_req)
199{
200 return get_board_type_runtime() == type_req;
201}
202
Eugeniy Paltsev1d897d12020-03-23 20:46:35 +0300203static bool is_board_match_config(enum board_type type_req)
204{
205 return get_board_type_config() == type_req;
206}
207
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +0300208static const char * board_name(enum board_type type)
209{
210 switch (type) {
211 case T_BOARD_HSDK:
212 return "ARC HS Development Kit";
213 case T_BOARD_HSDK_4XD:
214 return "ARC HS4x/HS4xD Development Kit";
215 default:
216 return "?";
217 }
218}
219
220static bool board_mismatch(void)
221{
222 return get_board_type_config() != get_board_type_runtime();
223}
224
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300225static void sync_cross_cpu_data(void)
Alexey Brodkin67482f52016-11-25 16:23:43 +0300226{
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300227 u32 value;
Alexey Brodkin67482f52016-11-25 16:23:43 +0300228
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300229 for (u32 i = 0; i < NR_CPUS; i++) {
230 value = env_core.entry[i].val;
231 arc_write_uncached_32(&cross_cpu_data.entry[i], value);
232 }
233
234 for (u32 i = 0; i < NR_CPUS; i++) {
235 value = env_core.iccm[i].val;
236 arc_write_uncached_32(&cross_cpu_data.iccm[i], value);
237 }
238
239 for (u32 i = 0; i < NR_CPUS; i++) {
240 value = env_core.dccm[i].val;
241 arc_write_uncached_32(&cross_cpu_data.dccm[i], value);
242 }
243
244 value = env_common.core_mask.val;
245 arc_write_uncached_32(&cross_cpu_data.core_mask, value);
246
247 value = env_common.icache.val;
248 arc_write_uncached_32(&cross_cpu_data.icache, value);
249
250 value = env_common.dcache.val;
251 arc_write_uncached_32(&cross_cpu_data.dcache, value);
252}
253
254/* Can be used only on master CPU */
255static bool is_cpu_used(u32 cpu_id)
256{
257 return !!(env_common.core_mask.val & BIT(cpu_id));
258}
259
260/* TODO: add ICCM BCR and DCCM BCR runtime check */
261static void init_slave_cpu_func(u32 core)
262{
263 u32 val;
264
265 /* Remap ICCM to another memory region if it exists */
266 val = arc_read_uncached_32(&cross_cpu_data.iccm[core]);
267 if (val != NO_CCM)
268 write_aux_reg(ARC_AUX_ICCM_BASE, val << APERTURE_SHIFT);
269
270 /* Remap DCCM to another memory region if it exists */
271 val = arc_read_uncached_32(&cross_cpu_data.dccm[core]);
272 if (val != NO_CCM)
273 write_aux_reg(ARC_AUX_DCCM_BASE, val << APERTURE_SHIFT);
274
275 if (arc_read_uncached_32(&cross_cpu_data.icache))
276 icache_enable();
277 else
278 icache_disable();
279
280 if (arc_read_uncached_32(&cross_cpu_data.dcache))
281 dcache_enable();
282 else
283 dcache_disable();
284}
285
286static void init_cluster_nvlim(void)
287{
288 u32 val = env_common.nvlim.val << APERTURE_SHIFT;
289
290 flush_dcache_all();
291 write_aux_reg(ARC_AUX_NON_VOLATILE_LIMIT, val);
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +0300292 /* AUX_AUX_CACHE_LIMIT reg is missing starting from HS48 */
293 if (is_board_match_runtime(T_BOARD_HSDK))
294 write_aux_reg(AUX_AUX_CACHE_LIMIT, val);
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300295 flush_n_invalidate_dcache_all();
296}
297
Eugeniy Paltsev1d897d12020-03-23 20:46:35 +0300298static void init_cluster_slc(void)
299{
300 /* ARC HS38 doesn't support SLC disabling */
301 if (!is_board_match_config(T_BOARD_HSDK_4XD))
302 return;
303
304 if (env_common.l2_cache.val)
305 slc_enable();
306 else
307 slc_disable();
308}
309
Eugeniy Paltsev6917a9d2020-03-23 21:50:03 +0300310#define CREG_CSM_BASE (CREG_BASE + 0x210)
311
312static void init_cluster_csm(void)
313{
314 /* ARC HS38 in HSDK SoC doesn't include CSM */
315 if (!is_board_match_config(T_BOARD_HSDK_4XD))
316 return;
317
318 if (env_common.csm_location.val == NO_CCM) {
319 write_aux_reg(ARC_AUX_CSM_ENABLE, 0);
320 } else {
321 /*
322 * CSM base address is 256kByte aligned but we allow to map
323 * CSM only to aperture start (256MByte aligned)
324 * The field in CREG_CSM_BASE is in 17:2 bits itself so we need
325 * to shift it.
326 */
327 u32 csm_base = (env_common.csm_location.val * SZ_1K) << 2;
328
329 write_aux_reg(ARC_AUX_CSM_ENABLE, 1);
330 writel(csm_base, (void __iomem *)CREG_CSM_BASE);
331 }
332}
333
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300334static void init_master_icache(void)
335{
336 if (icache_status()) {
337 /* I$ is enabled - we need to disable it */
338 if (!env_common.icache.val)
339 icache_disable();
340 } else {
341 /* I$ is disabled - we need to enable it */
342 if (env_common.icache.val) {
343 icache_enable();
344
345 /* invalidate I$ right after enable */
346 invalidate_icache_all();
347 }
348 }
349}
350
351static void init_master_dcache(void)
352{
353 if (dcache_status()) {
354 /* D$ is enabled - we need to disable it */
355 if (!env_common.dcache.val)
356 dcache_disable();
357 } else {
358 /* D$ is disabled - we need to enable it */
359 if (env_common.dcache.val)
360 dcache_enable();
361
362 /* TODO: probably we need ti invalidate D$ right after enable */
363 }
364}
365
366static int cleanup_before_go(void)
367{
368 disable_interrupts();
369 sync_n_cleanup_cache_all();
Alexey Brodkin67482f52016-11-25 16:23:43 +0300370
371 return 0;
372}
373
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300374void slave_cpu_set_boot_addr(u32 addr)
375{
376 /* All cores have reset vector pointing to 0 */
377 writel(addr, (void __iomem *)RESET_VECTOR_ADDR);
378
379 /* Make sure other cores see written value in memory */
380 sync_n_cleanup_cache_all();
381}
382
383static inline void halt_this_cpu(void)
384{
385 __builtin_arc_flag(1);
386}
387
Eugeniy Paltsev4b4da7f2020-01-16 19:22:32 +0300388static u32 get_masked_cpu_ctart_reg(void)
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300389{
390 int cmd = readl((void __iomem *)CREG_CPU_START);
391
Eugeniy Paltsev4b4da7f2020-01-16 19:22:32 +0300392 /*
393 * Quirk for HSDK-4xD - due to HW issues HSDK can use any pulse polarity
394 * and HSDK-4xD require active low polarity of cpu_start pulse.
395 */
396 cmd &= ~CREG_CPU_START_POL;
397
398 cmd &= ~CREG_CPU_START_MASK;
399
400 return cmd;
401}
402
403static void smp_kick_cpu_x(u32 cpu_id)
404{
405 int cmd;
406
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300407 if (cpu_id > NR_CPUS)
408 return;
409
Eugeniy Paltsev4b4da7f2020-01-16 19:22:32 +0300410 cmd = get_masked_cpu_ctart_reg();
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300411 cmd |= (1 << cpu_id);
412 writel(cmd, (void __iomem *)CREG_CPU_START);
413}
414
415static u32 prepare_cpu_ctart_reg(void)
416{
Eugeniy Paltsev4b4da7f2020-01-16 19:22:32 +0300417 return get_masked_cpu_ctart_reg() | env_common.core_mask.val;
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300418}
419
420/* slave CPU entry for configuration */
421__attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void)
422{
423 __asm__ __volatile__(
424 "ld.di r8, [%0]\n"
425 "mov %%sp, r8\n"
426 "mov %%fp, %%sp\n"
427 : /* no output */
428 : "r" (&cross_cpu_data.stack_ptr));
429
430 invalidate_icache_all();
431
432 arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_1);
433 init_slave_cpu_func(CPU_ID_GET());
434
435 arc_write_uncached_32(&cross_cpu_data.ready_flag, SLAVE_CPU_READY);
436 arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_2);
437
438 /* Halt the processor until the master kick us again */
439 halt_this_cpu();
440
441 /*
442 * 3 NOPs after FLAG 1 instruction are no longer required for ARCv2
443 * cores but we leave them for gebug purposes.
444 */
445 __builtin_arc_nop();
446 __builtin_arc_nop();
447 __builtin_arc_nop();
448
449 arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_3);
450
451 /* get the updated entry - invalidate i$ */
452 invalidate_icache_all();
453
454 arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_4);
455
456 /* Run our program */
457 ((void (*)(void))(arc_read_uncached_32(&cross_cpu_data.entry[CPU_ID_GET()])))();
458
459 /* This bootstage is unreachable as we don't return from app we launch */
460 arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_5);
461
462 /* Something went terribly wrong */
463 while (true)
464 halt_this_cpu();
465}
466
467static void clear_cross_cpu_data(void)
468{
469 arc_write_uncached_32(&cross_cpu_data.ready_flag, 0);
470 arc_write_uncached_32(&cross_cpu_data.stack_ptr, 0);
471
472 for (u32 i = 0; i < NR_CPUS; i++)
473 arc_write_uncached_32(&cross_cpu_data.status[i], 0);
474}
475
476static noinline void do_init_slave_cpu(u32 cpu_id)
477{
478 /* attempts number for check clave CPU ready_flag */
479 u32 attempts = 100;
480 u32 stack_ptr = (u32)(slave_stack + (64 * cpu_id));
481
482 if (cpu_id >= NR_CPUS)
483 return;
484
485 arc_write_uncached_32(&cross_cpu_data.ready_flag, 0);
486
487 /* Use global unique place for each slave cpu stack */
488 arc_write_uncached_32(&cross_cpu_data.stack_ptr, stack_ptr);
489
490 debug("CPU %u: stack pool base: %p\n", cpu_id, slave_stack);
491 debug("CPU %u: current slave stack base: %x\n", cpu_id, stack_ptr);
492 slave_cpu_set_boot_addr((u32)hsdk_core_init_f);
493
494 smp_kick_cpu_x(cpu_id);
495
496 debug("CPU %u: cross-cpu flag: %x [before timeout]\n", cpu_id,
497 arc_read_uncached_32(&cross_cpu_data.ready_flag));
498
499 while (!arc_read_uncached_32(&cross_cpu_data.ready_flag) && attempts--)
500 mdelay(10);
501
502 /* Just to be sure that slave cpu is halted after it set ready_flag */
503 mdelay(20);
504
505 /*
506 * Only print error here if we reach timeout as there is no option to
507 * halt slave cpu (or check that slave cpu is halted)
508 */
509 if (!attempts)
510 pr_err("CPU %u is not responding after init!\n", cpu_id);
511
512 /* Check current stage of slave cpu */
513 if (arc_read_uncached_32(&cross_cpu_data.status[cpu_id]) != BOOTSTAGE_2)
514 pr_err("CPU %u status is unexpected: %d\n", cpu_id,
515 arc_read_uncached_32(&cross_cpu_data.status[cpu_id]));
516
517 debug("CPU %u: cross-cpu flag: %x [after timeout]\n", cpu_id,
518 arc_read_uncached_32(&cross_cpu_data.ready_flag));
519 debug("CPU %u: status: %d [after timeout]\n", cpu_id,
520 arc_read_uncached_32(&cross_cpu_data.status[cpu_id]));
521}
522
523static void do_init_slave_cpus(void)
524{
525 clear_cross_cpu_data();
526 sync_cross_cpu_data();
527
528 debug("cross_cpu_data location: %#x\n", (u32)&cross_cpu_data);
529
530 for (u32 i = MASTER_CPU_ID + 1; i < NR_CPUS; i++)
531 if (is_cpu_used(i))
532 do_init_slave_cpu(i);
533}
534
535static void do_init_master_cpu(void)
536{
537 /*
538 * Setup master caches even if master isn't used as we want to use
539 * same cache configuration on all running CPUs
540 */
541 init_master_icache();
542 init_master_dcache();
543}
544
545enum hsdk_axi_masters {
546 M_HS_CORE = 0,
547 M_HS_RTT,
548 M_AXI_TUN,
549 M_HDMI_VIDEO,
550 M_HDMI_AUDIO,
551 M_USB_HOST,
552 M_ETHERNET,
553 M_SDIO,
554 M_GPU,
555 M_DMAC_0,
556 M_DMAC_1,
557 M_DVFS
558};
559
560#define UPDATE_VAL 1
561
562/*
563 * m master AXI_M_m_SLV0 AXI_M_m_SLV1 AXI_M_m_OFFSET0 AXI_M_m_OFFSET1
564 * 0 HS (CBU) 0x11111111 0x63111111 0xFEDCBA98 0x0E543210
565 * 1 HS (RTT) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
566 * 2 AXI Tunnel 0x88888888 0x88888888 0xFEDCBA98 0x76543210
567 * 3 HDMI-VIDEO 0x77777777 0x77777777 0xFEDCBA98 0x76543210
568 * 4 HDMI-ADUIO 0x77777777 0x77777777 0xFEDCBA98 0x76543210
569 * 5 USB-HOST 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
570 * 6 ETHERNET 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
571 * 7 SDIO 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
572 * 8 GPU 0x77777777 0x77777777 0xFEDCBA98 0x76543210
573 * 9 DMAC (port #1) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
574 * 10 DMAC (port #2) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
575 * 11 DVFS 0x00000000 0x60000000 0x00000000 0x00000000
576 *
577 * Please read ARC HS Development IC Specification, section 17.2 for more
578 * information about apertures configuration.
579 * NOTE: we intentionally modify default settings in U-boot. Default settings
580 * are specified in "Table 111 CREG Address Decoder register reset values".
581 */
582
583#define CREG_AXI_M_SLV0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m)))
584#define CREG_AXI_M_SLV1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x004))
585#define CREG_AXI_M_OFT0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x008))
586#define CREG_AXI_M_OFT1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x00C))
587#define CREG_AXI_M_UPDT(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x014))
588
589#define CREG_AXI_M_HS_CORE_BOOT ((void __iomem *)(CREG_BASE + 0x010))
590
591#define CREG_PAE ((void __iomem *)(CREG_BASE + 0x180))
592#define CREG_PAE_UPDT ((void __iomem *)(CREG_BASE + 0x194))
593
594void init_memory_bridge(void)
595{
596 u32 reg;
597
598 /*
599 * M_HS_CORE has one unic register - BOOT.
600 * We need to clean boot mirror (BOOT[1:0]) bits in them.
601 */
602 reg = readl(CREG_AXI_M_HS_CORE_BOOT) & (~0x3);
603 writel(reg, CREG_AXI_M_HS_CORE_BOOT);
604 writel(0x11111111, CREG_AXI_M_SLV0(M_HS_CORE));
605 writel(0x63111111, CREG_AXI_M_SLV1(M_HS_CORE));
606 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_CORE));
607 writel(0x0E543210, CREG_AXI_M_OFT1(M_HS_CORE));
608 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_CORE));
609
610 writel(0x77777777, CREG_AXI_M_SLV0(M_HS_RTT));
611 writel(0x77777777, CREG_AXI_M_SLV1(M_HS_RTT));
612 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_RTT));
613 writel(0x76543210, CREG_AXI_M_OFT1(M_HS_RTT));
614 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_RTT));
615
616 writel(0x88888888, CREG_AXI_M_SLV0(M_AXI_TUN));
617 writel(0x88888888, CREG_AXI_M_SLV1(M_AXI_TUN));
618 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_AXI_TUN));
619 writel(0x76543210, CREG_AXI_M_OFT1(M_AXI_TUN));
620 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_AXI_TUN));
621
622 writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_VIDEO));
623 writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_VIDEO));
624 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_VIDEO));
625 writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_VIDEO));
626 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_VIDEO));
627
628 writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_AUDIO));
629 writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_AUDIO));
630 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_AUDIO));
631 writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_AUDIO));
632 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_AUDIO));
633
634 writel(0x77777777, CREG_AXI_M_SLV0(M_USB_HOST));
635 writel(0x77999999, CREG_AXI_M_SLV1(M_USB_HOST));
636 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_USB_HOST));
637 writel(0x76DCBA98, CREG_AXI_M_OFT1(M_USB_HOST));
638 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_USB_HOST));
639
640 writel(0x77777777, CREG_AXI_M_SLV0(M_ETHERNET));
641 writel(0x77999999, CREG_AXI_M_SLV1(M_ETHERNET));
642 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_ETHERNET));
643 writel(0x76DCBA98, CREG_AXI_M_OFT1(M_ETHERNET));
644 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_ETHERNET));
645
646 writel(0x77777777, CREG_AXI_M_SLV0(M_SDIO));
647 writel(0x77999999, CREG_AXI_M_SLV1(M_SDIO));
648 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_SDIO));
649 writel(0x76DCBA98, CREG_AXI_M_OFT1(M_SDIO));
650 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_SDIO));
651
652 writel(0x77777777, CREG_AXI_M_SLV0(M_GPU));
653 writel(0x77777777, CREG_AXI_M_SLV1(M_GPU));
654 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_GPU));
655 writel(0x76543210, CREG_AXI_M_OFT1(M_GPU));
656 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU));
657
658 writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0));
659 writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_0));
660 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0));
661 writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_0));
662 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0));
663
664 writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1));
665 writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_1));
666 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1));
667 writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_1));
668 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1));
669
670 writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS));
671 writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS));
672 writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS));
673 writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS));
674 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS));
675
676 writel(0x00000000, CREG_PAE);
677 writel(UPDATE_VAL, CREG_PAE_UPDT);
678}
679
Eugeniy Paltsev32ac4ee2020-03-25 12:35:49 +0300680/*
681 * For HSDK-4xD we do additional AXI bridge tweaking in hsdk_init command:
682 * - we shrink IOC region.
683 * - we configure HS CORE SLV1 aperture depending on haps_apb_location
684 * environment variable.
685 *
686 * As we've already configured AXI bridge in init_memory_bridge we don't
687 * do full configuration here but reconfigure changed part.
688 *
689 * m master AXI_M_m_SLV0 AXI_M_m_SLV1 AXI_M_m_OFFSET0 AXI_M_m_OFFSET1
690 * 0 HS (CBU) 0x11111111 0x63111111 0xFEDCBA98 0x0E543210 [haps_apb_location = 0]
691 * 0 HS (CBU) 0x11111111 0x61111111 0xFEDCBA98 0x06543210 [haps_apb_location = 1]
692 * 1 HS (RTT) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
693 * 2 AXI Tunnel 0x88888888 0x88888888 0xFEDCBA98 0x76543210
694 * 3 HDMI-VIDEO 0x77777777 0x77777777 0xFEDCBA98 0x76543210
695 * 4 HDMI-ADUIO 0x77777777 0x77777777 0xFEDCBA98 0x76543210
696 * 5 USB-HOST 0x77777777 0x77779999 0xFEDCBA98 0x7654BA98
697 * 6 ETHERNET 0x77777777 0x77779999 0xFEDCBA98 0x7654BA98
698 * 7 SDIO 0x77777777 0x77779999 0xFEDCBA98 0x7654BA98
699 * 8 GPU 0x77777777 0x77777777 0xFEDCBA98 0x76543210
700 * 9 DMAC (port #1) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
701 * 10 DMAC (port #2) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
702 * 11 DVFS 0x00000000 0x60000000 0x00000000 0x00000000
703 */
704void tweak_memory_bridge_cfg(void)
705{
706 /*
707 * Only HSDK-4xD requre additional AXI bridge tweaking depending on
708 * haps_apb_location environment variable
709 */
710 if (!is_board_match_config(T_BOARD_HSDK_4XD))
711 return;
712
713 if (env_common.haps_apb.val) {
714 writel(0x61111111, CREG_AXI_M_SLV1(M_HS_CORE));
715 writel(0x06543210, CREG_AXI_M_OFT1(M_HS_CORE));
716 } else {
717 writel(0x63111111, CREG_AXI_M_SLV1(M_HS_CORE));
718 writel(0x0E543210, CREG_AXI_M_OFT1(M_HS_CORE));
719 }
720 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_CORE));
721
722 writel(0x77779999, CREG_AXI_M_SLV1(M_USB_HOST));
723 writel(0x7654BA98, CREG_AXI_M_OFT1(M_USB_HOST));
724 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_USB_HOST));
725
726 writel(0x77779999, CREG_AXI_M_SLV1(M_ETHERNET));;
727 writel(0x7654BA98, CREG_AXI_M_OFT1(M_ETHERNET));
728 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_ETHERNET));
729
730 writel(0x77779999, CREG_AXI_M_SLV1(M_SDIO));
731 writel(0x7654BA98, CREG_AXI_M_OFT1(M_SDIO));
732 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_SDIO));
733}
734
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300735static void setup_clocks(void)
736{
737 ulong rate;
738
739 /* Setup CPU clock */
740 if (env_common.cpu_freq.set) {
741 rate = env_common.cpu_freq.val;
742 soc_clk_ctl("cpu-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ);
743 }
744
745 /* Setup TUN clock */
746 if (env_common.tun_freq.set) {
747 rate = env_common.tun_freq.val;
748 if (rate)
749 soc_clk_ctl("tun-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ);
750 else
751 soc_clk_ctl("tun-clk", NULL, CLK_OFF);
752 }
753
754 if (env_common.axi_freq.set) {
755 rate = env_common.axi_freq.val;
756 soc_clk_ctl("axi-clk", &rate, CLK_SET | CLK_ON | CLK_MHZ);
757 }
758}
759
760static void do_init_cluster(void)
761{
762 /*
763 * A multi-core ARC HS configuration always includes only one
764 * ARC_AUX_NON_VOLATILE_LIMIT register, which is shared by all the
765 * cores.
766 */
767 init_cluster_nvlim();
Eugeniy Paltsev6917a9d2020-03-23 21:50:03 +0300768 init_cluster_csm();
Eugeniy Paltsev1d897d12020-03-23 20:46:35 +0300769 init_cluster_slc();
Eugeniy Paltsev32ac4ee2020-03-25 12:35:49 +0300770 tweak_memory_bridge_cfg();
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300771}
772
773static int check_master_cpu_id(void)
774{
775 if (CPU_ID_GET() == MASTER_CPU_ID)
776 return 0;
777
778 pr_err("u-boot runs on non-master cpu with id: %lu\n", CPU_ID_GET());
779
780 return -ENOENT;
781}
782
783static noinline int prepare_cpus(void)
784{
785 int ret;
786
787 ret = check_master_cpu_id();
788 if (ret)
789 return ret;
790
791 ret = envs_process_and_validate(env_map_common, env_map_core, is_cpu_used);
792 if (ret)
793 return ret;
794
795 printf("CPU start mask is %#x\n", env_common.core_mask.val);
796
797 do_init_slave_cpus();
798 do_init_master_cpu();
799 do_init_cluster();
800
801 return 0;
802}
803
804static int hsdk_go_run(u32 cpu_start_reg)
805{
806 /* Cleanup caches, disable interrupts */
807 cleanup_before_go();
808
809 if (env_common.halt_on_boot)
810 halt_this_cpu();
811
812 /*
813 * 3 NOPs after FLAG 1 instruction are no longer required for ARCv2
814 * cores but we leave them for gebug purposes.
815 */
816 __builtin_arc_nop();
817 __builtin_arc_nop();
818 __builtin_arc_nop();
819
820 /* Kick chosen slave CPUs */
821 writel(cpu_start_reg, (void __iomem *)CREG_CPU_START);
822
823 if (is_cpu_used(MASTER_CPU_ID))
824 ((void (*)(void))(env_core.entry[MASTER_CPU_ID].val))();
825 else
826 halt_this_cpu();
827
828 pr_err("u-boot still runs on cpu [%ld]\n", CPU_ID_GET());
829
830 /*
831 * We will never return after executing our program if master cpu used
832 * otherwise halt master cpu manually.
833 */
834 while (true)
835 halt_this_cpu();
836
837 return 0;
838}
839
840int board_prep_linux(bootm_headers_t *images)
841{
842 int ret, ofst;
843 char mask[15];
844
845 ret = envs_read_validate_common(env_map_mask);
846 if (ret)
847 return ret;
848
849 /* Rollback to default values */
850 if (!env_common.core_mask.set) {
851 env_common.core_mask.val = ALL_CPU_MASK;
852 env_common.core_mask.set = true;
853 }
854
855 printf("CPU start mask is %#x\n", env_common.core_mask.val);
856
857 if (!is_cpu_used(MASTER_CPU_ID))
858 pr_err("ERR: try to launch linux with CPU[0] disabled! It doesn't work for ARC.\n");
859
860 /*
861 * If we want to launch linux on all CPUs we don't need to patch
862 * linux DTB as it is default configuration
863 */
864 if (env_common.core_mask.val == ALL_CPU_MASK)
865 return 0;
866
867 if (!IMAGE_ENABLE_OF_LIBFDT || !images->ft_len) {
868 pr_err("WARN: core_mask setup will work properly only with external DTB!\n");
869 return 0;
870 }
871
872 /* patch '/possible-cpus' property according to cpu mask */
873 ofst = fdt_path_offset(images->ft_addr, "/");
874 sprintf(mask, "%s%s%s%s",
875 is_cpu_used(0) ? "0," : "",
876 is_cpu_used(1) ? "1," : "",
877 is_cpu_used(2) ? "2," : "",
878 is_cpu_used(3) ? "3," : "");
879 ret = fdt_setprop_string(images->ft_addr, ofst, "possible-cpus", mask);
880 /*
881 * If we failed to patch '/possible-cpus' property we don't need break
882 * linux loading process: kernel will handle it but linux will print
883 * warning like "Timeout: CPU1 FAILED to comeup !!!".
884 * So warn here about error, but return 0 like no error had occurred.
885 */
886 if (ret)
887 pr_err("WARN: failed to patch '/possible-cpus' property, ret=%d\n",
888 ret);
889
890 return 0;
891}
892
893void board_jump_and_run(ulong entry, int zero, int arch, uint params)
894{
895 void (*kernel_entry)(int zero, int arch, uint params);
896 u32 cpu_start_reg;
897
898 kernel_entry = (void (*)(int, int, uint))entry;
899
900 /* Prepare CREG_CPU_START for kicking chosen CPUs */
901 cpu_start_reg = prepare_cpu_ctart_reg();
902
903 /* In case of run without hsdk_init */
904 slave_cpu_set_boot_addr(entry);
905
906 /* In case of run with hsdk_init */
907 for (u32 i = 0; i < NR_CPUS; i++) {
908 env_core.entry[i].val = entry;
909 env_core.entry[i].set = true;
910 }
911 /* sync cross_cpu struct as we updated core-entry variables */
912 sync_cross_cpu_data();
913
914 /* Kick chosen slave CPUs */
915 writel(cpu_start_reg, (void __iomem *)CREG_CPU_START);
916
917 if (is_cpu_used(0))
918 kernel_entry(zero, arch, params);
919}
920
921static int hsdk_go_prepare_and_run(void)
922{
923 /* Prepare CREG_CPU_START for kicking chosen CPUs */
924 u32 reg = prepare_cpu_ctart_reg();
925
926 if (env_common.halt_on_boot)
927 printf("CPU will halt before application start, start application with debugger.\n");
928
929 return hsdk_go_run(reg);
930}
931
932static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
933{
934 int ret;
935
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +0300936 if (board_mismatch()) {
937 printf("ERR: U-boot is not configured for this board!\n");
938 return CMD_RET_FAILURE;
939 }
940
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300941 /*
942 * Check for 'halt' parameter. 'halt' = enter halt-mode just before
943 * starting the application; can be used for debug.
944 */
945 if (argc > 1) {
946 env_common.halt_on_boot = !strcmp(argv[1], "halt");
947 if (!env_common.halt_on_boot) {
948 pr_err("Unrecognised parameter: \'%s\'\n", argv[1]);
949 return CMD_RET_FAILURE;
950 }
951 }
952
953 ret = check_master_cpu_id();
954 if (ret)
955 return ret;
956
957 ret = envs_process_and_validate(env_map_mask, env_map_go, is_cpu_used);
958 if (ret)
959 return ret;
960
961 /* sync cross_cpu struct as we updated core-entry variables */
962 sync_cross_cpu_data();
963
964 ret = hsdk_go_prepare_and_run();
965
966 return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
967}
968
969U_BOOT_CMD(
970 hsdk_go, 3, 0, do_hsdk_go,
971 "Synopsys HSDK specific command",
972 " - Boot stand-alone application on HSDK\n"
973 "hsdk_go halt - Boot stand-alone application on HSDK, halt CPU just before application run\n"
974);
975
Eugeniy Paltsev25998ae2020-04-24 23:11:10 +0300976/*
977 * We may simply use static variable here to store init status, but we also want
978 * to avoid the situation when we reload U-boot via MDB after previous
979 * init is done but HW reset (board reset) isn't done. So let's store the
980 * init status in any unused register (i.e CREG_CPU_0_ENTRY) so status will
981 * survive after U-boot is reloaded via MDB.
982 */
983#define INIT_MARKER_REGISTER ((void __iomem *)CREG_CPU_0_ENTRY)
984/* must be equal to INIT_MARKER_REGISTER reset value */
985#define INIT_MARKER_PENDING 0
986
987static bool init_marker_get(void)
988{
989 return readl(INIT_MARKER_REGISTER) != INIT_MARKER_PENDING;
990}
991
992static void init_mark_done(void)
993{
994 writel(~INIT_MARKER_PENDING, INIT_MARKER_REGISTER);
995}
996
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300997static int do_hsdk_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
998{
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300999 int ret;
1000
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +03001001 if (board_mismatch()) {
1002 printf("ERR: U-boot is not configured for this board!\n");
1003 return CMD_RET_FAILURE;
1004 }
1005
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03001006 /* hsdk_init can be run only once */
Eugeniy Paltsev25998ae2020-04-24 23:11:10 +03001007 if (init_marker_get()) {
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03001008 printf("HSDK HW is already initialized! Please reset the board if you want to change the configuration.\n");
1009 return CMD_RET_FAILURE;
1010 }
1011
1012 ret = prepare_cpus();
1013 if (!ret)
Eugeniy Paltsev25998ae2020-04-24 23:11:10 +03001014 init_mark_done();
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03001015
1016 return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
1017}
1018
1019U_BOOT_CMD(
1020 hsdk_init, 1, 0, do_hsdk_init,
1021 "Synopsys HSDK specific command",
1022 "- Init HSDK HW\n"
1023);
1024
1025static int do_hsdk_clock_set(cmd_tbl_t *cmdtp, int flag, int argc,
1026 char *const argv[])
1027{
1028 int ret = 0;
1029
1030 /* Strip off leading subcommand argument */
1031 argc--;
1032 argv++;
1033
1034 envs_cleanup_common(env_map_clock);
1035
1036 if (!argc) {
1037 printf("Set clocks to values specified in environment\n");
1038 ret = envs_read_common(env_map_clock);
1039 } else {
1040 printf("Set clocks to values specified in args\n");
1041 ret = args_envs_enumerate(env_map_clock, 2, argc, argv);
1042 }
1043
1044 if (ret)
1045 return CMD_RET_FAILURE;
1046
1047 ret = envs_validate_common(env_map_clock);
1048 if (ret)
1049 return CMD_RET_FAILURE;
1050
1051 /* Setup clock tree HW */
1052 setup_clocks();
1053
1054 return CMD_RET_SUCCESS;
1055}
1056
1057static int do_hsdk_clock_get(cmd_tbl_t *cmdtp, int flag, int argc,
1058 char *const argv[])
1059{
1060 ulong rate;
1061
1062 if (soc_clk_ctl("cpu-clk", &rate, CLK_GET | CLK_MHZ))
1063 return CMD_RET_FAILURE;
1064
1065 if (env_set_ulong("cpu_freq", rate))
1066 return CMD_RET_FAILURE;
1067
1068 if (soc_clk_ctl("tun-clk", &rate, CLK_GET | CLK_MHZ))
1069 return CMD_RET_FAILURE;
1070
1071 if (env_set_ulong("tun_freq", rate))
1072 return CMD_RET_FAILURE;
1073
1074 if (soc_clk_ctl("axi-clk", &rate, CLK_GET | CLK_MHZ))
1075 return CMD_RET_FAILURE;
1076
1077 if (env_set_ulong("axi_freq", rate))
1078 return CMD_RET_FAILURE;
1079
1080 printf("Clock values are saved to environment\n");
1081
1082 return CMD_RET_SUCCESS;
1083}
1084
1085static int do_hsdk_clock_print(cmd_tbl_t *cmdtp, int flag, int argc,
1086 char *const argv[])
1087{
1088 /* Main clocks */
1089 soc_clk_ctl("cpu-clk", NULL, CLK_PRINT | CLK_MHZ);
1090 soc_clk_ctl("tun-clk", NULL, CLK_PRINT | CLK_MHZ);
1091 soc_clk_ctl("axi-clk", NULL, CLK_PRINT | CLK_MHZ);
1092 soc_clk_ctl("ddr-clk", NULL, CLK_PRINT | CLK_MHZ);
1093
1094 return CMD_RET_SUCCESS;
1095}
1096
1097static int do_hsdk_clock_print_all(cmd_tbl_t *cmdtp, int flag, int argc,
1098 char *const argv[])
1099{
1100 /*
1101 * NOTE: as of today we don't use some peripherals like HDMI / EBI
1102 * so we don't want to print their clocks ("hdmi-sys-clk", "hdmi-pll",
1103 * "hdmi-clk", "ebi-clk"). Nevertheless their clock subsystems is fully
1104 * functional and we can print their clocks if it is required
1105 */
1106
1107 /* CPU clock domain */
1108 soc_clk_ctl("cpu-pll", NULL, CLK_PRINT | CLK_MHZ);
1109 soc_clk_ctl("cpu-clk", NULL, CLK_PRINT | CLK_MHZ);
1110 printf("\n");
1111
1112 /* SYS clock domain */
1113 soc_clk_ctl("sys-pll", NULL, CLK_PRINT | CLK_MHZ);
1114 soc_clk_ctl("apb-clk", NULL, CLK_PRINT | CLK_MHZ);
1115 soc_clk_ctl("axi-clk", NULL, CLK_PRINT | CLK_MHZ);
1116 soc_clk_ctl("eth-clk", NULL, CLK_PRINT | CLK_MHZ);
1117 soc_clk_ctl("usb-clk", NULL, CLK_PRINT | CLK_MHZ);
1118 soc_clk_ctl("sdio-clk", NULL, CLK_PRINT | CLK_MHZ);
Eugeniy Paltsevb84aa4c2020-04-22 02:08:06 +03001119 if (is_board_match_runtime(T_BOARD_HSDK_4XD))
1120 soc_clk_ctl("hdmi-sys-clk", NULL, CLK_PRINT | CLK_MHZ);
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03001121 soc_clk_ctl("gfx-core-clk", NULL, CLK_PRINT | CLK_MHZ);
Eugeniy Paltsevda34c6b2020-04-22 22:44:24 +03001122 if (is_board_match_runtime(T_BOARD_HSDK)) {
1123 soc_clk_ctl("gfx-dma-clk", NULL, CLK_PRINT | CLK_MHZ);
1124 soc_clk_ctl("gfx-cfg-clk", NULL, CLK_PRINT | CLK_MHZ);
1125 }
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03001126 soc_clk_ctl("dmac-core-clk", NULL, CLK_PRINT | CLK_MHZ);
1127 soc_clk_ctl("dmac-cfg-clk", NULL, CLK_PRINT | CLK_MHZ);
1128 soc_clk_ctl("sdio-ref-clk", NULL, CLK_PRINT | CLK_MHZ);
1129 soc_clk_ctl("spi-clk", NULL, CLK_PRINT | CLK_MHZ);
1130 soc_clk_ctl("i2c-clk", NULL, CLK_PRINT | CLK_MHZ);
1131/* soc_clk_ctl("ebi-clk", NULL, CLK_PRINT | CLK_MHZ); */
1132 soc_clk_ctl("uart-clk", NULL, CLK_PRINT | CLK_MHZ);
1133 printf("\n");
1134
1135 /* DDR clock domain */
1136 soc_clk_ctl("ddr-clk", NULL, CLK_PRINT | CLK_MHZ);
1137 printf("\n");
1138
1139 /* HDMI clock domain */
Eugeniy Paltsevb84aa4c2020-04-22 02:08:06 +03001140 if (is_board_match_runtime(T_BOARD_HSDK_4XD)) {
1141 soc_clk_ctl("hdmi-pll", NULL, CLK_PRINT | CLK_MHZ);
1142 soc_clk_ctl("hdmi-clk", NULL, CLK_PRINT | CLK_MHZ);
1143 printf("\n");
1144 }
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03001145
1146 /* TUN clock domain */
1147 soc_clk_ctl("tun-pll", NULL, CLK_PRINT | CLK_MHZ);
1148 soc_clk_ctl("tun-clk", NULL, CLK_PRINT | CLK_MHZ);
1149 soc_clk_ctl("rom-clk", NULL, CLK_PRINT | CLK_MHZ);
1150 soc_clk_ctl("pwm-clk", NULL, CLK_PRINT | CLK_MHZ);
Eugeniy Paltsevd4ee5c32020-04-23 14:52:43 +03001151 if (is_board_match_runtime(T_BOARD_HSDK_4XD))
1152 soc_clk_ctl("timer-clk", NULL, CLK_PRINT | CLK_MHZ);
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03001153 printf("\n");
1154
1155 return CMD_RET_SUCCESS;
1156}
1157
1158cmd_tbl_t cmd_hsdk_clock[] = {
1159 U_BOOT_CMD_MKENT(set, 3, 0, do_hsdk_clock_set, "", ""),
1160 U_BOOT_CMD_MKENT(get, 3, 0, do_hsdk_clock_get, "", ""),
1161 U_BOOT_CMD_MKENT(print, 4, 0, do_hsdk_clock_print, "", ""),
1162 U_BOOT_CMD_MKENT(print_all, 4, 0, do_hsdk_clock_print_all, "", ""),
1163};
1164
1165static int do_hsdk_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
1166{
1167 cmd_tbl_t *c;
1168
1169 if (argc < 2)
1170 return CMD_RET_USAGE;
1171
1172 /* Strip off leading 'hsdk_clock' command argument */
1173 argc--;
1174 argv++;
1175
1176 c = find_cmd_tbl(argv[0], cmd_hsdk_clock, ARRAY_SIZE(cmd_hsdk_clock));
1177 if (!c)
1178 return CMD_RET_USAGE;
1179
1180 return c->cmd(cmdtp, flag, argc, argv);
1181}
1182
1183U_BOOT_CMD(
1184 hsdk_clock, CONFIG_SYS_MAXARGS, 0, do_hsdk_clock,
1185 "Synopsys HSDK specific clock command",
1186 "set - Set clock to values specified in environment / command line arguments\n"
1187 "hsdk_clock get - Save clock values to environment\n"
1188 "hsdk_clock print - Print main clock values to console\n"
1189 "hsdk_clock print_all - Print all clock values to console\n"
1190);
1191
1192/* init calls */
1193int board_early_init_f(void)
1194{
1195 /*
1196 * Setup AXI apertures unconditionally as we want to have DDR
1197 * in 0x00000000 region when we are kicking slave cpus.
1198 */
1199 init_memory_bridge();
1200
Eugeniy Paltsev54858312019-02-25 18:35:29 +03001201 /*
1202 * Switch SDIO external ciu clock divider from default div-by-8 to
1203 * minimum possible div-by-2.
1204 */
1205 writel(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *)SDIO_UHS_REG_EXT);
1206
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03001207 return 0;
1208}
1209
1210int board_early_init_r(void)
1211{
1212 /*
1213 * TODO: Init USB here to be able read environment from USB MSD.
1214 * It can be done with usb_init() call. We can't do it right now
1215 * due to brocken USB IP SW reset and lack of USB IP HW reset in
1216 * linux kernel (if we init USB here we will break USB in linux)
1217 */
1218
1219 /*
1220 * Flush all d$ as we want to use uncached area with st.di / ld.di
1221 * instructions and we don't want to have any dirty line in L1d$ or SL$
1222 * in this area. It is enough to flush all d$ once here as we access to
1223 * uncached area with regular st (non .di) instruction only when we copy
1224 * data during u-boot relocation.
1225 */
1226 flush_dcache_all();
1227
1228 printf("Relocation Offset is: %08lx\n", gd->reloc_off);
1229
1230 return 0;
1231}
1232
1233int board_late_init(void)
1234{
1235 /*
1236 * Populate environment with clock frequency values -
1237 * run hsdk_clock get callback without uboot command run.
1238 */
1239 do_hsdk_clock_get(NULL, 0, 0, NULL);
1240
1241 return 0;
1242}
Eugeniy Paltsev4e782b52017-10-21 15:35:12 +03001243
Alexey Brodkin6ef705b2018-11-27 09:47:01 +03001244int checkboard(void)
1245{
Eugeniy Paltseva8eb9b22020-04-29 21:36:44 +03001246 u32 reg;
1247
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +03001248 printf("Board: Synopsys %s\n", board_name(get_board_type_runtime()));
1249
1250 if (board_mismatch())
1251 printf("WARN: U-boot is configured NOT for this board but for %s!\n",
1252 board_name(get_board_type_config()));
1253
Eugeniy Paltseva8eb9b22020-04-29 21:36:44 +03001254 reg = readl(CREG_AXI_M_HS_CORE_BOOT) & CREG_CORE_BOOT_IMAGE;
1255 printf("U-boot autostart: %s\n", reg ? "enabled" : "disabled");
1256
Alexey Brodkin6ef705b2018-11-27 09:47:01 +03001257 return 0;
1258};