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