]>
Commit | Line | Data |
---|---|---|
c2562d7c LV |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * J721E: SoC specific initialization | |
4 | * | |
5 | * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/ | |
6 | * Lokesh Vutla <[email protected]> | |
7 | */ | |
8 | ||
9 | #include <common.h> | |
10 | #include <spl.h> | |
11 | #include <asm/io.h> | |
12 | #include <asm/armv7_mpu.h> | |
0a704924 | 13 | #include <asm/arch/hardware.h> |
9d1303b3 | 14 | #include <asm/arch/sysfw-loader.h> |
c2562d7c | 15 | #include "common.h" |
9c0ff866 LV |
16 | #include <asm/arch/sys_proto.h> |
17 | #include <linux/soc/ti/ti_sci_protocol.h> | |
9d1303b3 AD |
18 | #include <dm.h> |
19 | #include <dm/uclass-internal.h> | |
20 | #include <dm/pinctrl.h> | |
c2562d7c LV |
21 | |
22 | #ifdef CONFIG_SPL_BUILD | |
b73fcbce AD |
23 | static void mmr_unlock(u32 base, u32 partition) |
24 | { | |
25 | /* Translate the base address */ | |
26 | phys_addr_t part_base = base + partition * CTRL_MMR0_PARTITION_SIZE; | |
27 | ||
28 | /* Unlock the requested partition if locked using two-step sequence */ | |
29 | writel(CTRLMMR_LOCK_KICK0_UNLOCK_VAL, part_base + CTRLMMR_LOCK_KICK0); | |
30 | writel(CTRLMMR_LOCK_KICK1_UNLOCK_VAL, part_base + CTRLMMR_LOCK_KICK1); | |
31 | } | |
32 | ||
33 | static void ctrl_mmr_unlock(void) | |
34 | { | |
35 | /* Unlock all WKUP_CTRL_MMR0 module registers */ | |
36 | mmr_unlock(WKUP_CTRL_MMR0_BASE, 0); | |
37 | mmr_unlock(WKUP_CTRL_MMR0_BASE, 1); | |
38 | mmr_unlock(WKUP_CTRL_MMR0_BASE, 2); | |
39 | mmr_unlock(WKUP_CTRL_MMR0_BASE, 3); | |
40 | mmr_unlock(WKUP_CTRL_MMR0_BASE, 4); | |
41 | mmr_unlock(WKUP_CTRL_MMR0_BASE, 6); | |
42 | mmr_unlock(WKUP_CTRL_MMR0_BASE, 7); | |
43 | ||
44 | /* Unlock all MCU_CTRL_MMR0 module registers */ | |
45 | mmr_unlock(MCU_CTRL_MMR0_BASE, 0); | |
46 | mmr_unlock(MCU_CTRL_MMR0_BASE, 1); | |
47 | mmr_unlock(MCU_CTRL_MMR0_BASE, 2); | |
48 | mmr_unlock(MCU_CTRL_MMR0_BASE, 3); | |
49 | mmr_unlock(MCU_CTRL_MMR0_BASE, 4); | |
50 | ||
51 | /* Unlock all CTRL_MMR0 module registers */ | |
52 | mmr_unlock(CTRL_MMR0_BASE, 0); | |
53 | mmr_unlock(CTRL_MMR0_BASE, 1); | |
54 | mmr_unlock(CTRL_MMR0_BASE, 2); | |
55 | mmr_unlock(CTRL_MMR0_BASE, 3); | |
56 | mmr_unlock(CTRL_MMR0_BASE, 4); | |
57 | mmr_unlock(CTRL_MMR0_BASE, 5); | |
58 | mmr_unlock(CTRL_MMR0_BASE, 6); | |
59 | mmr_unlock(CTRL_MMR0_BASE, 7); | |
60 | } | |
61 | ||
f94a07c8 AD |
62 | /* |
63 | * This uninitialized global variable would normal end up in the .bss section, | |
64 | * but the .bss is cleared between writing and reading this variable, so move | |
65 | * it to the .data section. | |
66 | */ | |
67 | u32 bootindex __attribute__((section(".data"))); | |
68 | ||
69 | static void store_boot_index_from_rom(void) | |
70 | { | |
71 | bootindex = *(u32 *)(CONFIG_SYS_K3_BOOT_PARAM_TABLE_INDEX); | |
72 | } | |
73 | ||
c2562d7c LV |
74 | void board_init_f(ulong dummy) |
75 | { | |
22b54804 | 76 | #if defined(CONFIG_K3_J721E_DDRSS) || defined(CONFIG_K3_LOAD_SYSFW) |
9d1303b3 AD |
77 | struct udevice *dev; |
78 | int ret; | |
79 | #endif | |
c2562d7c | 80 | /* |
f94a07c8 AD |
81 | * Cannot delay this further as there is a chance that |
82 | * K3_BOOT_PARAM_TABLE_INDEX can be over written by SPL MALLOC section. | |
c2562d7c | 83 | */ |
f94a07c8 | 84 | store_boot_index_from_rom(); |
c2562d7c | 85 | |
b73fcbce AD |
86 | /* Make all control module registers accessible */ |
87 | ctrl_mmr_unlock(); | |
88 | ||
c2562d7c | 89 | #ifdef CONFIG_CPU_V7R |
40109f4d | 90 | disable_linefill_optimization(); |
c2562d7c LV |
91 | setup_k3_mpu_regions(); |
92 | #endif | |
93 | ||
94 | /* Init DM early */ | |
95 | spl_early_init(); | |
96 | ||
9d1303b3 AD |
97 | #ifdef CONFIG_K3_LOAD_SYSFW |
98 | /* | |
99 | * Process pinctrl for the serial0 a.k.a. MCU_UART0 module and continue | |
100 | * regardless of the result of pinctrl. Do this without probing the | |
101 | * device, but instead by searching the device that would request the | |
102 | * given sequence number if probed. The UART will be used by the system | |
103 | * firmware (SYSFW) image for various purposes and SYSFW depends on us | |
104 | * to initialize its pin settings. | |
105 | */ | |
106 | ret = uclass_find_device_by_seq(UCLASS_SERIAL, 0, true, &dev); | |
107 | if (!ret) | |
108 | pinctrl_select_state(dev, "default"); | |
109 | ||
110 | /* | |
111 | * Load, start up, and configure system controller firmware. Provide | |
112 | * the U-Boot console init function to the SYSFW post-PM configuration | |
113 | * callback hook, effectively switching on (or over) the console | |
114 | * output. | |
115 | */ | |
116 | k3_sysfw_loader(preloader_console_init); | |
117 | #else | |
c2562d7c LV |
118 | /* Prepare console output */ |
119 | preloader_console_init(); | |
9d1303b3 | 120 | #endif |
22b54804 | 121 | |
7b134930 K |
122 | #if defined(CONFIG_CPU_V7R) && defined(CONFIG_K3_AVS0) |
123 | ret = uclass_get_device_by_driver(UCLASS_MISC, DM_GET_DRIVER(k3_avs), | |
124 | &dev); | |
125 | if (ret) | |
126 | printf("AVS init failed: %d\n", ret); | |
127 | #endif | |
128 | ||
22b54804 LV |
129 | #if defined(CONFIG_K3_J721E_DDRSS) |
130 | ret = uclass_get_device(UCLASS_RAM, 0, &dev); | |
131 | if (ret) | |
132 | panic("DRAM init failed: %d\n", ret); | |
133 | #endif | |
c2562d7c | 134 | } |
0a704924 LV |
135 | |
136 | u32 spl_boot_mode(const u32 boot_device) | |
137 | { | |
138 | switch (boot_device) { | |
139 | case BOOT_DEVICE_MMC1: | |
140 | return MMCSD_MODE_EMMCBOOT; | |
141 | case BOOT_DEVICE_MMC2: | |
142 | return MMCSD_MODE_FS; | |
143 | default: | |
144 | return MMCSD_MODE_RAW; | |
145 | } | |
146 | } | |
147 | ||
148 | static u32 __get_primary_bootmedia(u32 main_devstat, u32 wkup_devstat) | |
149 | { | |
150 | ||
151 | u32 bootmode = (wkup_devstat & WKUP_DEVSTAT_PRIMARY_BOOTMODE_MASK) >> | |
152 | WKUP_DEVSTAT_PRIMARY_BOOTMODE_SHIFT; | |
153 | ||
154 | bootmode |= (main_devstat & MAIN_DEVSTAT_BOOT_MODE_B_MASK) << | |
155 | BOOT_MODE_B_SHIFT; | |
156 | ||
157 | if (bootmode == BOOT_DEVICE_OSPI || bootmode == BOOT_DEVICE_QSPI) | |
158 | bootmode = BOOT_DEVICE_SPI; | |
159 | ||
160 | if (bootmode == BOOT_DEVICE_MMC2) { | |
161 | u32 port = (main_devstat & | |
162 | MAIN_DEVSTAT_PRIM_BOOTMODE_MMC_PORT_MASK) >> | |
163 | MAIN_DEVSTAT_PRIM_BOOTMODE_PORT_SHIFT; | |
164 | if (port == 0x0) | |
165 | bootmode = BOOT_DEVICE_MMC1; | |
166 | } | |
167 | ||
168 | return bootmode; | |
169 | } | |
170 | ||
171 | u32 spl_boot_device(void) | |
172 | { | |
173 | u32 wkup_devstat = readl(CTRLMMR_WKUP_DEVSTAT); | |
174 | u32 main_devstat; | |
175 | ||
176 | if (wkup_devstat & WKUP_DEVSTAT_MCU_OMLY_MASK) { | |
177 | printf("ERROR: MCU only boot is not yet supported\n"); | |
178 | return BOOT_DEVICE_RAM; | |
179 | } | |
180 | ||
181 | /* MAIN CTRL MMR can only be read if MCU ONLY is 0 */ | |
182 | main_devstat = readl(CTRLMMR_MAIN_DEVSTAT); | |
183 | ||
184 | /* ToDo: Add support for backup boot media */ | |
185 | return __get_primary_bootmedia(main_devstat, wkup_devstat); | |
186 | } | |
c2562d7c | 187 | #endif |
9c0ff866 LV |
188 | |
189 | #ifdef CONFIG_SYS_K3_SPL_ATF | |
190 | ||
191 | #define J721E_DEV_MCU_RTI0 262 | |
192 | #define J721E_DEV_MCU_RTI1 263 | |
193 | #define J721E_DEV_MCU_ARMSS0_CPU0 250 | |
194 | #define J721E_DEV_MCU_ARMSS0_CPU1 251 | |
195 | ||
196 | void release_resources_for_core_shutdown(void) | |
197 | { | |
198 | struct ti_sci_handle *ti_sci; | |
199 | struct ti_sci_dev_ops *dev_ops; | |
200 | struct ti_sci_proc_ops *proc_ops; | |
201 | int ret; | |
202 | u32 i; | |
203 | ||
204 | const u32 put_device_ids[] = { | |
205 | J721E_DEV_MCU_RTI0, | |
206 | J721E_DEV_MCU_RTI1, | |
207 | }; | |
208 | ||
209 | ti_sci = get_ti_sci_handle(); | |
210 | dev_ops = &ti_sci->ops.dev_ops; | |
211 | proc_ops = &ti_sci->ops.proc_ops; | |
212 | ||
213 | /* Iterate through list of devices to put (shutdown) */ | |
214 | for (i = 0; i < ARRAY_SIZE(put_device_ids); i++) { | |
215 | u32 id = put_device_ids[i]; | |
216 | ||
217 | ret = dev_ops->put_device(ti_sci, id); | |
218 | if (ret) | |
219 | panic("Failed to put device %u (%d)\n", id, ret); | |
220 | } | |
221 | ||
222 | const u32 put_core_ids[] = { | |
223 | J721E_DEV_MCU_ARMSS0_CPU1, | |
224 | J721E_DEV_MCU_ARMSS0_CPU0, /* Handle CPU0 after CPU1 */ | |
225 | }; | |
226 | ||
227 | /* Iterate through list of cores to put (shutdown) */ | |
228 | for (i = 0; i < ARRAY_SIZE(put_core_ids); i++) { | |
229 | u32 id = put_core_ids[i]; | |
230 | ||
231 | /* | |
232 | * Queue up the core shutdown request. Note that this call | |
233 | * needs to be followed up by an actual invocation of an WFE | |
234 | * or WFI CPU instruction. | |
235 | */ | |
236 | ret = proc_ops->proc_shutdown_no_wait(ti_sci, id); | |
237 | if (ret) | |
238 | panic("Failed sending core %u shutdown message (%d)\n", | |
239 | id, ret); | |
240 | } | |
241 | } | |
242 | #endif |