blob: 577893de2a1fdd172e10beef35a490593eb16fba [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
45#define SDIO_BASE (ARC_PERIPHERAL_BASE + 0xA000)
46#define SDIO_UHS_REG_EXT (SDIO_BASE + 0x108)
47#define SDIO_UHS_REG_EXT_DIV_2 (2 << 30)
48
49/* Uncached access macros */
50#define arc_read_uncached_32(ptr) \
51({ \
52 unsigned int __ret; \
53 __asm__ __volatile__( \
54 " ld.di %0, [%1] \n" \
55 : "=r"(__ret) \
56 : "r"(ptr)); \
57 __ret; \
58})
59
60#define arc_write_uncached_32(ptr, data)\
61({ \
62 __asm__ __volatile__( \
63 " st.di %0, [%1] \n" \
64 : \
65 : "r"(data), "r"(ptr)); \
66})
67
68struct hsdk_env_core_ctl {
69 u32_env entry[NR_CPUS];
70 u32_env iccm[NR_CPUS];
71 u32_env dccm[NR_CPUS];
72};
73
74struct hsdk_env_common_ctl {
75 bool halt_on_boot;
76 u32_env core_mask;
77 u32_env cpu_freq;
78 u32_env axi_freq;
79 u32_env tun_freq;
80 u32_env nvlim;
81 u32_env icache;
82 u32_env dcache;
83};
84
85/*
86 * Uncached cross-cpu structure. All CPUs must access to this structure fields
87 * only with arc_read_uncached_32() / arc_write_uncached_32() accessors (which
88 * implement ld.di / st.di instructions). Simultaneous cached and uncached
89 * access to this area will lead to data loss.
90 * We flush all data caches in board_early_init_r() as we don't want to have
91 * any dirty line in L1d$ or SL$ in this area.
92 */
93struct hsdk_cross_cpu {
94 /* slave CPU ready flag */
95 u32 ready_flag;
96 /* address of the area, which can be used for stack by slave CPU */
97 u32 stack_ptr;
98 /* slave CPU status - bootstage number */
99 s32 status[NR_CPUS];
100
101 /*
102 * Slave CPU data - it is copy of corresponding fields in
103 * hsdk_env_core_ctl and hsdk_env_common_ctl structures which are
104 * required for slave CPUs initialization.
105 * This fields can be populated by copying from hsdk_env_core_ctl
106 * and hsdk_env_common_ctl structures with sync_cross_cpu_data()
107 * function.
108 */
109 u32 entry[NR_CPUS];
110 u32 iccm[NR_CPUS];
111 u32 dccm[NR_CPUS];
112
113 u32 core_mask;
114 u32 icache;
115 u32 dcache;
116
117 u8 cache_padding[ARCH_DMA_MINALIGN];
118} __aligned(ARCH_DMA_MINALIGN);
119
120/* Place for slave CPUs temporary stack */
121static u32 slave_stack[256 * NR_CPUS] __aligned(ARCH_DMA_MINALIGN);
122
123static struct hsdk_env_common_ctl env_common = {};
124static struct hsdk_env_core_ctl env_core = {};
125static struct hsdk_cross_cpu cross_cpu_data;
126
127static const struct env_map_common env_map_common[] = {
128 { "core_mask", ENV_HEX, true, 0x1, 0xF, &env_common.core_mask },
129 { "non_volatile_limit", ENV_HEX, true, 0, 0xF, &env_common.nvlim },
130 { "icache_ena", ENV_HEX, true, 0, 1, &env_common.icache },
131 { "dcache_ena", ENV_HEX, true, 0, 1, &env_common.dcache },
132 {}
133};
134
135static const struct env_map_common env_map_clock[] = {
136 { "cpu_freq", ENV_DEC, false, 100, 1000, &env_common.cpu_freq },
137 { "axi_freq", ENV_DEC, false, 200, 800, &env_common.axi_freq },
138 { "tun_freq", ENV_DEC, false, 0, 150, &env_common.tun_freq },
139 {}
140};
141
142static const struct env_map_percpu env_map_core[] = {
143 { "core_iccm", ENV_HEX, true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.iccm },
144 { "core_dccm", ENV_HEX, true, {NO_CCM, 0, NO_CCM, 0}, {NO_CCM, 0xF, NO_CCM, 0xF}, &env_core.dccm },
145 {}
146};
147
148static const struct env_map_common env_map_mask[] = {
149 { "core_mask", ENV_HEX, false, 0x1, 0xF, &env_common.core_mask },
150 {}
151};
152
153static const struct env_map_percpu env_map_go[] = {
154 { "core_entry", ENV_HEX, true, {0, 0, 0, 0}, {U32_MAX, U32_MAX, U32_MAX, U32_MAX}, &env_core.entry },
155 {}
156};
157
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +0300158enum board_type {
159 T_BOARD_NONE,
160 T_BOARD_HSDK,
161 T_BOARD_HSDK_4XD
162};
163
164static inline enum board_type get_board_type_runtime(void)
165{
166 u32 arc_id = read_aux_reg(ARC_AUX_IDENTITY) & 0xFF;
167
168 if (arc_id == 0x52)
169 return T_BOARD_HSDK;
170 else if (arc_id == 0x54)
171 return T_BOARD_HSDK_4XD;
172 else
173 return T_BOARD_NONE;
174}
175
176static inline enum board_type get_board_type_config(void)
177{
178 if (IS_ENABLED(CONFIG_BOARD_HSDK))
179 return T_BOARD_HSDK;
180 else if (IS_ENABLED(CONFIG_BOARD_HSDK_4XD))
181 return T_BOARD_HSDK_4XD;
182 else
183 return T_BOARD_NONE;
184}
185
186static bool is_board_match_runtime(enum board_type type_req)
187{
188 return get_board_type_runtime() == type_req;
189}
190
191static const char * board_name(enum board_type type)
192{
193 switch (type) {
194 case T_BOARD_HSDK:
195 return "ARC HS Development Kit";
196 case T_BOARD_HSDK_4XD:
197 return "ARC HS4x/HS4xD Development Kit";
198 default:
199 return "?";
200 }
201}
202
203static bool board_mismatch(void)
204{
205 return get_board_type_config() != get_board_type_runtime();
206}
207
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300208static void sync_cross_cpu_data(void)
Alexey Brodkin67482f52016-11-25 16:23:43 +0300209{
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300210 u32 value;
Alexey Brodkin67482f52016-11-25 16:23:43 +0300211
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300212 for (u32 i = 0; i < NR_CPUS; i++) {
213 value = env_core.entry[i].val;
214 arc_write_uncached_32(&cross_cpu_data.entry[i], value);
215 }
216
217 for (u32 i = 0; i < NR_CPUS; i++) {
218 value = env_core.iccm[i].val;
219 arc_write_uncached_32(&cross_cpu_data.iccm[i], value);
220 }
221
222 for (u32 i = 0; i < NR_CPUS; i++) {
223 value = env_core.dccm[i].val;
224 arc_write_uncached_32(&cross_cpu_data.dccm[i], value);
225 }
226
227 value = env_common.core_mask.val;
228 arc_write_uncached_32(&cross_cpu_data.core_mask, value);
229
230 value = env_common.icache.val;
231 arc_write_uncached_32(&cross_cpu_data.icache, value);
232
233 value = env_common.dcache.val;
234 arc_write_uncached_32(&cross_cpu_data.dcache, value);
235}
236
237/* Can be used only on master CPU */
238static bool is_cpu_used(u32 cpu_id)
239{
240 return !!(env_common.core_mask.val & BIT(cpu_id));
241}
242
243/* TODO: add ICCM BCR and DCCM BCR runtime check */
244static void init_slave_cpu_func(u32 core)
245{
246 u32 val;
247
248 /* Remap ICCM to another memory region if it exists */
249 val = arc_read_uncached_32(&cross_cpu_data.iccm[core]);
250 if (val != NO_CCM)
251 write_aux_reg(ARC_AUX_ICCM_BASE, val << APERTURE_SHIFT);
252
253 /* Remap DCCM to another memory region if it exists */
254 val = arc_read_uncached_32(&cross_cpu_data.dccm[core]);
255 if (val != NO_CCM)
256 write_aux_reg(ARC_AUX_DCCM_BASE, val << APERTURE_SHIFT);
257
258 if (arc_read_uncached_32(&cross_cpu_data.icache))
259 icache_enable();
260 else
261 icache_disable();
262
263 if (arc_read_uncached_32(&cross_cpu_data.dcache))
264 dcache_enable();
265 else
266 dcache_disable();
267}
268
269static void init_cluster_nvlim(void)
270{
271 u32 val = env_common.nvlim.val << APERTURE_SHIFT;
272
273 flush_dcache_all();
274 write_aux_reg(ARC_AUX_NON_VOLATILE_LIMIT, val);
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +0300275 /* AUX_AUX_CACHE_LIMIT reg is missing starting from HS48 */
276 if (is_board_match_runtime(T_BOARD_HSDK))
277 write_aux_reg(AUX_AUX_CACHE_LIMIT, val);
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300278 flush_n_invalidate_dcache_all();
279}
280
281static void init_master_icache(void)
282{
283 if (icache_status()) {
284 /* I$ is enabled - we need to disable it */
285 if (!env_common.icache.val)
286 icache_disable();
287 } else {
288 /* I$ is disabled - we need to enable it */
289 if (env_common.icache.val) {
290 icache_enable();
291
292 /* invalidate I$ right after enable */
293 invalidate_icache_all();
294 }
295 }
296}
297
298static void init_master_dcache(void)
299{
300 if (dcache_status()) {
301 /* D$ is enabled - we need to disable it */
302 if (!env_common.dcache.val)
303 dcache_disable();
304 } else {
305 /* D$ is disabled - we need to enable it */
306 if (env_common.dcache.val)
307 dcache_enable();
308
309 /* TODO: probably we need ti invalidate D$ right after enable */
310 }
311}
312
313static int cleanup_before_go(void)
314{
315 disable_interrupts();
316 sync_n_cleanup_cache_all();
Alexey Brodkin67482f52016-11-25 16:23:43 +0300317
318 return 0;
319}
320
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300321void slave_cpu_set_boot_addr(u32 addr)
322{
323 /* All cores have reset vector pointing to 0 */
324 writel(addr, (void __iomem *)RESET_VECTOR_ADDR);
325
326 /* Make sure other cores see written value in memory */
327 sync_n_cleanup_cache_all();
328}
329
330static inline void halt_this_cpu(void)
331{
332 __builtin_arc_flag(1);
333}
334
Eugeniy Paltsev4b4da7f2020-01-16 19:22:32 +0300335static u32 get_masked_cpu_ctart_reg(void)
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300336{
337 int cmd = readl((void __iomem *)CREG_CPU_START);
338
Eugeniy Paltsev4b4da7f2020-01-16 19:22:32 +0300339 /*
340 * Quirk for HSDK-4xD - due to HW issues HSDK can use any pulse polarity
341 * and HSDK-4xD require active low polarity of cpu_start pulse.
342 */
343 cmd &= ~CREG_CPU_START_POL;
344
345 cmd &= ~CREG_CPU_START_MASK;
346
347 return cmd;
348}
349
350static void smp_kick_cpu_x(u32 cpu_id)
351{
352 int cmd;
353
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300354 if (cpu_id > NR_CPUS)
355 return;
356
Eugeniy Paltsev4b4da7f2020-01-16 19:22:32 +0300357 cmd = get_masked_cpu_ctart_reg();
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300358 cmd |= (1 << cpu_id);
359 writel(cmd, (void __iomem *)CREG_CPU_START);
360}
361
362static u32 prepare_cpu_ctart_reg(void)
363{
Eugeniy Paltsev4b4da7f2020-01-16 19:22:32 +0300364 return get_masked_cpu_ctart_reg() | env_common.core_mask.val;
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300365}
366
367/* slave CPU entry for configuration */
368__attribute__((naked, noreturn, flatten)) noinline void hsdk_core_init_f(void)
369{
370 __asm__ __volatile__(
371 "ld.di r8, [%0]\n"
372 "mov %%sp, r8\n"
373 "mov %%fp, %%sp\n"
374 : /* no output */
375 : "r" (&cross_cpu_data.stack_ptr));
376
377 invalidate_icache_all();
378
379 arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_1);
380 init_slave_cpu_func(CPU_ID_GET());
381
382 arc_write_uncached_32(&cross_cpu_data.ready_flag, SLAVE_CPU_READY);
383 arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_2);
384
385 /* Halt the processor until the master kick us again */
386 halt_this_cpu();
387
388 /*
389 * 3 NOPs after FLAG 1 instruction are no longer required for ARCv2
390 * cores but we leave them for gebug purposes.
391 */
392 __builtin_arc_nop();
393 __builtin_arc_nop();
394 __builtin_arc_nop();
395
396 arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_3);
397
398 /* get the updated entry - invalidate i$ */
399 invalidate_icache_all();
400
401 arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_4);
402
403 /* Run our program */
404 ((void (*)(void))(arc_read_uncached_32(&cross_cpu_data.entry[CPU_ID_GET()])))();
405
406 /* This bootstage is unreachable as we don't return from app we launch */
407 arc_write_uncached_32(&cross_cpu_data.status[CPU_ID_GET()], BOOTSTAGE_5);
408
409 /* Something went terribly wrong */
410 while (true)
411 halt_this_cpu();
412}
413
414static void clear_cross_cpu_data(void)
415{
416 arc_write_uncached_32(&cross_cpu_data.ready_flag, 0);
417 arc_write_uncached_32(&cross_cpu_data.stack_ptr, 0);
418
419 for (u32 i = 0; i < NR_CPUS; i++)
420 arc_write_uncached_32(&cross_cpu_data.status[i], 0);
421}
422
423static noinline void do_init_slave_cpu(u32 cpu_id)
424{
425 /* attempts number for check clave CPU ready_flag */
426 u32 attempts = 100;
427 u32 stack_ptr = (u32)(slave_stack + (64 * cpu_id));
428
429 if (cpu_id >= NR_CPUS)
430 return;
431
432 arc_write_uncached_32(&cross_cpu_data.ready_flag, 0);
433
434 /* Use global unique place for each slave cpu stack */
435 arc_write_uncached_32(&cross_cpu_data.stack_ptr, stack_ptr);
436
437 debug("CPU %u: stack pool base: %p\n", cpu_id, slave_stack);
438 debug("CPU %u: current slave stack base: %x\n", cpu_id, stack_ptr);
439 slave_cpu_set_boot_addr((u32)hsdk_core_init_f);
440
441 smp_kick_cpu_x(cpu_id);
442
443 debug("CPU %u: cross-cpu flag: %x [before timeout]\n", cpu_id,
444 arc_read_uncached_32(&cross_cpu_data.ready_flag));
445
446 while (!arc_read_uncached_32(&cross_cpu_data.ready_flag) && attempts--)
447 mdelay(10);
448
449 /* Just to be sure that slave cpu is halted after it set ready_flag */
450 mdelay(20);
451
452 /*
453 * Only print error here if we reach timeout as there is no option to
454 * halt slave cpu (or check that slave cpu is halted)
455 */
456 if (!attempts)
457 pr_err("CPU %u is not responding after init!\n", cpu_id);
458
459 /* Check current stage of slave cpu */
460 if (arc_read_uncached_32(&cross_cpu_data.status[cpu_id]) != BOOTSTAGE_2)
461 pr_err("CPU %u status is unexpected: %d\n", cpu_id,
462 arc_read_uncached_32(&cross_cpu_data.status[cpu_id]));
463
464 debug("CPU %u: cross-cpu flag: %x [after timeout]\n", cpu_id,
465 arc_read_uncached_32(&cross_cpu_data.ready_flag));
466 debug("CPU %u: status: %d [after timeout]\n", cpu_id,
467 arc_read_uncached_32(&cross_cpu_data.status[cpu_id]));
468}
469
470static void do_init_slave_cpus(void)
471{
472 clear_cross_cpu_data();
473 sync_cross_cpu_data();
474
475 debug("cross_cpu_data location: %#x\n", (u32)&cross_cpu_data);
476
477 for (u32 i = MASTER_CPU_ID + 1; i < NR_CPUS; i++)
478 if (is_cpu_used(i))
479 do_init_slave_cpu(i);
480}
481
482static void do_init_master_cpu(void)
483{
484 /*
485 * Setup master caches even if master isn't used as we want to use
486 * same cache configuration on all running CPUs
487 */
488 init_master_icache();
489 init_master_dcache();
490}
491
492enum hsdk_axi_masters {
493 M_HS_CORE = 0,
494 M_HS_RTT,
495 M_AXI_TUN,
496 M_HDMI_VIDEO,
497 M_HDMI_AUDIO,
498 M_USB_HOST,
499 M_ETHERNET,
500 M_SDIO,
501 M_GPU,
502 M_DMAC_0,
503 M_DMAC_1,
504 M_DVFS
505};
506
507#define UPDATE_VAL 1
508
509/*
510 * m master AXI_M_m_SLV0 AXI_M_m_SLV1 AXI_M_m_OFFSET0 AXI_M_m_OFFSET1
511 * 0 HS (CBU) 0x11111111 0x63111111 0xFEDCBA98 0x0E543210
512 * 1 HS (RTT) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
513 * 2 AXI Tunnel 0x88888888 0x88888888 0xFEDCBA98 0x76543210
514 * 3 HDMI-VIDEO 0x77777777 0x77777777 0xFEDCBA98 0x76543210
515 * 4 HDMI-ADUIO 0x77777777 0x77777777 0xFEDCBA98 0x76543210
516 * 5 USB-HOST 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
517 * 6 ETHERNET 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
518 * 7 SDIO 0x77777777 0x77999999 0xFEDCBA98 0x76DCBA98
519 * 8 GPU 0x77777777 0x77777777 0xFEDCBA98 0x76543210
520 * 9 DMAC (port #1) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
521 * 10 DMAC (port #2) 0x77777777 0x77777777 0xFEDCBA98 0x76543210
522 * 11 DVFS 0x00000000 0x60000000 0x00000000 0x00000000
523 *
524 * Please read ARC HS Development IC Specification, section 17.2 for more
525 * information about apertures configuration.
526 * NOTE: we intentionally modify default settings in U-boot. Default settings
527 * are specified in "Table 111 CREG Address Decoder register reset values".
528 */
529
530#define CREG_AXI_M_SLV0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m)))
531#define CREG_AXI_M_SLV1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x004))
532#define CREG_AXI_M_OFT0(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x008))
533#define CREG_AXI_M_OFT1(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x00C))
534#define CREG_AXI_M_UPDT(m) ((void __iomem *)(CREG_BASE + 0x020 * (m) + 0x014))
535
536#define CREG_AXI_M_HS_CORE_BOOT ((void __iomem *)(CREG_BASE + 0x010))
537
538#define CREG_PAE ((void __iomem *)(CREG_BASE + 0x180))
539#define CREG_PAE_UPDT ((void __iomem *)(CREG_BASE + 0x194))
540
541void init_memory_bridge(void)
542{
543 u32 reg;
544
545 /*
546 * M_HS_CORE has one unic register - BOOT.
547 * We need to clean boot mirror (BOOT[1:0]) bits in them.
548 */
549 reg = readl(CREG_AXI_M_HS_CORE_BOOT) & (~0x3);
550 writel(reg, CREG_AXI_M_HS_CORE_BOOT);
551 writel(0x11111111, CREG_AXI_M_SLV0(M_HS_CORE));
552 writel(0x63111111, CREG_AXI_M_SLV1(M_HS_CORE));
553 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_CORE));
554 writel(0x0E543210, CREG_AXI_M_OFT1(M_HS_CORE));
555 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_CORE));
556
557 writel(0x77777777, CREG_AXI_M_SLV0(M_HS_RTT));
558 writel(0x77777777, CREG_AXI_M_SLV1(M_HS_RTT));
559 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HS_RTT));
560 writel(0x76543210, CREG_AXI_M_OFT1(M_HS_RTT));
561 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HS_RTT));
562
563 writel(0x88888888, CREG_AXI_M_SLV0(M_AXI_TUN));
564 writel(0x88888888, CREG_AXI_M_SLV1(M_AXI_TUN));
565 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_AXI_TUN));
566 writel(0x76543210, CREG_AXI_M_OFT1(M_AXI_TUN));
567 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_AXI_TUN));
568
569 writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_VIDEO));
570 writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_VIDEO));
571 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_VIDEO));
572 writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_VIDEO));
573 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_VIDEO));
574
575 writel(0x77777777, CREG_AXI_M_SLV0(M_HDMI_AUDIO));
576 writel(0x77777777, CREG_AXI_M_SLV1(M_HDMI_AUDIO));
577 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_HDMI_AUDIO));
578 writel(0x76543210, CREG_AXI_M_OFT1(M_HDMI_AUDIO));
579 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_HDMI_AUDIO));
580
581 writel(0x77777777, CREG_AXI_M_SLV0(M_USB_HOST));
582 writel(0x77999999, CREG_AXI_M_SLV1(M_USB_HOST));
583 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_USB_HOST));
584 writel(0x76DCBA98, CREG_AXI_M_OFT1(M_USB_HOST));
585 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_USB_HOST));
586
587 writel(0x77777777, CREG_AXI_M_SLV0(M_ETHERNET));
588 writel(0x77999999, CREG_AXI_M_SLV1(M_ETHERNET));
589 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_ETHERNET));
590 writel(0x76DCBA98, CREG_AXI_M_OFT1(M_ETHERNET));
591 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_ETHERNET));
592
593 writel(0x77777777, CREG_AXI_M_SLV0(M_SDIO));
594 writel(0x77999999, CREG_AXI_M_SLV1(M_SDIO));
595 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_SDIO));
596 writel(0x76DCBA98, CREG_AXI_M_OFT1(M_SDIO));
597 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_SDIO));
598
599 writel(0x77777777, CREG_AXI_M_SLV0(M_GPU));
600 writel(0x77777777, CREG_AXI_M_SLV1(M_GPU));
601 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_GPU));
602 writel(0x76543210, CREG_AXI_M_OFT1(M_GPU));
603 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_GPU));
604
605 writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_0));
606 writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_0));
607 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_0));
608 writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_0));
609 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_0));
610
611 writel(0x77777777, CREG_AXI_M_SLV0(M_DMAC_1));
612 writel(0x77777777, CREG_AXI_M_SLV1(M_DMAC_1));
613 writel(0xFEDCBA98, CREG_AXI_M_OFT0(M_DMAC_1));
614 writel(0x76543210, CREG_AXI_M_OFT1(M_DMAC_1));
615 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DMAC_1));
616
617 writel(0x00000000, CREG_AXI_M_SLV0(M_DVFS));
618 writel(0x60000000, CREG_AXI_M_SLV1(M_DVFS));
619 writel(0x00000000, CREG_AXI_M_OFT0(M_DVFS));
620 writel(0x00000000, CREG_AXI_M_OFT1(M_DVFS));
621 writel(UPDATE_VAL, CREG_AXI_M_UPDT(M_DVFS));
622
623 writel(0x00000000, CREG_PAE);
624 writel(UPDATE_VAL, CREG_PAE_UPDT);
625}
626
627static void setup_clocks(void)
628{
629 ulong rate;
630
631 /* Setup CPU clock */
632 if (env_common.cpu_freq.set) {
633 rate = env_common.cpu_freq.val;
634 soc_clk_ctl("cpu-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ);
635 }
636
637 /* Setup TUN clock */
638 if (env_common.tun_freq.set) {
639 rate = env_common.tun_freq.val;
640 if (rate)
641 soc_clk_ctl("tun-clk", &rate, CLK_ON | CLK_SET | CLK_MHZ);
642 else
643 soc_clk_ctl("tun-clk", NULL, CLK_OFF);
644 }
645
646 if (env_common.axi_freq.set) {
647 rate = env_common.axi_freq.val;
648 soc_clk_ctl("axi-clk", &rate, CLK_SET | CLK_ON | CLK_MHZ);
649 }
650}
651
652static void do_init_cluster(void)
653{
654 /*
655 * A multi-core ARC HS configuration always includes only one
656 * ARC_AUX_NON_VOLATILE_LIMIT register, which is shared by all the
657 * cores.
658 */
659 init_cluster_nvlim();
660}
661
662static int check_master_cpu_id(void)
663{
664 if (CPU_ID_GET() == MASTER_CPU_ID)
665 return 0;
666
667 pr_err("u-boot runs on non-master cpu with id: %lu\n", CPU_ID_GET());
668
669 return -ENOENT;
670}
671
672static noinline int prepare_cpus(void)
673{
674 int ret;
675
676 ret = check_master_cpu_id();
677 if (ret)
678 return ret;
679
680 ret = envs_process_and_validate(env_map_common, env_map_core, is_cpu_used);
681 if (ret)
682 return ret;
683
684 printf("CPU start mask is %#x\n", env_common.core_mask.val);
685
686 do_init_slave_cpus();
687 do_init_master_cpu();
688 do_init_cluster();
689
690 return 0;
691}
692
693static int hsdk_go_run(u32 cpu_start_reg)
694{
695 /* Cleanup caches, disable interrupts */
696 cleanup_before_go();
697
698 if (env_common.halt_on_boot)
699 halt_this_cpu();
700
701 /*
702 * 3 NOPs after FLAG 1 instruction are no longer required for ARCv2
703 * cores but we leave them for gebug purposes.
704 */
705 __builtin_arc_nop();
706 __builtin_arc_nop();
707 __builtin_arc_nop();
708
709 /* Kick chosen slave CPUs */
710 writel(cpu_start_reg, (void __iomem *)CREG_CPU_START);
711
712 if (is_cpu_used(MASTER_CPU_ID))
713 ((void (*)(void))(env_core.entry[MASTER_CPU_ID].val))();
714 else
715 halt_this_cpu();
716
717 pr_err("u-boot still runs on cpu [%ld]\n", CPU_ID_GET());
718
719 /*
720 * We will never return after executing our program if master cpu used
721 * otherwise halt master cpu manually.
722 */
723 while (true)
724 halt_this_cpu();
725
726 return 0;
727}
728
729int board_prep_linux(bootm_headers_t *images)
730{
731 int ret, ofst;
732 char mask[15];
733
734 ret = envs_read_validate_common(env_map_mask);
735 if (ret)
736 return ret;
737
738 /* Rollback to default values */
739 if (!env_common.core_mask.set) {
740 env_common.core_mask.val = ALL_CPU_MASK;
741 env_common.core_mask.set = true;
742 }
743
744 printf("CPU start mask is %#x\n", env_common.core_mask.val);
745
746 if (!is_cpu_used(MASTER_CPU_ID))
747 pr_err("ERR: try to launch linux with CPU[0] disabled! It doesn't work for ARC.\n");
748
749 /*
750 * If we want to launch linux on all CPUs we don't need to patch
751 * linux DTB as it is default configuration
752 */
753 if (env_common.core_mask.val == ALL_CPU_MASK)
754 return 0;
755
756 if (!IMAGE_ENABLE_OF_LIBFDT || !images->ft_len) {
757 pr_err("WARN: core_mask setup will work properly only with external DTB!\n");
758 return 0;
759 }
760
761 /* patch '/possible-cpus' property according to cpu mask */
762 ofst = fdt_path_offset(images->ft_addr, "/");
763 sprintf(mask, "%s%s%s%s",
764 is_cpu_used(0) ? "0," : "",
765 is_cpu_used(1) ? "1," : "",
766 is_cpu_used(2) ? "2," : "",
767 is_cpu_used(3) ? "3," : "");
768 ret = fdt_setprop_string(images->ft_addr, ofst, "possible-cpus", mask);
769 /*
770 * If we failed to patch '/possible-cpus' property we don't need break
771 * linux loading process: kernel will handle it but linux will print
772 * warning like "Timeout: CPU1 FAILED to comeup !!!".
773 * So warn here about error, but return 0 like no error had occurred.
774 */
775 if (ret)
776 pr_err("WARN: failed to patch '/possible-cpus' property, ret=%d\n",
777 ret);
778
779 return 0;
780}
781
782void board_jump_and_run(ulong entry, int zero, int arch, uint params)
783{
784 void (*kernel_entry)(int zero, int arch, uint params);
785 u32 cpu_start_reg;
786
787 kernel_entry = (void (*)(int, int, uint))entry;
788
789 /* Prepare CREG_CPU_START for kicking chosen CPUs */
790 cpu_start_reg = prepare_cpu_ctart_reg();
791
792 /* In case of run without hsdk_init */
793 slave_cpu_set_boot_addr(entry);
794
795 /* In case of run with hsdk_init */
796 for (u32 i = 0; i < NR_CPUS; i++) {
797 env_core.entry[i].val = entry;
798 env_core.entry[i].set = true;
799 }
800 /* sync cross_cpu struct as we updated core-entry variables */
801 sync_cross_cpu_data();
802
803 /* Kick chosen slave CPUs */
804 writel(cpu_start_reg, (void __iomem *)CREG_CPU_START);
805
806 if (is_cpu_used(0))
807 kernel_entry(zero, arch, params);
808}
809
810static int hsdk_go_prepare_and_run(void)
811{
812 /* Prepare CREG_CPU_START for kicking chosen CPUs */
813 u32 reg = prepare_cpu_ctart_reg();
814
815 if (env_common.halt_on_boot)
816 printf("CPU will halt before application start, start application with debugger.\n");
817
818 return hsdk_go_run(reg);
819}
820
821static int do_hsdk_go(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
822{
823 int ret;
824
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +0300825 if (board_mismatch()) {
826 printf("ERR: U-boot is not configured for this board!\n");
827 return CMD_RET_FAILURE;
828 }
829
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300830 /*
831 * Check for 'halt' parameter. 'halt' = enter halt-mode just before
832 * starting the application; can be used for debug.
833 */
834 if (argc > 1) {
835 env_common.halt_on_boot = !strcmp(argv[1], "halt");
836 if (!env_common.halt_on_boot) {
837 pr_err("Unrecognised parameter: \'%s\'\n", argv[1]);
838 return CMD_RET_FAILURE;
839 }
840 }
841
842 ret = check_master_cpu_id();
843 if (ret)
844 return ret;
845
846 ret = envs_process_and_validate(env_map_mask, env_map_go, is_cpu_used);
847 if (ret)
848 return ret;
849
850 /* sync cross_cpu struct as we updated core-entry variables */
851 sync_cross_cpu_data();
852
853 ret = hsdk_go_prepare_and_run();
854
855 return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
856}
857
858U_BOOT_CMD(
859 hsdk_go, 3, 0, do_hsdk_go,
860 "Synopsys HSDK specific command",
861 " - Boot stand-alone application on HSDK\n"
862 "hsdk_go halt - Boot stand-alone application on HSDK, halt CPU just before application run\n"
863);
864
865static int do_hsdk_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
866{
867 static bool done = false;
868 int ret;
869
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +0300870 if (board_mismatch()) {
871 printf("ERR: U-boot is not configured for this board!\n");
872 return CMD_RET_FAILURE;
873 }
874
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +0300875 /* hsdk_init can be run only once */
876 if (done) {
877 printf("HSDK HW is already initialized! Please reset the board if you want to change the configuration.\n");
878 return CMD_RET_FAILURE;
879 }
880
881 ret = prepare_cpus();
882 if (!ret)
883 done = true;
884
885 return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
886}
887
888U_BOOT_CMD(
889 hsdk_init, 1, 0, do_hsdk_init,
890 "Synopsys HSDK specific command",
891 "- Init HSDK HW\n"
892);
893
894static int do_hsdk_clock_set(cmd_tbl_t *cmdtp, int flag, int argc,
895 char *const argv[])
896{
897 int ret = 0;
898
899 /* Strip off leading subcommand argument */
900 argc--;
901 argv++;
902
903 envs_cleanup_common(env_map_clock);
904
905 if (!argc) {
906 printf("Set clocks to values specified in environment\n");
907 ret = envs_read_common(env_map_clock);
908 } else {
909 printf("Set clocks to values specified in args\n");
910 ret = args_envs_enumerate(env_map_clock, 2, argc, argv);
911 }
912
913 if (ret)
914 return CMD_RET_FAILURE;
915
916 ret = envs_validate_common(env_map_clock);
917 if (ret)
918 return CMD_RET_FAILURE;
919
920 /* Setup clock tree HW */
921 setup_clocks();
922
923 return CMD_RET_SUCCESS;
924}
925
926static int do_hsdk_clock_get(cmd_tbl_t *cmdtp, int flag, int argc,
927 char *const argv[])
928{
929 ulong rate;
930
931 if (soc_clk_ctl("cpu-clk", &rate, CLK_GET | CLK_MHZ))
932 return CMD_RET_FAILURE;
933
934 if (env_set_ulong("cpu_freq", rate))
935 return CMD_RET_FAILURE;
936
937 if (soc_clk_ctl("tun-clk", &rate, CLK_GET | CLK_MHZ))
938 return CMD_RET_FAILURE;
939
940 if (env_set_ulong("tun_freq", rate))
941 return CMD_RET_FAILURE;
942
943 if (soc_clk_ctl("axi-clk", &rate, CLK_GET | CLK_MHZ))
944 return CMD_RET_FAILURE;
945
946 if (env_set_ulong("axi_freq", rate))
947 return CMD_RET_FAILURE;
948
949 printf("Clock values are saved to environment\n");
950
951 return CMD_RET_SUCCESS;
952}
953
954static int do_hsdk_clock_print(cmd_tbl_t *cmdtp, int flag, int argc,
955 char *const argv[])
956{
957 /* Main clocks */
958 soc_clk_ctl("cpu-clk", NULL, CLK_PRINT | CLK_MHZ);
959 soc_clk_ctl("tun-clk", NULL, CLK_PRINT | CLK_MHZ);
960 soc_clk_ctl("axi-clk", NULL, CLK_PRINT | CLK_MHZ);
961 soc_clk_ctl("ddr-clk", NULL, CLK_PRINT | CLK_MHZ);
962
963 return CMD_RET_SUCCESS;
964}
965
966static int do_hsdk_clock_print_all(cmd_tbl_t *cmdtp, int flag, int argc,
967 char *const argv[])
968{
969 /*
970 * NOTE: as of today we don't use some peripherals like HDMI / EBI
971 * so we don't want to print their clocks ("hdmi-sys-clk", "hdmi-pll",
972 * "hdmi-clk", "ebi-clk"). Nevertheless their clock subsystems is fully
973 * functional and we can print their clocks if it is required
974 */
975
976 /* CPU clock domain */
977 soc_clk_ctl("cpu-pll", NULL, CLK_PRINT | CLK_MHZ);
978 soc_clk_ctl("cpu-clk", NULL, CLK_PRINT | CLK_MHZ);
979 printf("\n");
980
981 /* SYS clock domain */
982 soc_clk_ctl("sys-pll", NULL, CLK_PRINT | CLK_MHZ);
983 soc_clk_ctl("apb-clk", NULL, CLK_PRINT | CLK_MHZ);
984 soc_clk_ctl("axi-clk", NULL, CLK_PRINT | CLK_MHZ);
985 soc_clk_ctl("eth-clk", NULL, CLK_PRINT | CLK_MHZ);
986 soc_clk_ctl("usb-clk", NULL, CLK_PRINT | CLK_MHZ);
987 soc_clk_ctl("sdio-clk", NULL, CLK_PRINT | CLK_MHZ);
988/* soc_clk_ctl("hdmi-sys-clk", NULL, CLK_PRINT | CLK_MHZ); */
989 soc_clk_ctl("gfx-core-clk", NULL, CLK_PRINT | CLK_MHZ);
990 soc_clk_ctl("gfx-dma-clk", NULL, CLK_PRINT | CLK_MHZ);
991 soc_clk_ctl("gfx-cfg-clk", NULL, CLK_PRINT | CLK_MHZ);
992 soc_clk_ctl("dmac-core-clk", NULL, CLK_PRINT | CLK_MHZ);
993 soc_clk_ctl("dmac-cfg-clk", NULL, CLK_PRINT | CLK_MHZ);
994 soc_clk_ctl("sdio-ref-clk", NULL, CLK_PRINT | CLK_MHZ);
995 soc_clk_ctl("spi-clk", NULL, CLK_PRINT | CLK_MHZ);
996 soc_clk_ctl("i2c-clk", NULL, CLK_PRINT | CLK_MHZ);
997/* soc_clk_ctl("ebi-clk", NULL, CLK_PRINT | CLK_MHZ); */
998 soc_clk_ctl("uart-clk", NULL, CLK_PRINT | CLK_MHZ);
999 printf("\n");
1000
1001 /* DDR clock domain */
1002 soc_clk_ctl("ddr-clk", NULL, CLK_PRINT | CLK_MHZ);
1003 printf("\n");
1004
1005 /* HDMI clock domain */
1006/* soc_clk_ctl("hdmi-pll", NULL, CLK_PRINT | CLK_MHZ); */
1007/* soc_clk_ctl("hdmi-clk", NULL, CLK_PRINT | CLK_MHZ); */
1008/* printf("\n"); */
1009
1010 /* TUN clock domain */
1011 soc_clk_ctl("tun-pll", NULL, CLK_PRINT | CLK_MHZ);
1012 soc_clk_ctl("tun-clk", NULL, CLK_PRINT | CLK_MHZ);
1013 soc_clk_ctl("rom-clk", NULL, CLK_PRINT | CLK_MHZ);
1014 soc_clk_ctl("pwm-clk", NULL, CLK_PRINT | CLK_MHZ);
1015 printf("\n");
1016
1017 return CMD_RET_SUCCESS;
1018}
1019
1020cmd_tbl_t cmd_hsdk_clock[] = {
1021 U_BOOT_CMD_MKENT(set, 3, 0, do_hsdk_clock_set, "", ""),
1022 U_BOOT_CMD_MKENT(get, 3, 0, do_hsdk_clock_get, "", ""),
1023 U_BOOT_CMD_MKENT(print, 4, 0, do_hsdk_clock_print, "", ""),
1024 U_BOOT_CMD_MKENT(print_all, 4, 0, do_hsdk_clock_print_all, "", ""),
1025};
1026
1027static int do_hsdk_clock(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
1028{
1029 cmd_tbl_t *c;
1030
1031 if (argc < 2)
1032 return CMD_RET_USAGE;
1033
1034 /* Strip off leading 'hsdk_clock' command argument */
1035 argc--;
1036 argv++;
1037
1038 c = find_cmd_tbl(argv[0], cmd_hsdk_clock, ARRAY_SIZE(cmd_hsdk_clock));
1039 if (!c)
1040 return CMD_RET_USAGE;
1041
1042 return c->cmd(cmdtp, flag, argc, argv);
1043}
1044
1045U_BOOT_CMD(
1046 hsdk_clock, CONFIG_SYS_MAXARGS, 0, do_hsdk_clock,
1047 "Synopsys HSDK specific clock command",
1048 "set - Set clock to values specified in environment / command line arguments\n"
1049 "hsdk_clock get - Save clock values to environment\n"
1050 "hsdk_clock print - Print main clock values to console\n"
1051 "hsdk_clock print_all - Print all clock values to console\n"
1052);
1053
1054/* init calls */
1055int board_early_init_f(void)
1056{
1057 /*
1058 * Setup AXI apertures unconditionally as we want to have DDR
1059 * in 0x00000000 region when we are kicking slave cpus.
1060 */
1061 init_memory_bridge();
1062
Eugeniy Paltsev54858312019-02-25 18:35:29 +03001063 /*
1064 * Switch SDIO external ciu clock divider from default div-by-8 to
1065 * minimum possible div-by-2.
1066 */
1067 writel(SDIO_UHS_REG_EXT_DIV_2, (void __iomem *)SDIO_UHS_REG_EXT);
1068
Eugeniy Paltsevada8aff2018-03-26 15:57:37 +03001069 return 0;
1070}
1071
1072int board_early_init_r(void)
1073{
1074 /*
1075 * TODO: Init USB here to be able read environment from USB MSD.
1076 * It can be done with usb_init() call. We can't do it right now
1077 * due to brocken USB IP SW reset and lack of USB IP HW reset in
1078 * linux kernel (if we init USB here we will break USB in linux)
1079 */
1080
1081 /*
1082 * Flush all d$ as we want to use uncached area with st.di / ld.di
1083 * instructions and we don't want to have any dirty line in L1d$ or SL$
1084 * in this area. It is enough to flush all d$ once here as we access to
1085 * uncached area with regular st (non .di) instruction only when we copy
1086 * data during u-boot relocation.
1087 */
1088 flush_dcache_all();
1089
1090 printf("Relocation Offset is: %08lx\n", gd->reloc_off);
1091
1092 return 0;
1093}
1094
1095int board_late_init(void)
1096{
1097 /*
1098 * Populate environment with clock frequency values -
1099 * run hsdk_clock get callback without uboot command run.
1100 */
1101 do_hsdk_clock_get(NULL, 0, 0, NULL);
1102
1103 return 0;
1104}
Eugeniy Paltsev4e782b52017-10-21 15:35:12 +03001105
Alexey Brodkin6ef705b2018-11-27 09:47:01 +03001106int checkboard(void)
1107{
Eugeniy Paltsevf0f84ef2020-04-22 00:33:40 +03001108 printf("Board: Synopsys %s\n", board_name(get_board_type_runtime()));
1109
1110 if (board_mismatch())
1111 printf("WARN: U-boot is configured NOT for this board but for %s!\n",
1112 board_name(get_board_type_config()));
1113
Alexey Brodkin6ef705b2018-11-27 09:47:01 +03001114 return 0;
1115};