Commit d91e719fc830e011b182abb9712ed09b76f1d400
Committed by
Ye Li
1 parent
887f338901
Exists in
smarc_8mm-imx_v2019.04_4.19.35_1.1.0
and in
1 other branch
MLK-22836 imx8m: soc: Fix secure boot support for i.MX8MM and i.MX8MN targets
Since commit c98b47f1ff60 ("MLK-22749 imx8mq: Add workaround to fix sticky bits lock up") it's not possible to build i.MX8MM and i.MX8MN targets with CONFIG_SECURE_BOOT enabled: CC cmd/version.o arch/arm/mach-imx/imx8m/soc.c:326:23: error: ‘CONFIG_IMX_UNIQUE_ID’ undeclared \ (first use in this function); did you mean ‘CONFIG_IMX_VIDEO_SKIP’? if (!is_uid_matched(CONFIG_IMX_UNIQUE_ID)) ^~~~~~~~~~~~~~~~~~~~ The OCOTP sticky bit workaround is only needed for i.MX8MQ devices, other devices should not build the secure_lockup() function. Add CONFIG_IMX8MQ to the conditional compilation to avoid such issue. Fixes: c98b47f1ff60 ("MLK-22749 imx8mq: Add workaround to fix sticky bits lock up") Signed-off-by: Breno Lima <breno.lima@nxp.com> Reviewed-by: Ye Li <ye.li@nxp.com> (cherry picked from commit be033bff3c718e8bd7d4ac5ecfe4361892fc6e61)
Showing 1 changed file with 2 additions and 2 deletions Inline Diff
arch/arm/mach-imx/imx8m/soc.c
1 | // SPDX-License-Identifier: GPL-2.0+ | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | 2 | /* |
3 | * Copyright 2017-2019 NXP | 3 | * Copyright 2017-2019 NXP |
4 | * | 4 | * |
5 | * Peng Fan <peng.fan@nxp.com> | 5 | * Peng Fan <peng.fan@nxp.com> |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <common.h> | 8 | #include <common.h> |
9 | #include <asm/arch/imx-regs.h> | 9 | #include <asm/arch/imx-regs.h> |
10 | #include <asm/io.h> | 10 | #include <asm/io.h> |
11 | #include <asm/arch/clock.h> | 11 | #include <asm/arch/clock.h> |
12 | #include <asm/arch/sys_proto.h> | 12 | #include <asm/arch/sys_proto.h> |
13 | #include <asm/mach-imx/hab.h> | 13 | #include <asm/mach-imx/hab.h> |
14 | #include <asm/mach-imx/boot_mode.h> | 14 | #include <asm/mach-imx/boot_mode.h> |
15 | #include <asm/mach-imx/syscounter.h> | 15 | #include <asm/mach-imx/syscounter.h> |
16 | #include <asm/armv8/mmu.h> | 16 | #include <asm/armv8/mmu.h> |
17 | #include <errno.h> | 17 | #include <errno.h> |
18 | #include <fdt_support.h> | 18 | #include <fdt_support.h> |
19 | #include <fdtdec.h> | 19 | #include <fdtdec.h> |
20 | #include <fsl_wdog.h> | 20 | #include <fsl_wdog.h> |
21 | #include <imx_sip.h> | 21 | #include <imx_sip.h> |
22 | #include <generated/version_autogenerated.h> | 22 | #include <generated/version_autogenerated.h> |
23 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
24 | #include <asm/bootm.h> | 24 | #include <asm/bootm.h> |
25 | #ifdef CONFIG_IMX_SEC_INIT | 25 | #ifdef CONFIG_IMX_SEC_INIT |
26 | #include <fsl_caam.h> | 26 | #include <fsl_caam.h> |
27 | #endif | 27 | #endif |
28 | #include <environment.h> | 28 | #include <environment.h> |
29 | #include <efi_loader.h> | 29 | #include <efi_loader.h> |
30 | 30 | ||
31 | DECLARE_GLOBAL_DATA_PTR; | 31 | DECLARE_GLOBAL_DATA_PTR; |
32 | 32 | ||
33 | #if defined(CONFIG_SECURE_BOOT) || defined(CONFIG_AVB_ATX) || defined(CONFIG_IMX_TRUSTY_OS) | 33 | #if defined(CONFIG_SECURE_BOOT) || defined(CONFIG_AVB_ATX) || defined(CONFIG_IMX_TRUSTY_OS) |
34 | struct imx_sec_config_fuse_t const imx_sec_config_fuse = { | 34 | struct imx_sec_config_fuse_t const imx_sec_config_fuse = { |
35 | .bank = 1, | 35 | .bank = 1, |
36 | .word = 3, | 36 | .word = 3, |
37 | }; | 37 | }; |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | int timer_init(void) | 40 | int timer_init(void) |
41 | { | 41 | { |
42 | #ifdef CONFIG_SPL_BUILD | 42 | #ifdef CONFIG_SPL_BUILD |
43 | struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR; | 43 | struct sctr_regs *sctr = (struct sctr_regs *)SYSCNT_CTRL_BASE_ADDR; |
44 | unsigned long freq = readl(&sctr->cntfid0); | 44 | unsigned long freq = readl(&sctr->cntfid0); |
45 | 45 | ||
46 | /* Update with accurate clock frequency */ | 46 | /* Update with accurate clock frequency */ |
47 | asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory"); | 47 | asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory"); |
48 | 48 | ||
49 | clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1, | 49 | clrsetbits_le32(&sctr->cntcr, SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1, |
50 | SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG); | 50 | SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG); |
51 | #endif | 51 | #endif |
52 | 52 | ||
53 | gd->arch.tbl = 0; | 53 | gd->arch.tbl = 0; |
54 | gd->arch.tbu = 0; | 54 | gd->arch.tbu = 0; |
55 | 55 | ||
56 | return 0; | 56 | return 0; |
57 | } | 57 | } |
58 | 58 | ||
59 | void enable_tzc380(void) | 59 | void enable_tzc380(void) |
60 | { | 60 | { |
61 | struct iomuxc_gpr_base_regs *gpr = | 61 | struct iomuxc_gpr_base_regs *gpr = |
62 | (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR; | 62 | (struct iomuxc_gpr_base_regs *)IOMUXC_GPR_BASE_ADDR; |
63 | 63 | ||
64 | /* Enable TZASC and lock setting */ | 64 | /* Enable TZASC and lock setting */ |
65 | setbits_le32(&gpr->gpr[10], GPR_TZASC_EN); | 65 | setbits_le32(&gpr->gpr[10], GPR_TZASC_EN); |
66 | setbits_le32(&gpr->gpr[10], GPR_TZASC_EN_LOCK); | 66 | setbits_le32(&gpr->gpr[10], GPR_TZASC_EN_LOCK); |
67 | #if defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN) | 67 | #if defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN) |
68 | setbits_le32(&gpr->gpr[10], GPR_TZASC_SWAP_ID); | 68 | setbits_le32(&gpr->gpr[10], GPR_TZASC_SWAP_ID); |
69 | #endif | 69 | #endif |
70 | 70 | ||
71 | /* | 71 | /* |
72 | * set Region 0 attribute to allow secure and non-secure read/write permission | 72 | * set Region 0 attribute to allow secure and non-secure read/write permission |
73 | * Found some masters like usb dwc3 controllers can't work with secure memory. | 73 | * Found some masters like usb dwc3 controllers can't work with secure memory. |
74 | */ | 74 | */ |
75 | writel(0xf0000000, TZASC_BASE_ADDR + 0x108); | 75 | writel(0xf0000000, TZASC_BASE_ADDR + 0x108); |
76 | } | 76 | } |
77 | 77 | ||
78 | void set_wdog_reset(struct wdog_regs *wdog) | 78 | void set_wdog_reset(struct wdog_regs *wdog) |
79 | { | 79 | { |
80 | /* | 80 | /* |
81 | * Output WDOG_B signal to reset external pmic or POR_B decided by | 81 | * Output WDOG_B signal to reset external pmic or POR_B decided by |
82 | * the board design. Without external reset, the peripherals/DDR/ | 82 | * the board design. Without external reset, the peripherals/DDR/ |
83 | * PMIC are not reset, that may cause system working abnormal. | 83 | * PMIC are not reset, that may cause system working abnormal. |
84 | * WDZST bit is write-once only bit. Align this bit in kernel, | 84 | * WDZST bit is write-once only bit. Align this bit in kernel, |
85 | * otherwise kernel code will have no chance to set this bit. | 85 | * otherwise kernel code will have no chance to set this bit. |
86 | */ | 86 | */ |
87 | setbits_le16(&wdog->wcr, WDOG_WDT_MASK | WDOG_WDZST_MASK); | 87 | setbits_le16(&wdog->wcr, WDOG_WDT_MASK | WDOG_WDZST_MASK); |
88 | } | 88 | } |
89 | 89 | ||
90 | static struct mm_region imx8m_mem_map[] = { | 90 | static struct mm_region imx8m_mem_map[] = { |
91 | { | 91 | { |
92 | /* ROM */ | 92 | /* ROM */ |
93 | .virt = 0x0UL, | 93 | .virt = 0x0UL, |
94 | .phys = 0x0UL, | 94 | .phys = 0x0UL, |
95 | .size = 0x100000UL, | 95 | .size = 0x100000UL, |
96 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | | 96 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | |
97 | PTE_BLOCK_OUTER_SHARE | 97 | PTE_BLOCK_OUTER_SHARE |
98 | }, { | 98 | }, { |
99 | /* CAAM */ | 99 | /* CAAM */ |
100 | .virt = 0x100000UL, | 100 | .virt = 0x100000UL, |
101 | .phys = 0x100000UL, | 101 | .phys = 0x100000UL, |
102 | .size = 0x8000UL, | 102 | .size = 0x8000UL, |
103 | .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | | 103 | .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | |
104 | PTE_BLOCK_NON_SHARE | | 104 | PTE_BLOCK_NON_SHARE | |
105 | PTE_BLOCK_PXN | PTE_BLOCK_UXN | 105 | PTE_BLOCK_PXN | PTE_BLOCK_UXN |
106 | }, { | 106 | }, { |
107 | /* TCM */ | 107 | /* TCM */ |
108 | .virt = 0x7C0000UL, | 108 | .virt = 0x7C0000UL, |
109 | .phys = 0x7C0000UL, | 109 | .phys = 0x7C0000UL, |
110 | .size = 0x80000UL, | 110 | .size = 0x80000UL, |
111 | .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | | 111 | .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | |
112 | PTE_BLOCK_NON_SHARE | | 112 | PTE_BLOCK_NON_SHARE | |
113 | PTE_BLOCK_PXN | PTE_BLOCK_UXN | 113 | PTE_BLOCK_PXN | PTE_BLOCK_UXN |
114 | }, { | 114 | }, { |
115 | /* OCRAM */ | 115 | /* OCRAM */ |
116 | .virt = 0x900000UL, | 116 | .virt = 0x900000UL, |
117 | .phys = 0x900000UL, | 117 | .phys = 0x900000UL, |
118 | .size = 0x200000UL, | 118 | .size = 0x200000UL, |
119 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | | 119 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | |
120 | PTE_BLOCK_OUTER_SHARE | 120 | PTE_BLOCK_OUTER_SHARE |
121 | }, { | 121 | }, { |
122 | /* AIPS */ | 122 | /* AIPS */ |
123 | .virt = 0xB00000UL, | 123 | .virt = 0xB00000UL, |
124 | .phys = 0xB00000UL, | 124 | .phys = 0xB00000UL, |
125 | .size = 0x3f500000UL, | 125 | .size = 0x3f500000UL, |
126 | .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | | 126 | .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | |
127 | PTE_BLOCK_NON_SHARE | | 127 | PTE_BLOCK_NON_SHARE | |
128 | PTE_BLOCK_PXN | PTE_BLOCK_UXN | 128 | PTE_BLOCK_PXN | PTE_BLOCK_UXN |
129 | }, { | 129 | }, { |
130 | /* DRAM1 */ | 130 | /* DRAM1 */ |
131 | .virt = 0x40000000UL, | 131 | .virt = 0x40000000UL, |
132 | .phys = 0x40000000UL, | 132 | .phys = 0x40000000UL, |
133 | .size = PHYS_SDRAM_SIZE, | 133 | .size = PHYS_SDRAM_SIZE, |
134 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | | 134 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | |
135 | #ifdef CONFIG_IMX_TRUSTY_OS | 135 | #ifdef CONFIG_IMX_TRUSTY_OS |
136 | PTE_BLOCK_INNER_SHARE | 136 | PTE_BLOCK_INNER_SHARE |
137 | #else | 137 | #else |
138 | PTE_BLOCK_OUTER_SHARE | 138 | PTE_BLOCK_OUTER_SHARE |
139 | #endif | 139 | #endif |
140 | #ifdef PHYS_SDRAM_2_SIZE | 140 | #ifdef PHYS_SDRAM_2_SIZE |
141 | }, { | 141 | }, { |
142 | /* DRAM2 */ | 142 | /* DRAM2 */ |
143 | .virt = 0x100000000UL, | 143 | .virt = 0x100000000UL, |
144 | .phys = 0x100000000UL, | 144 | .phys = 0x100000000UL, |
145 | .size = PHYS_SDRAM_2_SIZE, | 145 | .size = PHYS_SDRAM_2_SIZE, |
146 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | | 146 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | |
147 | #ifdef CONFIG_IMX_TRUSTY_OS | 147 | #ifdef CONFIG_IMX_TRUSTY_OS |
148 | PTE_BLOCK_INNER_SHARE | 148 | PTE_BLOCK_INNER_SHARE |
149 | #else | 149 | #else |
150 | PTE_BLOCK_OUTER_SHARE | 150 | PTE_BLOCK_OUTER_SHARE |
151 | #endif | 151 | #endif |
152 | #endif | 152 | #endif |
153 | }, { | 153 | }, { |
154 | /* List terminator */ | 154 | /* List terminator */ |
155 | 0, | 155 | 0, |
156 | } | 156 | } |
157 | }; | 157 | }; |
158 | 158 | ||
159 | struct mm_region *mem_map = imx8m_mem_map; | 159 | struct mm_region *mem_map = imx8m_mem_map; |
160 | 160 | ||
161 | void enable_caches(void) | 161 | void enable_caches(void) |
162 | { | 162 | { |
163 | /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch */ | 163 | /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch */ |
164 | if (rom_pointer[1]) { | 164 | if (rom_pointer[1]) { |
165 | imx8m_mem_map[5].size -= rom_pointer[1]; | 165 | imx8m_mem_map[5].size -= rom_pointer[1]; |
166 | } | 166 | } |
167 | 167 | ||
168 | icache_enable(); | 168 | icache_enable(); |
169 | dcache_enable(); | 169 | dcache_enable(); |
170 | } | 170 | } |
171 | 171 | ||
172 | static u32 get_cpu_variant_type(u32 type) | 172 | static u32 get_cpu_variant_type(u32 type) |
173 | { | 173 | { |
174 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | 174 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; |
175 | struct fuse_bank *bank = &ocotp->bank[1]; | 175 | struct fuse_bank *bank = &ocotp->bank[1]; |
176 | struct fuse_bank1_regs *fuse = | 176 | struct fuse_bank1_regs *fuse = |
177 | (struct fuse_bank1_regs *)bank->fuse_regs; | 177 | (struct fuse_bank1_regs *)bank->fuse_regs; |
178 | 178 | ||
179 | u32 value = readl(&fuse->tester4); | 179 | u32 value = readl(&fuse->tester4); |
180 | 180 | ||
181 | if (type == MXC_CPU_IMX8MQ) { | 181 | if (type == MXC_CPU_IMX8MQ) { |
182 | if ((value & 0x3) == 0x2) | 182 | if ((value & 0x3) == 0x2) |
183 | return MXC_CPU_IMX8MD; | 183 | return MXC_CPU_IMX8MD; |
184 | else if (value & 0x200000) | 184 | else if (value & 0x200000) |
185 | return MXC_CPU_IMX8MQL; | 185 | return MXC_CPU_IMX8MQL; |
186 | 186 | ||
187 | } else if (type == MXC_CPU_IMX8MM) { | 187 | } else if (type == MXC_CPU_IMX8MM) { |
188 | switch (value & 0x3) { | 188 | switch (value & 0x3) { |
189 | case 2: | 189 | case 2: |
190 | if (value & 0x1c0000) | 190 | if (value & 0x1c0000) |
191 | return MXC_CPU_IMX8MMDL; | 191 | return MXC_CPU_IMX8MMDL; |
192 | else | 192 | else |
193 | return MXC_CPU_IMX8MMD; | 193 | return MXC_CPU_IMX8MMD; |
194 | case 3: | 194 | case 3: |
195 | if (value & 0x1c0000) | 195 | if (value & 0x1c0000) |
196 | return MXC_CPU_IMX8MMSL; | 196 | return MXC_CPU_IMX8MMSL; |
197 | else | 197 | else |
198 | return MXC_CPU_IMX8MMS; | 198 | return MXC_CPU_IMX8MMS; |
199 | default: | 199 | default: |
200 | if (value & 0x1c0000) | 200 | if (value & 0x1c0000) |
201 | return MXC_CPU_IMX8MML; | 201 | return MXC_CPU_IMX8MML; |
202 | break; | 202 | break; |
203 | } | 203 | } |
204 | } else if (type == MXC_CPU_IMX8MN) { | 204 | } else if (type == MXC_CPU_IMX8MN) { |
205 | switch (value & 0x3) { | 205 | switch (value & 0x3) { |
206 | case 2: | 206 | case 2: |
207 | if (value & 0x1000000) | 207 | if (value & 0x1000000) |
208 | return MXC_CPU_IMX8MNDL; | 208 | return MXC_CPU_IMX8MNDL; |
209 | else | 209 | else |
210 | return MXC_CPU_IMX8MND; | 210 | return MXC_CPU_IMX8MND; |
211 | case 3: | 211 | case 3: |
212 | if (value & 0x1000000) | 212 | if (value & 0x1000000) |
213 | return MXC_CPU_IMX8MNSL; | 213 | return MXC_CPU_IMX8MNSL; |
214 | else | 214 | else |
215 | return MXC_CPU_IMX8MNS; | 215 | return MXC_CPU_IMX8MNS; |
216 | default: | 216 | default: |
217 | if (value & 0x1000000) | 217 | if (value & 0x1000000) |
218 | return MXC_CPU_IMX8MNL; | 218 | return MXC_CPU_IMX8MNL; |
219 | break; | 219 | break; |
220 | } | 220 | } |
221 | } | 221 | } |
222 | 222 | ||
223 | return type; | 223 | return type; |
224 | } | 224 | } |
225 | 225 | ||
226 | u32 get_cpu_rev(void) | 226 | u32 get_cpu_rev(void) |
227 | { | 227 | { |
228 | struct anamix_pll *ana_pll = (struct anamix_pll *)ANATOP_BASE_ADDR; | 228 | struct anamix_pll *ana_pll = (struct anamix_pll *)ANATOP_BASE_ADDR; |
229 | u32 reg = readl(&ana_pll->digprog); | 229 | u32 reg = readl(&ana_pll->digprog); |
230 | u32 type = (reg >> 16) & 0xff; | 230 | u32 type = (reg >> 16) & 0xff; |
231 | u32 major_low = (reg >> 8) & 0xff; | 231 | u32 major_low = (reg >> 8) & 0xff; |
232 | u32 rom_version; | 232 | u32 rom_version; |
233 | 233 | ||
234 | reg &= 0xff; | 234 | reg &= 0xff; |
235 | 235 | ||
236 | /* iMX8MN */ | 236 | /* iMX8MN */ |
237 | if (major_low == 0x42) { | 237 | if (major_low == 0x42) { |
238 | type = get_cpu_variant_type(MXC_CPU_IMX8MN); | 238 | type = get_cpu_variant_type(MXC_CPU_IMX8MN); |
239 | return (type << 12) | reg; | 239 | return (type << 12) | reg; |
240 | } else if (major_low == 0x41) { | 240 | } else if (major_low == 0x41) { |
241 | /* iMX8MM */ | 241 | /* iMX8MM */ |
242 | type = get_cpu_variant_type(MXC_CPU_IMX8MM); | 242 | type = get_cpu_variant_type(MXC_CPU_IMX8MM); |
243 | return (type << 12) | reg; | 243 | return (type << 12) | reg; |
244 | } else { | 244 | } else { |
245 | /* iMX8MQ */ | 245 | /* iMX8MQ */ |
246 | if (reg == CHIP_REV_1_0) { | 246 | if (reg == CHIP_REV_1_0) { |
247 | /* | 247 | /* |
248 | * For B0 chip, the DIGPROG is not updated, still TO1.0. | 248 | * For B0 chip, the DIGPROG is not updated, still TO1.0. |
249 | * we have to check ROM version or OCOTP_READ_FUSE_DATA | 249 | * we have to check ROM version or OCOTP_READ_FUSE_DATA |
250 | */ | 250 | */ |
251 | if (readl((void __iomem *)(OCOTP_BASE_ADDR + 0x40)) | 251 | if (readl((void __iomem *)(OCOTP_BASE_ADDR + 0x40)) |
252 | == 0xff0055aa) { | 252 | == 0xff0055aa) { |
253 | /* 0xff0055aa is magic number for B1 */ | 253 | /* 0xff0055aa is magic number for B1 */ |
254 | reg = CHIP_REV_2_1; | 254 | reg = CHIP_REV_2_1; |
255 | } else { | 255 | } else { |
256 | rom_version = readb((void __iomem *)ROM_VERSION_A0); | 256 | rom_version = readb((void __iomem *)ROM_VERSION_A0); |
257 | if (rom_version != CHIP_REV_1_0) { | 257 | if (rom_version != CHIP_REV_1_0) { |
258 | rom_version = readb((void __iomem *)ROM_VERSION_B0); | 258 | rom_version = readb((void __iomem *)ROM_VERSION_B0); |
259 | if (rom_version == CHIP_REV_2_0) | 259 | if (rom_version == CHIP_REV_2_0) |
260 | reg = CHIP_REV_2_0; | 260 | reg = CHIP_REV_2_0; |
261 | } | 261 | } |
262 | } | 262 | } |
263 | } | 263 | } |
264 | 264 | ||
265 | type = get_cpu_variant_type(type); | 265 | type = get_cpu_variant_type(type); |
266 | 266 | ||
267 | return (type << 12) | reg; | 267 | return (type << 12) | reg; |
268 | } | 268 | } |
269 | } | 269 | } |
270 | 270 | ||
271 | static void imx_set_wdog_powerdown(bool enable) | 271 | static void imx_set_wdog_powerdown(bool enable) |
272 | { | 272 | { |
273 | struct wdog_regs *wdog1 = (struct wdog_regs *)WDOG1_BASE_ADDR; | 273 | struct wdog_regs *wdog1 = (struct wdog_regs *)WDOG1_BASE_ADDR; |
274 | struct wdog_regs *wdog2 = (struct wdog_regs *)WDOG2_BASE_ADDR; | 274 | struct wdog_regs *wdog2 = (struct wdog_regs *)WDOG2_BASE_ADDR; |
275 | struct wdog_regs *wdog3 = (struct wdog_regs *)WDOG3_BASE_ADDR; | 275 | struct wdog_regs *wdog3 = (struct wdog_regs *)WDOG3_BASE_ADDR; |
276 | 276 | ||
277 | /* Write to the PDE (Power Down Enable) bit */ | 277 | /* Write to the PDE (Power Down Enable) bit */ |
278 | writew(enable, &wdog1->wmcr); | 278 | writew(enable, &wdog1->wmcr); |
279 | writew(enable, &wdog2->wmcr); | 279 | writew(enable, &wdog2->wmcr); |
280 | writew(enable, &wdog3->wmcr); | 280 | writew(enable, &wdog3->wmcr); |
281 | } | 281 | } |
282 | 282 | ||
283 | #ifdef CONFIG_SECURE_BOOT | 283 | #if defined(CONFIG_SECURE_BOOT) && defined(CONFIG_IMX8MQ) |
284 | static bool is_hdmi_fused(void) { | 284 | static bool is_hdmi_fused(void) { |
285 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | 285 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; |
286 | struct fuse_bank *bank = &ocotp->bank[1]; | 286 | struct fuse_bank *bank = &ocotp->bank[1]; |
287 | struct fuse_bank1_regs *fuse = | 287 | struct fuse_bank1_regs *fuse = |
288 | (struct fuse_bank1_regs *)bank->fuse_regs; | 288 | (struct fuse_bank1_regs *)bank->fuse_regs; |
289 | 289 | ||
290 | u32 value = readl(&fuse->tester4); | 290 | u32 value = readl(&fuse->tester4); |
291 | 291 | ||
292 | if (is_imx8mq()) { | 292 | if (is_imx8mq()) { |
293 | if (value & 0x02000000) | 293 | if (value & 0x02000000) |
294 | return true; | 294 | return true; |
295 | } | 295 | } |
296 | 296 | ||
297 | return false; | 297 | return false; |
298 | } | 298 | } |
299 | 299 | ||
300 | bool is_uid_matched(u64 uid) { | 300 | bool is_uid_matched(u64 uid) { |
301 | struct tag_serialnr nr; | 301 | struct tag_serialnr nr; |
302 | get_board_serial(&nr); | 302 | get_board_serial(&nr); |
303 | 303 | ||
304 | if (lower_32_bits(uid) == nr.low && | 304 | if (lower_32_bits(uid) == nr.low && |
305 | upper_32_bits(uid) == nr.high) | 305 | upper_32_bits(uid) == nr.high) |
306 | return true; | 306 | return true; |
307 | 307 | ||
308 | return false; | 308 | return false; |
309 | } | 309 | } |
310 | 310 | ||
311 | static void secure_lockup(void) | 311 | static void secure_lockup(void) |
312 | { | 312 | { |
313 | if (is_imx8mq() && is_soc_rev(CHIP_REV_2_1) && | 313 | if (is_imx8mq() && is_soc_rev(CHIP_REV_2_1) && |
314 | imx_hab_is_enabled() && !is_hdmi_fused()) { | 314 | imx_hab_is_enabled() && !is_hdmi_fused()) { |
315 | #ifdef CONFIG_SECURE_STICKY_BITS_LOCKUP | 315 | #ifdef CONFIG_SECURE_STICKY_BITS_LOCKUP |
316 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | 316 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; |
317 | 317 | ||
318 | clock_enable(CCGR_OCOTP, 1); | 318 | clock_enable(CCGR_OCOTP, 1); |
319 | setbits_le32(&ocotp->sw_sticky, 0x6); /* Lock up field return and SRK revoke */ | 319 | setbits_le32(&ocotp->sw_sticky, 0x6); /* Lock up field return and SRK revoke */ |
320 | writel(0x80000000, &ocotp->scs_set); /* Lock up SCS */ | 320 | writel(0x80000000, &ocotp->scs_set); /* Lock up SCS */ |
321 | 321 | ||
322 | /* Clear mfg prot private key in CAAM */ | 322 | /* Clear mfg prot private key in CAAM */ |
323 | setbits_le32((ulong)(CONFIG_SYS_FSL_SEC_ADDR + 0xc), 0x08000000); | 323 | setbits_le32((ulong)(CONFIG_SYS_FSL_SEC_ADDR + 0xc), 0x08000000); |
324 | #else | 324 | #else |
325 | /* Check the Unique ID, if it is matched with UID config, then allow to leave sticky bits unlocked */ | 325 | /* Check the Unique ID, if it is matched with UID config, then allow to leave sticky bits unlocked */ |
326 | if (!is_uid_matched(CONFIG_IMX_UNIQUE_ID)) | 326 | if (!is_uid_matched(CONFIG_IMX_UNIQUE_ID)) |
327 | hang(); | 327 | hang(); |
328 | #endif | 328 | #endif |
329 | } | 329 | } |
330 | } | 330 | } |
331 | #endif | 331 | #endif |
332 | 332 | ||
333 | int arch_cpu_init(void) | 333 | int arch_cpu_init(void) |
334 | { | 334 | { |
335 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | 335 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; |
336 | /* | 336 | /* |
337 | * Init timer at very early state, because pll setting will use it, | 337 | * Init timer at very early state, because pll setting will use it, |
338 | * Rom Turnned off SCTR, enable it before timer_init | 338 | * Rom Turnned off SCTR, enable it before timer_init |
339 | */ | 339 | */ |
340 | 340 | ||
341 | clock_enable(CCGR_SCTR, 1); | 341 | clock_enable(CCGR_SCTR, 1); |
342 | timer_init(); | 342 | timer_init(); |
343 | 343 | ||
344 | if (IS_ENABLED(CONFIG_SPL_BUILD)) { | 344 | if (IS_ENABLED(CONFIG_SPL_BUILD)) { |
345 | clock_init(); | 345 | clock_init(); |
346 | imx_set_wdog_powerdown(false); | 346 | imx_set_wdog_powerdown(false); |
347 | 347 | ||
348 | #ifdef CONFIG_SECURE_BOOT | 348 | #if defined(CONFIG_SECURE_BOOT) && defined(CONFIG_IMX8MQ) |
349 | secure_lockup(); | 349 | secure_lockup(); |
350 | #endif | 350 | #endif |
351 | if (is_imx8md() || is_imx8mmd() || is_imx8mmdl() || is_imx8mms() || is_imx8mmsl() || | 351 | if (is_imx8md() || is_imx8mmd() || is_imx8mmdl() || is_imx8mms() || is_imx8mmsl() || |
352 | is_imx8mnd() || is_imx8mndl() || is_imx8mns() || is_imx8mnsl()) { | 352 | is_imx8mnd() || is_imx8mndl() || is_imx8mns() || is_imx8mnsl()) { |
353 | /* Power down cpu core 1, 2 and 3 for iMX8M Dual core or Single core */ | 353 | /* Power down cpu core 1, 2 and 3 for iMX8M Dual core or Single core */ |
354 | struct pgc_reg *pgc_core1 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x840); | 354 | struct pgc_reg *pgc_core1 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x840); |
355 | struct pgc_reg *pgc_core2 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x880); | 355 | struct pgc_reg *pgc_core2 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x880); |
356 | struct pgc_reg *pgc_core3 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x8C0); | 356 | struct pgc_reg *pgc_core3 = (struct pgc_reg *)(GPC_BASE_ADDR + 0x8C0); |
357 | struct gpc_reg *gpc = (struct gpc_reg *)GPC_BASE_ADDR; | 357 | struct gpc_reg *gpc = (struct gpc_reg *)GPC_BASE_ADDR; |
358 | 358 | ||
359 | writel(0x1, &pgc_core2->pgcr); | 359 | writel(0x1, &pgc_core2->pgcr); |
360 | writel(0x1, &pgc_core3->pgcr); | 360 | writel(0x1, &pgc_core3->pgcr); |
361 | if (is_imx8mms() || is_imx8mmsl() || is_imx8mns() || is_imx8mnsl()) { | 361 | if (is_imx8mms() || is_imx8mmsl() || is_imx8mns() || is_imx8mnsl()) { |
362 | writel(0x1, &pgc_core1->pgcr); | 362 | writel(0x1, &pgc_core1->pgcr); |
363 | writel(0xE, &gpc->cpu_pgc_dn_trg); | 363 | writel(0xE, &gpc->cpu_pgc_dn_trg); |
364 | } else { | 364 | } else { |
365 | writel(0xC, &gpc->cpu_pgc_dn_trg); | 365 | writel(0xC, &gpc->cpu_pgc_dn_trg); |
366 | } | 366 | } |
367 | } | 367 | } |
368 | } | 368 | } |
369 | 369 | ||
370 | #ifdef CONFIG_IMX_SEC_INIT | 370 | #ifdef CONFIG_IMX_SEC_INIT |
371 | /* Secure init function such RNG */ | 371 | /* Secure init function such RNG */ |
372 | imx_sec_init(); | 372 | imx_sec_init(); |
373 | #endif | 373 | #endif |
374 | #if defined(CONFIG_ANDROID_SUPPORT) | 374 | #if defined(CONFIG_ANDROID_SUPPORT) |
375 | /* Enable RTC */ | 375 | /* Enable RTC */ |
376 | writel(0x21, 0x30370038); | 376 | writel(0x21, 0x30370038); |
377 | #endif | 377 | #endif |
378 | 378 | ||
379 | if (is_imx8mq()) { | 379 | if (is_imx8mq()) { |
380 | clock_enable(CCGR_OCOTP, 1); | 380 | clock_enable(CCGR_OCOTP, 1); |
381 | if (readl(&ocotp->ctrl) & 0x200) | 381 | if (readl(&ocotp->ctrl) & 0x200) |
382 | writel(0x200, &ocotp->ctrl_clr); | 382 | writel(0x200, &ocotp->ctrl_clr); |
383 | } | 383 | } |
384 | 384 | ||
385 | return 0; | 385 | return 0; |
386 | } | 386 | } |
387 | 387 | ||
388 | #ifdef CONFIG_IMX8MN | 388 | #ifdef CONFIG_IMX8MN |
389 | struct rom_api | 389 | struct rom_api |
390 | { | 390 | { |
391 | uint16_t ver; | 391 | uint16_t ver; |
392 | uint16_t tag; | 392 | uint16_t tag; |
393 | uint32_t reserved1; | 393 | uint32_t reserved1; |
394 | uint32_t (*download_image)(uint8_t * dest, uint32_t offset, uint32_t size, uint32_t xor); | 394 | uint32_t (*download_image)(uint8_t * dest, uint32_t offset, uint32_t size, uint32_t xor); |
395 | uint32_t (*query_boot_infor)(uint32_t info_type, uint32_t *info, uint32_t xor); | 395 | uint32_t (*query_boot_infor)(uint32_t info_type, uint32_t *info, uint32_t xor); |
396 | }; | 396 | }; |
397 | static struct rom_api* g_rom_api = (struct rom_api*)0x980; | 397 | static struct rom_api* g_rom_api = (struct rom_api*)0x980; |
398 | 398 | ||
399 | typedef enum { | 399 | typedef enum { |
400 | BT_DEV_TYPE_SD = 1, | 400 | BT_DEV_TYPE_SD = 1, |
401 | BT_DEV_TYPE_MMC = 2, | 401 | BT_DEV_TYPE_MMC = 2, |
402 | BT_DEV_TYPE_NAND = 3, | 402 | BT_DEV_TYPE_NAND = 3, |
403 | BT_DEV_TYPE_FLEXSPINOR = 4, | 403 | BT_DEV_TYPE_FLEXSPINOR = 4, |
404 | 404 | ||
405 | BT_DEV_TYPE_USB = 0xE, | 405 | BT_DEV_TYPE_USB = 0xE, |
406 | BT_DEV_TYPE_MEM_DEV = 0xF, | 406 | BT_DEV_TYPE_MEM_DEV = 0xF, |
407 | 407 | ||
408 | BT_DEV_TYPE_INVALID = 0xFF | 408 | BT_DEV_TYPE_INVALID = 0xFF |
409 | } boot_dev_type_e; | 409 | } boot_dev_type_e; |
410 | 410 | ||
411 | #define QUERY_BT_DEV 2 | 411 | #define QUERY_BT_DEV 2 |
412 | 412 | ||
413 | #define ROM_API_OKAY 0xF0 | 413 | #define ROM_API_OKAY 0xF0 |
414 | 414 | ||
415 | enum boot_device get_boot_device(void) | 415 | enum boot_device get_boot_device(void) |
416 | { | 416 | { |
417 | volatile gd_t *pgd = gd; | 417 | volatile gd_t *pgd = gd; |
418 | int ret; | 418 | int ret; |
419 | uint32_t boot; | 419 | uint32_t boot; |
420 | u16 boot_type; | 420 | u16 boot_type; |
421 | u8 boot_instance; | 421 | u8 boot_instance; |
422 | enum boot_device boot_dev = SD1_BOOT; | 422 | enum boot_device boot_dev = SD1_BOOT; |
423 | 423 | ||
424 | ret = g_rom_api->query_boot_infor(QUERY_BT_DEV, &boot, ((uintptr_t) &boot)^ QUERY_BT_DEV); | 424 | ret = g_rom_api->query_boot_infor(QUERY_BT_DEV, &boot, ((uintptr_t) &boot)^ QUERY_BT_DEV); |
425 | gd = pgd; | 425 | gd = pgd; |
426 | 426 | ||
427 | if (ret != ROM_API_OKAY) { | 427 | if (ret != ROM_API_OKAY) { |
428 | puts("ROMAPI: failure at query_boot_info\n"); | 428 | puts("ROMAPI: failure at query_boot_info\n"); |
429 | return -1; | 429 | return -1; |
430 | } | 430 | } |
431 | 431 | ||
432 | boot_type = boot >> 16; | 432 | boot_type = boot >> 16; |
433 | boot_instance = (boot >> 8) & 0xff; | 433 | boot_instance = (boot >> 8) & 0xff; |
434 | 434 | ||
435 | switch (boot_type) { | 435 | switch (boot_type) { |
436 | case BT_DEV_TYPE_SD: | 436 | case BT_DEV_TYPE_SD: |
437 | boot_dev = boot_instance + SD1_BOOT; | 437 | boot_dev = boot_instance + SD1_BOOT; |
438 | break; | 438 | break; |
439 | case BT_DEV_TYPE_MMC: | 439 | case BT_DEV_TYPE_MMC: |
440 | boot_dev = boot_instance + MMC1_BOOT; | 440 | boot_dev = boot_instance + MMC1_BOOT; |
441 | break; | 441 | break; |
442 | case BT_DEV_TYPE_NAND: | 442 | case BT_DEV_TYPE_NAND: |
443 | boot_dev = NAND_BOOT; | 443 | boot_dev = NAND_BOOT; |
444 | break; | 444 | break; |
445 | case BT_DEV_TYPE_FLEXSPINOR: | 445 | case BT_DEV_TYPE_FLEXSPINOR: |
446 | boot_dev = QSPI_BOOT; | 446 | boot_dev = QSPI_BOOT; |
447 | break; | 447 | break; |
448 | case BT_DEV_TYPE_USB: | 448 | case BT_DEV_TYPE_USB: |
449 | boot_dev = USB_BOOT; | 449 | boot_dev = USB_BOOT; |
450 | break; | 450 | break; |
451 | default: | 451 | default: |
452 | break; | 452 | break; |
453 | } | 453 | } |
454 | 454 | ||
455 | return boot_dev; | 455 | return boot_dev; |
456 | } | 456 | } |
457 | #endif | 457 | #endif |
458 | 458 | ||
459 | bool is_usb_boot(void) | 459 | bool is_usb_boot(void) |
460 | { | 460 | { |
461 | return get_boot_device() == USB_BOOT; | 461 | return get_boot_device() == USB_BOOT; |
462 | } | 462 | } |
463 | #ifdef CONFIG_SERIAL_TAG | 463 | #ifdef CONFIG_SERIAL_TAG |
464 | void get_board_serial(struct tag_serialnr *serialnr) | 464 | void get_board_serial(struct tag_serialnr *serialnr) |
465 | { | 465 | { |
466 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | 466 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; |
467 | struct fuse_bank *bank = &ocotp->bank[0]; | 467 | struct fuse_bank *bank = &ocotp->bank[0]; |
468 | struct fuse_bank0_regs *fuse = | 468 | struct fuse_bank0_regs *fuse = |
469 | (struct fuse_bank0_regs *)bank->fuse_regs; | 469 | (struct fuse_bank0_regs *)bank->fuse_regs; |
470 | 470 | ||
471 | serialnr->low = fuse->uid_low; | 471 | serialnr->low = fuse->uid_low; |
472 | serialnr->high = fuse->uid_high; | 472 | serialnr->high = fuse->uid_high; |
473 | } | 473 | } |
474 | #endif | 474 | #endif |
475 | 475 | ||
476 | #ifdef CONFIG_OF_SYSTEM_SETUP | 476 | #ifdef CONFIG_OF_SYSTEM_SETUP |
477 | static int ft_add_optee_node(void *fdt, bd_t *bd) | 477 | static int ft_add_optee_node(void *fdt, bd_t *bd) |
478 | { | 478 | { |
479 | const char *path, *subpath; | 479 | const char *path, *subpath; |
480 | int offs; | 480 | int offs; |
481 | 481 | ||
482 | /* | 482 | /* |
483 | * No TEE space allocated indicating no TEE running, so no | 483 | * No TEE space allocated indicating no TEE running, so no |
484 | * need to add optee node in dts | 484 | * need to add optee node in dts |
485 | */ | 485 | */ |
486 | if (!rom_pointer[1]) | 486 | if (!rom_pointer[1]) |
487 | return 0; | 487 | return 0; |
488 | 488 | ||
489 | offs = fdt_increase_size(fdt, 512); | 489 | offs = fdt_increase_size(fdt, 512); |
490 | if (offs) { | 490 | if (offs) { |
491 | printf("No Space for dtb\n"); | 491 | printf("No Space for dtb\n"); |
492 | return 1; | 492 | return 1; |
493 | } | 493 | } |
494 | 494 | ||
495 | path = "/firmware"; | 495 | path = "/firmware"; |
496 | offs = fdt_path_offset(fdt, path); | 496 | offs = fdt_path_offset(fdt, path); |
497 | if (offs < 0) { | 497 | if (offs < 0) { |
498 | path = "/"; | 498 | path = "/"; |
499 | offs = fdt_path_offset(fdt, path); | 499 | offs = fdt_path_offset(fdt, path); |
500 | 500 | ||
501 | if (offs < 0) { | 501 | if (offs < 0) { |
502 | printf("Could not find root node.\n"); | 502 | printf("Could not find root node.\n"); |
503 | return 1; | 503 | return 1; |
504 | } | 504 | } |
505 | 505 | ||
506 | subpath = "firmware"; | 506 | subpath = "firmware"; |
507 | offs = fdt_add_subnode(fdt, offs, subpath); | 507 | offs = fdt_add_subnode(fdt, offs, subpath); |
508 | if (offs < 0) { | 508 | if (offs < 0) { |
509 | printf("Could not create %s node.\n", subpath); | 509 | printf("Could not create %s node.\n", subpath); |
510 | } | 510 | } |
511 | } | 511 | } |
512 | 512 | ||
513 | subpath = "optee"; | 513 | subpath = "optee"; |
514 | offs = fdt_add_subnode(fdt, offs, subpath); | 514 | offs = fdt_add_subnode(fdt, offs, subpath); |
515 | if (offs < 0) { | 515 | if (offs < 0) { |
516 | printf("Could not create %s node.\n", subpath); | 516 | printf("Could not create %s node.\n", subpath); |
517 | } | 517 | } |
518 | 518 | ||
519 | fdt_setprop_string(fdt, offs, "compatible", "linaro,optee-tz"); | 519 | fdt_setprop_string(fdt, offs, "compatible", "linaro,optee-tz"); |
520 | fdt_setprop_string(fdt, offs, "method", "smc"); | 520 | fdt_setprop_string(fdt, offs, "method", "smc"); |
521 | 521 | ||
522 | return 0; | 522 | return 0; |
523 | } | 523 | } |
524 | 524 | ||
525 | static int disable_fdt_nodes(void *blob, const char *nodes_path[], int size_array) | 525 | static int disable_fdt_nodes(void *blob, const char *nodes_path[], int size_array) |
526 | { | 526 | { |
527 | int i = 0; | 527 | int i = 0; |
528 | int rc; | 528 | int rc; |
529 | int nodeoff; | 529 | int nodeoff; |
530 | const char *status = "disabled"; | 530 | const char *status = "disabled"; |
531 | 531 | ||
532 | for (i = 0; i < size_array; i++) { | 532 | for (i = 0; i < size_array; i++) { |
533 | nodeoff = fdt_path_offset(blob, nodes_path[i]); | 533 | nodeoff = fdt_path_offset(blob, nodes_path[i]); |
534 | if (nodeoff < 0) | 534 | if (nodeoff < 0) |
535 | continue; /* Not found, skip it */ | 535 | continue; /* Not found, skip it */ |
536 | 536 | ||
537 | printf("Found %s node\n", nodes_path[i]); | 537 | printf("Found %s node\n", nodes_path[i]); |
538 | 538 | ||
539 | add_status: | 539 | add_status: |
540 | rc = fdt_setprop(blob, nodeoff, "status", status, strlen(status) + 1); | 540 | rc = fdt_setprop(blob, nodeoff, "status", status, strlen(status) + 1); |
541 | if (rc) { | 541 | if (rc) { |
542 | if (rc == -FDT_ERR_NOSPACE) { | 542 | if (rc == -FDT_ERR_NOSPACE) { |
543 | rc = fdt_increase_size(blob, 512); | 543 | rc = fdt_increase_size(blob, 512); |
544 | if (!rc) | 544 | if (!rc) |
545 | goto add_status; | 545 | goto add_status; |
546 | } | 546 | } |
547 | printf("Unable to update property %s:%s, err=%s\n", | 547 | printf("Unable to update property %s:%s, err=%s\n", |
548 | nodes_path[i], "status", fdt_strerror(rc)); | 548 | nodes_path[i], "status", fdt_strerror(rc)); |
549 | } else { | 549 | } else { |
550 | printf("Modify %s:%s disabled\n", | 550 | printf("Modify %s:%s disabled\n", |
551 | nodes_path[i], "status"); | 551 | nodes_path[i], "status"); |
552 | } | 552 | } |
553 | } | 553 | } |
554 | 554 | ||
555 | return 0; | 555 | return 0; |
556 | } | 556 | } |
557 | 557 | ||
558 | #ifdef CONFIG_IMX8MQ | 558 | #ifdef CONFIG_IMX8MQ |
559 | bool check_dcss_fused(void) | 559 | bool check_dcss_fused(void) |
560 | { | 560 | { |
561 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | 561 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; |
562 | struct fuse_bank *bank = &ocotp->bank[1]; | 562 | struct fuse_bank *bank = &ocotp->bank[1]; |
563 | struct fuse_bank1_regs *fuse = | 563 | struct fuse_bank1_regs *fuse = |
564 | (struct fuse_bank1_regs *)bank->fuse_regs; | 564 | (struct fuse_bank1_regs *)bank->fuse_regs; |
565 | 565 | ||
566 | u32 value = readl(&fuse->tester4); | 566 | u32 value = readl(&fuse->tester4); |
567 | if (value & 0x4000000) | 567 | if (value & 0x4000000) |
568 | return true; | 568 | return true; |
569 | 569 | ||
570 | return false; | 570 | return false; |
571 | } | 571 | } |
572 | 572 | ||
573 | static int disable_mipi_dsi_nodes(void *blob) | 573 | static int disable_mipi_dsi_nodes(void *blob) |
574 | { | 574 | { |
575 | const char *nodes_path[] = { | 575 | const char *nodes_path[] = { |
576 | "/mipi_dsi@30A00000", | 576 | "/mipi_dsi@30A00000", |
577 | "/mipi_dsi_bridge@30A00000", | 577 | "/mipi_dsi_bridge@30A00000", |
578 | "/dsi_phy@30A00300" | 578 | "/dsi_phy@30A00300" |
579 | }; | 579 | }; |
580 | 580 | ||
581 | return disable_fdt_nodes(blob, nodes_path, ARRAY_SIZE(nodes_path)); | 581 | return disable_fdt_nodes(blob, nodes_path, ARRAY_SIZE(nodes_path)); |
582 | } | 582 | } |
583 | 583 | ||
584 | static int disable_dcss_nodes(void *blob) | 584 | static int disable_dcss_nodes(void *blob) |
585 | { | 585 | { |
586 | const char *nodes_path[] = { | 586 | const char *nodes_path[] = { |
587 | "/dcss@0x32e00000", | 587 | "/dcss@0x32e00000", |
588 | "/dcss@32e00000", | 588 | "/dcss@32e00000", |
589 | "/hdmi@32c00000", | 589 | "/hdmi@32c00000", |
590 | "/hdmi_cec@32c33800", | 590 | "/hdmi_cec@32c33800", |
591 | "/hdmi_drm@32c00000", | 591 | "/hdmi_drm@32c00000", |
592 | "/display-subsystem", | 592 | "/display-subsystem", |
593 | "/sound-hdmi", | 593 | "/sound-hdmi", |
594 | "/sound-hdmi-arc" | 594 | "/sound-hdmi-arc" |
595 | }; | 595 | }; |
596 | 596 | ||
597 | return disable_fdt_nodes(blob, nodes_path, ARRAY_SIZE(nodes_path)); | 597 | return disable_fdt_nodes(blob, nodes_path, ARRAY_SIZE(nodes_path)); |
598 | } | 598 | } |
599 | 599 | ||
600 | static int check_mipi_dsi_nodes(void *blob) | 600 | static int check_mipi_dsi_nodes(void *blob) |
601 | { | 601 | { |
602 | const char *lcdif_path = "/lcdif@30320000"; | 602 | const char *lcdif_path = "/lcdif@30320000"; |
603 | const char *mipi_dsi_path = "/mipi_dsi@30A00000"; | 603 | const char *mipi_dsi_path = "/mipi_dsi@30A00000"; |
604 | 604 | ||
605 | const char *lcdif_ep_path = "/lcdif@30320000/port@0/mipi-dsi-endpoint"; | 605 | const char *lcdif_ep_path = "/lcdif@30320000/port@0/mipi-dsi-endpoint"; |
606 | const char *mipi_dsi_ep_path = "/mipi_dsi@30A00000/port@1/endpoint"; | 606 | const char *mipi_dsi_ep_path = "/mipi_dsi@30A00000/port@1/endpoint"; |
607 | 607 | ||
608 | int nodeoff; | 608 | int nodeoff; |
609 | nodeoff = fdt_path_offset(blob, lcdif_path); | 609 | nodeoff = fdt_path_offset(blob, lcdif_path); |
610 | if (nodeoff < 0 || !fdtdec_get_is_enabled(blob, nodeoff)) { | 610 | if (nodeoff < 0 || !fdtdec_get_is_enabled(blob, nodeoff)) { |
611 | /* If can't find lcdif node or lcdif node is disabled, then disable all mipi dsi, | 611 | /* If can't find lcdif node or lcdif node is disabled, then disable all mipi dsi, |
612 | since they only can input from DCSS */ | 612 | since they only can input from DCSS */ |
613 | return disable_mipi_dsi_nodes(blob); | 613 | return disable_mipi_dsi_nodes(blob); |
614 | } | 614 | } |
615 | 615 | ||
616 | nodeoff = fdt_path_offset(blob, mipi_dsi_path); | 616 | nodeoff = fdt_path_offset(blob, mipi_dsi_path); |
617 | if (nodeoff < 0 || !fdtdec_get_is_enabled(blob, nodeoff)) | 617 | if (nodeoff < 0 || !fdtdec_get_is_enabled(blob, nodeoff)) |
618 | return 0; | 618 | return 0; |
619 | 619 | ||
620 | nodeoff = fdt_path_offset(blob, lcdif_ep_path); | 620 | nodeoff = fdt_path_offset(blob, lcdif_ep_path); |
621 | if (nodeoff < 0) { | 621 | if (nodeoff < 0) { |
622 | /* If can't find lcdif endpoint, then disable all mipi dsi, | 622 | /* If can't find lcdif endpoint, then disable all mipi dsi, |
623 | since they only can input from DCSS */ | 623 | since they only can input from DCSS */ |
624 | return disable_mipi_dsi_nodes(blob); | 624 | return disable_mipi_dsi_nodes(blob); |
625 | } else { | 625 | } else { |
626 | int lookup_node; | 626 | int lookup_node; |
627 | lookup_node = fdtdec_lookup_phandle(blob, nodeoff, "remote-endpoint"); | 627 | lookup_node = fdtdec_lookup_phandle(blob, nodeoff, "remote-endpoint"); |
628 | nodeoff = fdt_path_offset(blob, mipi_dsi_ep_path); | 628 | nodeoff = fdt_path_offset(blob, mipi_dsi_ep_path); |
629 | 629 | ||
630 | if (nodeoff >0 && nodeoff == lookup_node) | 630 | if (nodeoff >0 && nodeoff == lookup_node) |
631 | return 0; | 631 | return 0; |
632 | 632 | ||
633 | return disable_mipi_dsi_nodes(blob); | 633 | return disable_mipi_dsi_nodes(blob); |
634 | } | 634 | } |
635 | 635 | ||
636 | } | 636 | } |
637 | 637 | ||
638 | void board_quiesce_devices(void) | 638 | void board_quiesce_devices(void) |
639 | { | 639 | { |
640 | #ifdef CONFIG_USB_DWC3 | 640 | #ifdef CONFIG_USB_DWC3 |
641 | if (is_usb_boot()) | 641 | if (is_usb_boot()) |
642 | disconnect_from_pc(); | 642 | disconnect_from_pc(); |
643 | #endif | 643 | #endif |
644 | } | 644 | } |
645 | #endif | 645 | #endif |
646 | 646 | ||
647 | int disable_vpu_nodes(void *blob) | 647 | int disable_vpu_nodes(void *blob) |
648 | { | 648 | { |
649 | const char *nodes_path_8mq[] = { | 649 | const char *nodes_path_8mq[] = { |
650 | "/vpu@38300000" | 650 | "/vpu@38300000" |
651 | }; | 651 | }; |
652 | 652 | ||
653 | const char *nodes_path_8mm[] = { | 653 | const char *nodes_path_8mm[] = { |
654 | "/vpu_g1@38300000", | 654 | "/vpu_g1@38300000", |
655 | "/vpu_g2@38310000", | 655 | "/vpu_g2@38310000", |
656 | "/vpu_h1@38320000" | 656 | "/vpu_h1@38320000" |
657 | }; | 657 | }; |
658 | 658 | ||
659 | if (is_imx8mq()) | 659 | if (is_imx8mq()) |
660 | return disable_fdt_nodes(blob, nodes_path_8mq, ARRAY_SIZE(nodes_path_8mq)); | 660 | return disable_fdt_nodes(blob, nodes_path_8mq, ARRAY_SIZE(nodes_path_8mq)); |
661 | else if (is_imx8mm()) | 661 | else if (is_imx8mm()) |
662 | return disable_fdt_nodes(blob, nodes_path_8mm, ARRAY_SIZE(nodes_path_8mm)); | 662 | return disable_fdt_nodes(blob, nodes_path_8mm, ARRAY_SIZE(nodes_path_8mm)); |
663 | else | 663 | else |
664 | return -EPERM; | 664 | return -EPERM; |
665 | 665 | ||
666 | } | 666 | } |
667 | 667 | ||
668 | int disable_gpu_nodes(void *blob) | 668 | int disable_gpu_nodes(void *blob) |
669 | { | 669 | { |
670 | const char *nodes_path_8mn[] = { | 670 | const char *nodes_path_8mn[] = { |
671 | "/gpu@38000000" | 671 | "/gpu@38000000" |
672 | }; | 672 | }; |
673 | 673 | ||
674 | return disable_fdt_nodes(blob, nodes_path_8mn, ARRAY_SIZE(nodes_path_8mn)); | 674 | return disable_fdt_nodes(blob, nodes_path_8mn, ARRAY_SIZE(nodes_path_8mn)); |
675 | } | 675 | } |
676 | 676 | ||
677 | int disable_cpu_nodes(void *blob, u32 disabled_cores) | 677 | int disable_cpu_nodes(void *blob, u32 disabled_cores) |
678 | { | 678 | { |
679 | const char *nodes_path[] = { | 679 | const char *nodes_path[] = { |
680 | "/cpus/cpu@1", | 680 | "/cpus/cpu@1", |
681 | "/cpus/cpu@2", | 681 | "/cpus/cpu@2", |
682 | "/cpus/cpu@3", | 682 | "/cpus/cpu@3", |
683 | }; | 683 | }; |
684 | 684 | ||
685 | u32 i = 0; | 685 | u32 i = 0; |
686 | int rc; | 686 | int rc; |
687 | int nodeoff; | 687 | int nodeoff; |
688 | 688 | ||
689 | if (disabled_cores > 3) | 689 | if (disabled_cores > 3) |
690 | return -EINVAL; | 690 | return -EINVAL; |
691 | 691 | ||
692 | i = 3 - disabled_cores; | 692 | i = 3 - disabled_cores; |
693 | 693 | ||
694 | for (; i < 3; i++) { | 694 | for (; i < 3; i++) { |
695 | nodeoff = fdt_path_offset(blob, nodes_path[i]); | 695 | nodeoff = fdt_path_offset(blob, nodes_path[i]); |
696 | if (nodeoff < 0) | 696 | if (nodeoff < 0) |
697 | continue; /* Not found, skip it */ | 697 | continue; /* Not found, skip it */ |
698 | 698 | ||
699 | printf("Found %s node\n", nodes_path[i]); | 699 | printf("Found %s node\n", nodes_path[i]); |
700 | 700 | ||
701 | rc = fdt_del_node(blob, nodeoff); | 701 | rc = fdt_del_node(blob, nodeoff); |
702 | if (rc < 0) { | 702 | if (rc < 0) { |
703 | printf("Unable to delete node %s, err=%s\n", | 703 | printf("Unable to delete node %s, err=%s\n", |
704 | nodes_path[i], fdt_strerror(rc)); | 704 | nodes_path[i], fdt_strerror(rc)); |
705 | } else { | 705 | } else { |
706 | printf("Delete node %s\n", nodes_path[i]); | 706 | printf("Delete node %s\n", nodes_path[i]); |
707 | } | 707 | } |
708 | } | 708 | } |
709 | 709 | ||
710 | return 0; | 710 | return 0; |
711 | } | 711 | } |
712 | 712 | ||
713 | int ft_system_setup(void *blob, bd_t *bd) | 713 | int ft_system_setup(void *blob, bd_t *bd) |
714 | { | 714 | { |
715 | #ifdef CONFIG_IMX8MQ | 715 | #ifdef CONFIG_IMX8MQ |
716 | int i = 0; | 716 | int i = 0; |
717 | int rc; | 717 | int rc; |
718 | int nodeoff; | 718 | int nodeoff; |
719 | 719 | ||
720 | if (get_boot_device() == USB_BOOT) { | 720 | if (get_boot_device() == USB_BOOT) { |
721 | 721 | ||
722 | disable_dcss_nodes(blob); | 722 | disable_dcss_nodes(blob); |
723 | 723 | ||
724 | const char *usb_dwc3_path = "/usb@38100000/dwc3"; | 724 | const char *usb_dwc3_path = "/usb@38100000/dwc3"; |
725 | nodeoff = fdt_path_offset(blob, usb_dwc3_path); | 725 | nodeoff = fdt_path_offset(blob, usb_dwc3_path); |
726 | if (nodeoff >= 0) { | 726 | if (nodeoff >= 0) { |
727 | const char *speed = "high-speed"; | 727 | const char *speed = "high-speed"; |
728 | printf("Found %s node\n", usb_dwc3_path); | 728 | printf("Found %s node\n", usb_dwc3_path); |
729 | 729 | ||
730 | usb_modify_speed: | 730 | usb_modify_speed: |
731 | 731 | ||
732 | rc = fdt_setprop(blob, nodeoff, "maximum-speed", speed, strlen(speed) + 1); | 732 | rc = fdt_setprop(blob, nodeoff, "maximum-speed", speed, strlen(speed) + 1); |
733 | if (rc) { | 733 | if (rc) { |
734 | if (rc == -FDT_ERR_NOSPACE) { | 734 | if (rc == -FDT_ERR_NOSPACE) { |
735 | rc = fdt_increase_size(blob, 512); | 735 | rc = fdt_increase_size(blob, 512); |
736 | if (!rc) | 736 | if (!rc) |
737 | goto usb_modify_speed; | 737 | goto usb_modify_speed; |
738 | } | 738 | } |
739 | printf("Unable to set property %s:%s, err=%s\n", | 739 | printf("Unable to set property %s:%s, err=%s\n", |
740 | usb_dwc3_path, "maximum-speed", fdt_strerror(rc)); | 740 | usb_dwc3_path, "maximum-speed", fdt_strerror(rc)); |
741 | } else { | 741 | } else { |
742 | printf("Modify %s:%s = %s\n", | 742 | printf("Modify %s:%s = %s\n", |
743 | usb_dwc3_path, "maximum-speed", speed); | 743 | usb_dwc3_path, "maximum-speed", speed); |
744 | } | 744 | } |
745 | }else { | 745 | }else { |
746 | printf("Can't found %s node\n", usb_dwc3_path); | 746 | printf("Can't found %s node\n", usb_dwc3_path); |
747 | } | 747 | } |
748 | } | 748 | } |
749 | 749 | ||
750 | /* Disable the CPU idle for A0 chip since the HW does not support it */ | 750 | /* Disable the CPU idle for A0 chip since the HW does not support it */ |
751 | if (is_soc_rev(CHIP_REV_1_0)) { | 751 | if (is_soc_rev(CHIP_REV_1_0)) { |
752 | static const char * const nodes_path[] = { | 752 | static const char * const nodes_path[] = { |
753 | "/cpus/cpu@0", | 753 | "/cpus/cpu@0", |
754 | "/cpus/cpu@1", | 754 | "/cpus/cpu@1", |
755 | "/cpus/cpu@2", | 755 | "/cpus/cpu@2", |
756 | "/cpus/cpu@3", | 756 | "/cpus/cpu@3", |
757 | }; | 757 | }; |
758 | 758 | ||
759 | for (i = 0; i < ARRAY_SIZE(nodes_path); i++) { | 759 | for (i = 0; i < ARRAY_SIZE(nodes_path); i++) { |
760 | nodeoff = fdt_path_offset(blob, nodes_path[i]); | 760 | nodeoff = fdt_path_offset(blob, nodes_path[i]); |
761 | if (nodeoff < 0) | 761 | if (nodeoff < 0) |
762 | continue; /* Not found, skip it */ | 762 | continue; /* Not found, skip it */ |
763 | 763 | ||
764 | printf("Found %s node\n", nodes_path[i]); | 764 | printf("Found %s node\n", nodes_path[i]); |
765 | 765 | ||
766 | rc = fdt_delprop(blob, nodeoff, "cpu-idle-states"); | 766 | rc = fdt_delprop(blob, nodeoff, "cpu-idle-states"); |
767 | if (rc) { | 767 | if (rc) { |
768 | printf("Unable to update property %s:%s, err=%s\n", | 768 | printf("Unable to update property %s:%s, err=%s\n", |
769 | nodes_path[i], "status", fdt_strerror(rc)); | 769 | nodes_path[i], "status", fdt_strerror(rc)); |
770 | return rc; | 770 | return rc; |
771 | } | 771 | } |
772 | 772 | ||
773 | printf("Remove %s:%s\n", nodes_path[i], | 773 | printf("Remove %s:%s\n", nodes_path[i], |
774 | "cpu-idle-states"); | 774 | "cpu-idle-states"); |
775 | } | 775 | } |
776 | } | 776 | } |
777 | 777 | ||
778 | if (is_imx8mql()) { | 778 | if (is_imx8mql()) { |
779 | disable_vpu_nodes(blob); | 779 | disable_vpu_nodes(blob); |
780 | if (check_dcss_fused()) { | 780 | if (check_dcss_fused()) { |
781 | printf("DCSS is fused\n"); | 781 | printf("DCSS is fused\n"); |
782 | disable_dcss_nodes(blob); | 782 | disable_dcss_nodes(blob); |
783 | check_mipi_dsi_nodes(blob); | 783 | check_mipi_dsi_nodes(blob); |
784 | } | 784 | } |
785 | } | 785 | } |
786 | 786 | ||
787 | if (is_imx8md()) | 787 | if (is_imx8md()) |
788 | disable_cpu_nodes(blob, 2); | 788 | disable_cpu_nodes(blob, 2); |
789 | 789 | ||
790 | #elif defined(CONFIG_IMX8MM) | 790 | #elif defined(CONFIG_IMX8MM) |
791 | if (is_imx8mml() || is_imx8mmdl() || is_imx8mmsl()) | 791 | if (is_imx8mml() || is_imx8mmdl() || is_imx8mmsl()) |
792 | disable_vpu_nodes(blob); | 792 | disable_vpu_nodes(blob); |
793 | 793 | ||
794 | if (is_imx8mmd() || is_imx8mmdl()) | 794 | if (is_imx8mmd() || is_imx8mmdl()) |
795 | disable_cpu_nodes(blob, 2); | 795 | disable_cpu_nodes(blob, 2); |
796 | else if (is_imx8mms() || is_imx8mmsl()) | 796 | else if (is_imx8mms() || is_imx8mmsl()) |
797 | disable_cpu_nodes(blob, 3); | 797 | disable_cpu_nodes(blob, 3); |
798 | 798 | ||
799 | #elif defined(CONFIG_IMX8MN) | 799 | #elif defined(CONFIG_IMX8MN) |
800 | if (is_imx8mnl() || is_imx8mndl() || is_imx8mnsl()) | 800 | if (is_imx8mnl() || is_imx8mndl() || is_imx8mnsl()) |
801 | disable_gpu_nodes(blob); | 801 | disable_gpu_nodes(blob); |
802 | 802 | ||
803 | if (is_imx8mnd() || is_imx8mndl()) | 803 | if (is_imx8mnd() || is_imx8mndl()) |
804 | disable_cpu_nodes(blob, 2); | 804 | disable_cpu_nodes(blob, 2); |
805 | else if (is_imx8mns() || is_imx8mnsl()) | 805 | else if (is_imx8mns() || is_imx8mnsl()) |
806 | disable_cpu_nodes(blob, 3); | 806 | disable_cpu_nodes(blob, 3); |
807 | 807 | ||
808 | #ifdef CONFIG_IMX8MN_FORCE_NOM_SOC | 808 | #ifdef CONFIG_IMX8MN_FORCE_NOM_SOC |
809 | /* Disable the DVFS by removing 1.4Ghz and 1.5Ghz operating-points*/ | 809 | /* Disable the DVFS by removing 1.4Ghz and 1.5Ghz operating-points*/ |
810 | int rc; | 810 | int rc; |
811 | int nodeoff; | 811 | int nodeoff; |
812 | static const char * const nodes_path = "/cpus/cpu@0"; | 812 | static const char * const nodes_path = "/cpus/cpu@0"; |
813 | u32 val[] = {1200000, 850000}; | 813 | u32 val[] = {1200000, 850000}; |
814 | 814 | ||
815 | nodeoff = fdt_path_offset(blob, nodes_path); | 815 | nodeoff = fdt_path_offset(blob, nodes_path); |
816 | if (nodeoff < 0) { | 816 | if (nodeoff < 0) { |
817 | printf("Unable to find node %s, err=%s\n", | 817 | printf("Unable to find node %s, err=%s\n", |
818 | nodes_path, fdt_strerror(nodeoff)); | 818 | nodes_path, fdt_strerror(nodeoff)); |
819 | return nodeoff; | 819 | return nodeoff; |
820 | } | 820 | } |
821 | 821 | ||
822 | printf("Found %s node\n", nodes_path); | 822 | printf("Found %s node\n", nodes_path); |
823 | 823 | ||
824 | val[0] = cpu_to_fdt32(val[0]); | 824 | val[0] = cpu_to_fdt32(val[0]); |
825 | val[1] = cpu_to_fdt32(val[1]); | 825 | val[1] = cpu_to_fdt32(val[1]); |
826 | rc = fdt_setprop(blob, nodeoff, "operating-points", &val, 2 * sizeof(u32)); | 826 | rc = fdt_setprop(blob, nodeoff, "operating-points", &val, 2 * sizeof(u32)); |
827 | if (rc) { | 827 | if (rc) { |
828 | printf("Unable to update operating-points for node %s, err=%s\n", | 828 | printf("Unable to update operating-points for node %s, err=%s\n", |
829 | nodes_path, fdt_strerror(rc)); | 829 | nodes_path, fdt_strerror(rc)); |
830 | return rc; | 830 | return rc; |
831 | } | 831 | } |
832 | 832 | ||
833 | printf("Update %s:%s\n", nodes_path, | 833 | printf("Update %s:%s\n", nodes_path, |
834 | "operating-points"); | 834 | "operating-points"); |
835 | 835 | ||
836 | #endif /* CONFIG_IMX8MN_FORCE_NOM_SOC */ | 836 | #endif /* CONFIG_IMX8MN_FORCE_NOM_SOC */ |
837 | 837 | ||
838 | #endif | 838 | #endif |
839 | 839 | ||
840 | return ft_add_optee_node(blob, bd); | 840 | return ft_add_optee_node(blob, bd); |
841 | } | 841 | } |
842 | #endif | 842 | #endif |
843 | 843 | ||
844 | void reset_cpu(ulong addr) | 844 | void reset_cpu(ulong addr) |
845 | { | 845 | { |
846 | struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR; | 846 | struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR; |
847 | 847 | ||
848 | /* Clear WDA to trigger WDOG_B immediately */ | 848 | /* Clear WDA to trigger WDOG_B immediately */ |
849 | writew((WCR_WDE | WCR_SRS), &wdog->wcr); | 849 | writew((WCR_WDE | WCR_SRS), &wdog->wcr); |
850 | 850 | ||
851 | while (1) { | 851 | while (1) { |
852 | /* | 852 | /* |
853 | * spin for .5 seconds before reset | 853 | * spin for .5 seconds before reset |
854 | */ | 854 | */ |
855 | } | 855 | } |
856 | } | 856 | } |
857 | 857 | ||
858 | #if defined(CONFIG_ARCH_MISC_INIT) | 858 | #if defined(CONFIG_ARCH_MISC_INIT) |
859 | #define FSL_SIP_BUILDINFO 0xC2000003 | 859 | #define FSL_SIP_BUILDINFO 0xC2000003 |
860 | #define FSL_SIP_BUILDINFO_GET_COMMITHASH 0x00 | 860 | #define FSL_SIP_BUILDINFO_GET_COMMITHASH 0x00 |
861 | static void acquire_buildinfo(void) | 861 | static void acquire_buildinfo(void) |
862 | { | 862 | { |
863 | uint64_t atf_commit = 0; | 863 | uint64_t atf_commit = 0; |
864 | 864 | ||
865 | /* Get ARM Trusted Firmware commit id */ | 865 | /* Get ARM Trusted Firmware commit id */ |
866 | atf_commit = call_imx_sip(FSL_SIP_BUILDINFO, | 866 | atf_commit = call_imx_sip(FSL_SIP_BUILDINFO, |
867 | FSL_SIP_BUILDINFO_GET_COMMITHASH, 0, 0, 0); | 867 | FSL_SIP_BUILDINFO_GET_COMMITHASH, 0, 0, 0); |
868 | if (atf_commit == 0xffffffff) { | 868 | if (atf_commit == 0xffffffff) { |
869 | debug("ATF does not support build info\n"); | 869 | debug("ATF does not support build info\n"); |
870 | atf_commit = 0x30; /* Display 0, 0 ascii is 0x30 */ | 870 | atf_commit = 0x30; /* Display 0, 0 ascii is 0x30 */ |
871 | } | 871 | } |
872 | 872 | ||
873 | printf("\n BuildInfo:\n - ATF %s\n - %s\n\n", (char *)&atf_commit, | 873 | printf("\n BuildInfo:\n - ATF %s\n - %s\n\n", (char *)&atf_commit, |
874 | U_BOOT_VERSION); | 874 | U_BOOT_VERSION); |
875 | } | 875 | } |
876 | 876 | ||
877 | int arch_misc_init(void) | 877 | int arch_misc_init(void) |
878 | { | 878 | { |
879 | acquire_buildinfo(); | 879 | acquire_buildinfo(); |
880 | 880 | ||
881 | return 0; | 881 | return 0; |
882 | } | 882 | } |
883 | #endif | 883 | #endif |
884 | 884 | ||
885 | #define FSL_SIP_GPC 0xC2000000 | 885 | #define FSL_SIP_GPC 0xC2000000 |
886 | #define FSL_SIP_CONFIG_GPC_PM_DOMAIN 0x03 | 886 | #define FSL_SIP_CONFIG_GPC_PM_DOMAIN 0x03 |
887 | 887 | ||
888 | #ifdef CONFIG_SPL_BUILD | 888 | #ifdef CONFIG_SPL_BUILD |
889 | static uint32_t gpc_pu_m_core_offset[11] = { | 889 | static uint32_t gpc_pu_m_core_offset[11] = { |
890 | 0xc00, 0xc40, 0xc80, 0xcc0, | 890 | 0xc00, 0xc40, 0xc80, 0xcc0, |
891 | 0xdc0, 0xe00, 0xe40, 0xe80, | 891 | 0xdc0, 0xe00, 0xe40, 0xe80, |
892 | 0xec0, 0xf00, 0xf40, | 892 | 0xec0, 0xf00, 0xf40, |
893 | }; | 893 | }; |
894 | 894 | ||
895 | #define PGC_PCR 0 | 895 | #define PGC_PCR 0 |
896 | 896 | ||
897 | void imx_gpc_set_m_core_pgc(unsigned int offset, bool pdn) | 897 | void imx_gpc_set_m_core_pgc(unsigned int offset, bool pdn) |
898 | { | 898 | { |
899 | uint32_t val; | 899 | uint32_t val; |
900 | uintptr_t reg = GPC_BASE_ADDR + offset; | 900 | uintptr_t reg = GPC_BASE_ADDR + offset; |
901 | 901 | ||
902 | val = readl(reg); | 902 | val = readl(reg); |
903 | val &= ~(0x1 << PGC_PCR); | 903 | val &= ~(0x1 << PGC_PCR); |
904 | 904 | ||
905 | if(pdn) | 905 | if(pdn) |
906 | val |= 0x1 << PGC_PCR; | 906 | val |= 0x1 << PGC_PCR; |
907 | writel(val, reg); | 907 | writel(val, reg); |
908 | } | 908 | } |
909 | 909 | ||
910 | void imx8m_usb_power_domain(uint32_t domain_id, bool on) | 910 | void imx8m_usb_power_domain(uint32_t domain_id, bool on) |
911 | { | 911 | { |
912 | uint32_t val; | 912 | uint32_t val; |
913 | uintptr_t reg; | 913 | uintptr_t reg; |
914 | 914 | ||
915 | imx_gpc_set_m_core_pgc(gpc_pu_m_core_offset[domain_id], true); | 915 | imx_gpc_set_m_core_pgc(gpc_pu_m_core_offset[domain_id], true); |
916 | 916 | ||
917 | reg = GPC_BASE_ADDR + (on ? 0xf8 : 0x104); | 917 | reg = GPC_BASE_ADDR + (on ? 0xf8 : 0x104); |
918 | val = 1 << (domain_id > 3 ? (domain_id + 3) : domain_id); | 918 | val = 1 << (domain_id > 3 ? (domain_id + 3) : domain_id); |
919 | writel(val, reg); | 919 | writel(val, reg); |
920 | while (readl(reg) & val) | 920 | while (readl(reg) & val) |
921 | ; | 921 | ; |
922 | imx_gpc_set_m_core_pgc(gpc_pu_m_core_offset[domain_id], false); | 922 | imx_gpc_set_m_core_pgc(gpc_pu_m_core_offset[domain_id], false); |
923 | } | 923 | } |
924 | #endif | 924 | #endif |
925 | 925 | ||
926 | int imx8m_usb_power(int usb_id, bool on) | 926 | int imx8m_usb_power(int usb_id, bool on) |
927 | { | 927 | { |
928 | if (usb_id > 1) | 928 | if (usb_id > 1) |
929 | return -EINVAL; | 929 | return -EINVAL; |
930 | #ifdef CONFIG_SPL_BUILD | 930 | #ifdef CONFIG_SPL_BUILD |
931 | imx8m_usb_power_domain(2 + usb_id, on); | 931 | imx8m_usb_power_domain(2 + usb_id, on); |
932 | #else | 932 | #else |
933 | if (call_imx_sip(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN, | 933 | if (call_imx_sip(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN, |
934 | 2 + usb_id, on, 0)) | 934 | 2 + usb_id, on, 0)) |
935 | return -EPERM; | 935 | return -EPERM; |
936 | #endif | 936 | #endif |
937 | return 0; | 937 | return 0; |
938 | } | 938 | } |
939 | 939 | ||
940 | void nxp_tmu_arch_init(void *reg_base) | 940 | void nxp_tmu_arch_init(void *reg_base) |
941 | { | 941 | { |
942 | if (is_imx8mm() || is_imx8mn()) { | 942 | if (is_imx8mm() || is_imx8mn()) { |
943 | /* Load TCALIV and TASR from fuses */ | 943 | /* Load TCALIV and TASR from fuses */ |
944 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; | 944 | struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR; |
945 | struct fuse_bank *bank = &ocotp->bank[3]; | 945 | struct fuse_bank *bank = &ocotp->bank[3]; |
946 | struct fuse_bank3_regs *fuse = | 946 | struct fuse_bank3_regs *fuse = |
947 | (struct fuse_bank3_regs *)bank->fuse_regs; | 947 | (struct fuse_bank3_regs *)bank->fuse_regs; |
948 | 948 | ||
949 | u32 tca_rt, tca_hr, tca_en; | 949 | u32 tca_rt, tca_hr, tca_en; |
950 | u32 buf_vref, buf_slope; | 950 | u32 buf_vref, buf_slope; |
951 | 951 | ||
952 | tca_rt = fuse->ana0 & 0xFF; | 952 | tca_rt = fuse->ana0 & 0xFF; |
953 | tca_hr = (fuse->ana0 & 0xFF00) >> 8; | 953 | tca_hr = (fuse->ana0 & 0xFF00) >> 8; |
954 | tca_en = (fuse->ana0 & 0x2000000) >> 25; | 954 | tca_en = (fuse->ana0 & 0x2000000) >> 25; |
955 | 955 | ||
956 | buf_vref = (fuse->ana0 & 0x1F00000) >> 20; | 956 | buf_vref = (fuse->ana0 & 0x1F00000) >> 20; |
957 | buf_slope = (fuse->ana0 & 0xF0000) >> 16; | 957 | buf_slope = (fuse->ana0 & 0xF0000) >> 16; |
958 | 958 | ||
959 | writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28); | 959 | writel(buf_vref | (buf_slope << 16), (ulong)reg_base + 0x28); |
960 | writel((tca_en << 31) |(tca_hr <<16) | tca_rt, (ulong)reg_base + 0x30); | 960 | writel((tca_en << 31) |(tca_hr <<16) | tca_rt, (ulong)reg_base + 0x30); |
961 | } | 961 | } |
962 | } | 962 | } |
963 | 963 | ||
964 | #if defined(CONFIG_SPL_BUILD) | 964 | #if defined(CONFIG_SPL_BUILD) |
965 | #if defined(CONFIG_IMX8MQ) || defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN) | 965 | #if defined(CONFIG_IMX8MQ) || defined(CONFIG_IMX8MM) || defined(CONFIG_IMX8MN) |
966 | bool serror_need_skip = true; | 966 | bool serror_need_skip = true; |
967 | void do_error(struct pt_regs *pt_regs, unsigned int esr) | 967 | void do_error(struct pt_regs *pt_regs, unsigned int esr) |
968 | { | 968 | { |
969 | /* If stack is still in ROM reserved OCRAM not switch to SPL, it is the ROM SError */ | 969 | /* If stack is still in ROM reserved OCRAM not switch to SPL, it is the ROM SError */ |
970 | ulong sp; | 970 | ulong sp; |
971 | asm volatile("mov %0, sp" : "=r"(sp) : ); | 971 | asm volatile("mov %0, sp" : "=r"(sp) : ); |
972 | 972 | ||
973 | if (serror_need_skip && | 973 | if (serror_need_skip && |
974 | sp < 0x910000 && sp >= 0x900000) { | 974 | sp < 0x910000 && sp >= 0x900000) { |
975 | 975 | ||
976 | /* Check for ERR050342, imx8mq HDCP enabled parts */ | 976 | /* Check for ERR050342, imx8mq HDCP enabled parts */ |
977 | if (is_imx8mq() && !(readl(OCOTP_BASE_ADDR + 0x450) & 0x08000000)) { | 977 | if (is_imx8mq() && !(readl(OCOTP_BASE_ADDR + 0x450) & 0x08000000)) { |
978 | serror_need_skip = false; | 978 | serror_need_skip = false; |
979 | return; /* Do nothing skip the SError in ROM */ | 979 | return; /* Do nothing skip the SError in ROM */ |
980 | } | 980 | } |
981 | 981 | ||
982 | /* Check for ERR050350, field return mode for imx8mq, mm and mn */ | 982 | /* Check for ERR050350, field return mode for imx8mq, mm and mn */ |
983 | if (readl(OCOTP_BASE_ADDR + 0x630) & 0x1) { | 983 | if (readl(OCOTP_BASE_ADDR + 0x630) & 0x1) { |
984 | serror_need_skip = false; | 984 | serror_need_skip = false; |
985 | return; /* Do nothing skip the SError in ROM */ | 985 | return; /* Do nothing skip the SError in ROM */ |
986 | } | 986 | } |
987 | } | 987 | } |
988 | 988 | ||
989 | efi_restore_gd(); | 989 | efi_restore_gd(); |
990 | printf("\"Error\" handler, esr 0x%08x\n", esr); | 990 | printf("\"Error\" handler, esr 0x%08x\n", esr); |
991 | show_regs(pt_regs); | 991 | show_regs(pt_regs); |
992 | panic("Resetting CPU ...\n"); | 992 | panic("Resetting CPU ...\n"); |
993 | 993 | ||
994 | } | 994 | } |
995 | #endif | 995 | #endif |
996 | #endif | 996 | #endif |
997 | 997 | ||
998 | #if defined(CONFIG_IMX8MN) | 998 | #if defined(CONFIG_IMX8MN) |
999 | enum env_location env_get_location(enum env_operation op, int prio) | 999 | enum env_location env_get_location(enum env_operation op, int prio) |
1000 | { | 1000 | { |
1001 | enum boot_device dev = get_boot_device(); | 1001 | enum boot_device dev = get_boot_device(); |
1002 | enum env_location env_loc = ENVL_UNKNOWN; | 1002 | enum env_location env_loc = ENVL_UNKNOWN; |
1003 | 1003 | ||
1004 | if (prio) | 1004 | if (prio) |
1005 | return env_loc; | 1005 | return env_loc; |
1006 | 1006 | ||
1007 | switch (dev) { | 1007 | switch (dev) { |
1008 | #ifdef CONFIG_ENV_IS_IN_SPI_FLASH | 1008 | #ifdef CONFIG_ENV_IS_IN_SPI_FLASH |
1009 | case QSPI_BOOT: | 1009 | case QSPI_BOOT: |
1010 | env_loc = ENVL_SPI_FLASH; | 1010 | env_loc = ENVL_SPI_FLASH; |
1011 | break; | 1011 | break; |
1012 | #endif | 1012 | #endif |
1013 | #ifdef CONFIG_ENV_IS_IN_NAND | 1013 | #ifdef CONFIG_ENV_IS_IN_NAND |
1014 | case NAND_BOOT: | 1014 | case NAND_BOOT: |
1015 | env_loc = ENVL_NAND; | 1015 | env_loc = ENVL_NAND; |
1016 | break; | 1016 | break; |
1017 | #endif | 1017 | #endif |
1018 | #ifdef CONFIG_ENV_IS_IN_MMC | 1018 | #ifdef CONFIG_ENV_IS_IN_MMC |
1019 | case SD1_BOOT: | 1019 | case SD1_BOOT: |
1020 | case SD2_BOOT: | 1020 | case SD2_BOOT: |
1021 | case SD3_BOOT: | 1021 | case SD3_BOOT: |
1022 | case MMC1_BOOT: | 1022 | case MMC1_BOOT: |
1023 | case MMC2_BOOT: | 1023 | case MMC2_BOOT: |
1024 | case MMC3_BOOT: | 1024 | case MMC3_BOOT: |
1025 | env_loc = ENVL_MMC; | 1025 | env_loc = ENVL_MMC; |
1026 | break; | 1026 | break; |
1027 | #endif | 1027 | #endif |
1028 | default: | 1028 | default: |
1029 | #ifdef CONFIG_ENV_DEFAULT_NOWHERE | 1029 | #ifdef CONFIG_ENV_DEFAULT_NOWHERE |
1030 | env_loc = ENVL_NOWHERE; | 1030 | env_loc = ENVL_NOWHERE; |
1031 | #endif | 1031 | #endif |
1032 | break; | 1032 | break; |
1033 | } | 1033 | } |
1034 | 1034 | ||
1035 | return env_loc; | 1035 | return env_loc; |
1036 | } | 1036 | } |
1037 | 1037 | ||
1038 | #ifndef ENV_IS_EMBEDDED | 1038 | #ifndef ENV_IS_EMBEDDED |
1039 | long long env_get_offset(long long defautl_offset) | 1039 | long long env_get_offset(long long defautl_offset) |
1040 | { | 1040 | { |
1041 | enum boot_device dev = get_boot_device(); | 1041 | enum boot_device dev = get_boot_device(); |
1042 | 1042 | ||
1043 | switch (dev) { | 1043 | switch (dev) { |
1044 | case NAND_BOOT: | 1044 | case NAND_BOOT: |
1045 | return (60 << 20); /* 60MB offset for NAND */ | 1045 | return (60 << 20); /* 60MB offset for NAND */ |
1046 | default: | 1046 | default: |
1047 | break; | 1047 | break; |
1048 | } | 1048 | } |
1049 | 1049 | ||
1050 | return defautl_offset; | 1050 | return defautl_offset; |
1051 | } | 1051 | } |
1052 | #endif | 1052 | #endif |
1053 | #endif | 1053 | #endif |
1054 | 1054 |