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