1 /* Copyright (c) 2021 Intel Corporation
2 * SPDX-License-Identifier: Apache-2.0
3 */
4 #ifndef __INTEL_ADSP_CPU_INIT_H
5 #define __INTEL_ADSP_CPU_INIT_H
6
7 #include <zephyr/arch/arch_inlines.h>
8 #include <zephyr/arch/xtensa/arch.h>
9 #include <xtensa/config/core-isa.h>
10 #include <xtensa/corebits.h>
11 #include <adsp_memory.h>
12
13 #define MEMCTL_VALUE (MEMCTL_INV_EN | MEMCTL_ICWU_MASK | MEMCTL_DCWA_MASK | \
14 MEMCTL_DCWU_MASK | MEMCTL_L0IBUF_EN)
15
16 #define ATOMCTL_BY_RCW BIT(0) /* RCW Transaction for Bypass Memory */
17 #define ATOMCTL_WT_RCW BIT(2) /* RCW Transaction for Writethrough Cacheable Memory */
18 #define ATOMCTL_WB_RCW BIT(4) /* RCW Transaction for Writeback Cacheable Memory */
19 #define ATOMCTL_VALUE (ATOMCTL_BY_RCW | ATOMCTL_WT_RCW | ATOMCTL_WB_RCW)
20
21 #ifdef CONFIG_INTEL_ADSP_MEMORY_IS_MIRRORED
22
23 /* Utility to generate an unrolled and optimal[1] code sequence to set
24 * the RPO TLB registers (contra the HAL cacheattr macros, which
25 * generate larger code and can't be called from C), based on the
26 * KERNEL_COHERENCE configuration in use. Selects RPO attribute "2"
27 * for regions (including MMIO registers in region zero) which want to
28 * bypass L1, "4" for the cached region which wants writeback, and
29 * "15" (invalid) elsewhere.
30 *
31 * Note that on cores that have the "translation" option set, we need
32 * to put an identity mapping in the high bits. Also per spec
33 * changing the current code region (by definition cached) requires
34 * that WITLB be followed by an ISYNC and that both instructions live
35 * in the same cache line (two 3-byte instructions fit in an 8-byte
36 * aligned region, so that's guaranteed not to cross a cache line
37 * boundary).
38 *
39 * [1] With the sole exception of gcc's infuriating insistence on
40 * emitting a precomputed literal for addr + addrincr instead of
41 * computing it with a single ADD instruction from values it already
42 * has in registers. Explicitly assigning the variables to registers
43 * via an attribute works, but then emits needless MOV instructions
44 * instead. I tell myself it's just 32 bytes of .text, but... Sigh.
45 */
46 #define _REGION_ATTR(r) \
47 ((r) == 0 ? 2 : \
48 ((r) == CONFIG_INTEL_ADSP_CACHED_REGION ? 4 : \
49 ((r) == CONFIG_INTEL_ADSP_UNCACHED_REGION ? 2 : 15)))
50
51 #define _SET_ONE_TLB(region) do { \
52 uint32_t attr = _REGION_ATTR(region); \
53 if (XCHAL_HAVE_XLT_CACHEATTR) { \
54 attr |= addr; /* RPO with translation */ \
55 } \
56 if (region != CONFIG_INTEL_ADSP_CACHED_REGION) { \
57 __asm__ volatile("wdtlb %0, %1; witlb %0, %1" \
58 :: "r"(attr), "r"(addr)); \
59 } else { \
60 __asm__ volatile("wdtlb %0, %1" \
61 :: "r"(attr), "r"(addr)); \
62 __asm__ volatile("j 1f; .align 8; 1:"); \
63 __asm__ volatile("witlb %0, %1; isync" \
64 :: "r"(attr), "r"(addr)); \
65 } \
66 addr += addrincr; \
67 } while (0)
68
69 /**
70 * @brief Setup RPO TLB registers.
71 */
72 #define SET_RPO_TLB() \
73 do { \
74 register uint32_t addr = 0, addrincr = 0x20000000; \
75 FOR_EACH(_SET_ONE_TLB, (;), 0, 1, 2, 3, 4, 5, 6, 7); \
76 } while (0)
77
78 #endif /* CONFIG_INTEL_ADSP_MEMORY_IS_MIRRORED */
79
80 /* Low-level CPU initialization. Call this immediately after entering
81 * C code to initialize the cache, protection and synchronization
82 * features.
83 */
cpu_early_init(void)84 static ALWAYS_INLINE void cpu_early_init(void)
85 {
86 uint32_t reg;
87
88 #ifdef CONFIG_ADSP_NEED_POWER_ON_CACHE
89 /* First, we need to power the cache SRAM banks on! Write a bit
90 * for each cache way in the bottom half of the L1CCFG register
91 * and poll the top half for them to turn on.
92 */
93 uint32_t dmask = BIT(ADSP_CxL1CCAP_DCMWC) - 1;
94 uint32_t imask = BIT(ADSP_CxL1CCAP_ICMWC) - 1;
95 uint32_t waymask = (imask << 8) | dmask;
96
97 ADSP_CxL1CCFG_REG = waymask;
98 while (((ADSP_CxL1CCFG_REG >> 16) & waymask) != waymask) {
99 }
100
101 /* Prefetcher also power gates, same interface */
102 ADSP_CxL1PCFG_REG = 1;
103 while ((ADSP_CxL1PCFG_REG & 0x10000) == 0) {
104 }
105 #endif
106
107 /* Now set up the Xtensa CPU to enable the cache logic. The
108 * details of the fields are somewhat complicated, but per the
109 * ISA ref: "Turning on caches at power-up usually consists of
110 * writing a constant with bits[31:8] all 1’s to MEMCTL.".
111 * Also set bit 0 to enable the LOOP extension instruction
112 * fetch buffer.
113 */
114 #if XCHAL_USE_MEMCTL
115 reg = MEMCTL_VALUE;
116 XTENSA_WSR("MEMCTL", reg);
117 __asm__ volatile("rsync");
118 #endif
119
120 #if XCHAL_HAVE_THREADPTR
121 reg = 0;
122 XTENSA_WUR("THREADPTR", reg);
123 #endif
124
125 /* Likewise enable prefetching. Sadly these values are not
126 * architecturally defined by Xtensa (they're just documented
127 * as priority hints), so this constant is just copied from
128 * SOF for now. If we care about prefetch priority tuning
129 * we're supposed to ask Cadence I guess.
130 */
131 reg = ADSP_L1_CACHE_PREFCTL_VALUE;
132 XTENSA_WSR("PREFCTL", reg);
133 __asm__ volatile("rsync");
134
135 /* Finally we need to enable the cache in the Region
136 * Protection Option "TLB" entries. The hardware defaults
137 * have this set to RW/uncached everywhere.
138 *
139 * If we have MMU enabled, we don't need to do this right now.
140 * Let use the default configuration and properly configure the
141 * MMU when running from RAM.
142 */
143 #if defined(CONFIG_INTEL_ADSP_MEMORY_IS_MIRRORED) && !defined(CONFIG_MMU)
144 SET_RPO_TLB();
145 #endif /* CONFIG_INTEL_ADSP_MEMORY_IS_MIRRORED && !CONFIG_MMU */
146
147
148 /* Initialize ATOMCTL: Hardware defaults for S32C1I use
149 * "internal" operations, meaning they are atomic only WRT the
150 * local CPU! We need external transactions on the shared
151 * bus.
152 */
153 reg = ATOMCTL_VALUE;
154 XTENSA_WSR("ATOMCTL", reg);
155
156 /* Initialize interrupts to "disabled" */
157 reg = 0;
158 XTENSA_WSR("INTENABLE", reg);
159
160 /* Finally VECBASE. Note that on core 0 startup, we're still
161 * running in IMR and the vectors at this address won't be
162 * copied into HP-SRAM until later. That's OK, as interrupts
163 * are still disabled at this stage and will remain so
164 * consistently until Zephyr switches into the main thread.
165 */
166 reg = VECBASE_RESET_PADDR_SRAM;
167 XTENSA_WSR("VECBASE", reg);
168 }
169
170 #endif /* __INTEL_ADSP_CPU_INIT_H */
171