1 /**
2 * \file sbl_slave_core_boot.c
3 *
4 * \brief This file contain functions related to slave core boot-up.
5 *
6 */
8 /*
9 * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 *
15 * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the
21 * distribution.
22 *
23 * Neither the name of Texas Instruments Incorporated nor the names of
24 * its contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *
39 */
41 /* ========================================================================== */
42 /* Include Files */
43 /* ========================================================================== */
45 #include <stdint.h>
46 #include <string.h>
47 #include <ti/csl/csl_types.h>
48 #include <ti/csl/cslr_device.h>
49 #include <ti/csl/hw_types.h>
50 #include <ti/csl/arch/csl_arch.h>
51 #include <ti/csl/soc.h>
52 #include <ti/drv/uart/UART_stdio.h>
54 #include "sbl_soc.h"
55 #include "sbl_log.h"
56 #include "sbl_soc_cfg.h"
57 #include "sbl_profile.h"
58 #include "sbl_err_trap.h"
59 #include "sbl_slave_core_boot.h"
60 #include "sbl_rcm.h"
61 #include "sbl_utils_addrxlate.h"
63 #if defined(BOOT_UART)
64 #include "sbl_uart.h"
65 #endif
67 #if defined(BOOT_QSPI)
68 #include "sbl_qspi.h"
69 #endif
71 /* ========================================================================== */
72 /* Macros & Typedefs */
73 /* ========================================================================== */
74 #define SBL_DISABLE_MCU_LOCKSTEP (0)
75 #define SBL_ENABLE_MCU_LOCKSTEP (1)
77 /* Entry address for DSP1 applications in the memory region where trampolene is located */
78 #define DSP_ENTRY_ADDR (CSL_DSP_L2_U_BASE)
80 /*
81 * DSP instructions to be copied to the Trampolene to avoid the alignment
82 * requirement.
83 */
84 uint32_t dspInstruction[10] =
85 {
86 0x0500002a, /* MVK.S2 destAddr, B10 */
87 0x0500006a, /* MVKH.S2 destAddr, B10 */
88 0x00280362, /* B.S2 B10 */
89 0x00006000, /* NOP 4 */
90 0x00000000, /* NOP */
91 0x00000000 /* NOP */
92 };
94 /* ========================================================================== */
95 /* Internal Functions */
96 /* ========================================================================== */
97 static void SBL_c66xWakeup(void)
98 {
99 CSL_dss_rcmRegs *dssRcmRegs = (CSL_dss_rcmRegs *)CSL_DSS_RCM_U_BASE;
100 Rcm_Return retVal;
102 /* GEL reset RST CTRL before DSS PLL config. Changing order here. Revert if not functional */
103 /* WR_MEM_32(CSL_DSS_RCM_U_BASE+CSL_DSS_RCM_DSS_DSP_RST_CTRL, 0x0); //DSS_DSP_RST_CTRL */
104 //HW_WR_REG32(CSL_DSS_RCM_U_BASE+DSS_DSP_CLK_DIV_VAL, 0x000); //DSS_WDT_CLK_DIV_VAL_CLKDIVR = 0x000; 450/1
105 //HW_WR_REG32(CSL_DSS_RCM_U_BASE+DSS_DSP_CLK_SRC_SEL, 0x222); //DSS_WDT_CLK_SRC_SEL_CLKSRCSEL = 0x222;
106 retVal = SBL_RcmSetDspCoreClock(Rcm_DSPClockSource_DPLL_DSP_HSDIV0_CLKOUT1, SBL_DSP1_C66X_FREQ_HZ);
107 DebugP_assert(retVal == Rcm_Return_SUCCESS);
109 CSL_FINS(dssRcmRegs->DSS_DSP_RST_CTRL, DSS_RCM_DSS_DSP_RST_CTRL_DSS_DSP_RST_CTRL_ASSERT_POR, 0x0);
110 CSL_FINS(dssRcmRegs->DSS_DSP_RST_CTRL, DSS_RCM_DSS_DSP_RST_CTRL_DSS_DSP_RST_CTRL_ASSERT_GLOBAL, 0x0);
111 CSL_FINS(dssRcmRegs->DSS_DSP_RST_CTRL, DSS_RCM_DSS_DSP_RST_CTRL_DSS_DSP_RST_CTRL_ASSERT_LOCAL, 0x0);
113 CSL_FINS(dssRcmRegs->DSS_DSP_CLK_GATE, DSS_RCM_DSS_DSP_CLK_GATE_DSS_DSP_CLK_GATE_GATED, 0x0);
115 CSL_FINS(dssRcmRegs->DSP_PD_WAKEUP_MASK0, DSS_RCM_DSP_PD_WAKEUP_MASK0_DSP_PD_WAKEUP_MASK0_WAKEUP_MASK0, 0xFFFEFFFF);
116 CSL_FINS(dssRcmRegs->DSP_PD_TRIGGER_WAKUP,DSS_RCM_DSP_PD_TRIGGER_WAKUP_DSP_PD_TRIGGER_WAKUP_WAKEUP_TRIGGER, 0x1);
118 while((CSL_FEXT(dssRcmRegs->DSP_PD_STATUS, DSS_RCM_DSP_PD_STATUS_DSP_PD_STATUS_PD_STATUS) & 0x1) != 1U);
119 (void)Osal_delay(1);
120 }
122 static void SBL_c66xStart(void)
123 {
124 CSL_dss_rcmRegs *dssRcmRegs = (CSL_dss_rcmRegs *)CSL_DSS_RCM_U_BASE;
126 CSL_FINS(dssRcmRegs->DSP_PD_CTRL, DSS_RCM_DSP_PD_CTRL_DSP_PD_CTRL_INTERRUPT_MASK, 0x1);
127 CSL_FINS(dssRcmRegs->DSP_PD_CTRL, DSS_RCM_DSP_PD_CTRL_DSP_PD_CTRL_INTERRUPT_MASK, 0x0);
128 CSL_FINS(dssRcmRegs->DSP_PD_CTRL, DSS_RCM_DSP_PD_CTRL_DSP_PD_CTRL_PROC_HALT, 0x0);
129 }
131 static void SBL_memInitc66x(void)
132 {
133 SBL_RcmStartMeminitDSSL2(RCM_MEMINIT_DSSL2_MEMBANK_ALL);
134 SBL_RcmStartMeminitDSSL3(RCM_MEMINIT_DSSL3_MEMBANK_ALL);
135 SBL_RcmWaitMeminitDSSL2(RCM_MEMINIT_DSSL2_MEMBANK_ALL);
136 SBL_RcmWaitMeminitDSSL3(RCM_MEMINIT_DSSL3_MEMBANK_ALL);
137 }
139 static void SBL_memInitTCMACR5(void)
140 {
141 SBL_RcmStartMeminitTCMA();
142 SBL_RcmWaitMeminitTCMA();
143 }
145 static void SBL_memInitTCMBCR5(void)
146 {
147 SBL_RcmStartMeminitTCMB();
148 SBL_RcmWaitMeminitTCMB();
149 }
151 void SBL_cr5AUnhalt(CSL_mss_ctrlRegs *mssCtrl)
152 {
153 //Core A unhalt
154 CSL_FINS(mssCtrl->R5_COREA_HALT, MSS_CTRL_R5_COREA_HALT_R5_COREA_HALT_HALT, 0x0U);
155 }
157 void SBL_cr5BUnhalt(CSL_mss_ctrlRegs *mssCtrl)
158 {
159 //Core B unhalt
160 CSL_FINS(mssCtrl->R5_COREB_HALT, MSS_CTRL_R5_COREB_HALT_R5_COREB_HALT_HALT, 0x0);
161 }
163 void SBL_localR5CoreTriggerReset(void)
164 {
165 CSL_mss_ctrlRegs *mssCtrl = (CSL_mss_ctrlRegs *)CSL_MSS_CTRL_U_BASE;
166 CSL_FINS(mssCtrl->R5_CONTROL, MSS_CTRL_R5_CONTROL_R5_CONTROL_RESET_FSM_TRIGGER, 0x7);
167 asm(" wfi ");
168 }
171 static void SBL_dualCoreBoot(CSL_mss_ctrlRegs *mssCtrl, CSL_mss_rcmRegs *rcmRegs)
172 {
173 uint32_t regVal;
175 regVal = rcmRegs->RST2ASSERTDLY;
176 CSL_FINS(regVal, MSS_RCM_RST2ASSERTDLY_RST2ASSERTDLY_R5SSA, 0x0);
177 CSL_FINS(regVal, MSS_RCM_RST2ASSERTDLY_RST2ASSERTDLY_R5SSB, 0x0);
178 CSL_FINS(regVal, MSS_RCM_RST2ASSERTDLY_RST2ASSERTDLY_R5A, 0x0);
179 CSL_FINS(regVal, MSS_RCM_RST2ASSERTDLY_RST2ASSERTDLY_R5B, 0x0);
180 rcmRegs->RST2ASSERTDLY = regVal;
182 regVal = rcmRegs->RST_WFICHECK;
183 CSL_FINS(regVal, MSS_RCM_RST_WFICHECK_RST_WFICHECK_R5SSA, 0x7);
184 CSL_FINS(regVal, MSS_RCM_RST_WFICHECK_RST_WFICHECK_R5SSB, 0x7);
185 CSL_FINS(regVal, MSS_RCM_RST_WFICHECK_RST_WFICHECK_R5A, 0x7);
186 CSL_FINS(regVal, MSS_RCM_RST_WFICHECK_RST_WFICHECK_R5B, 0x7);
187 rcmRegs->RST_WFICHECK = regVal;
189 regVal = mssCtrl->R5_CONTROL;
190 CSL_FINS(regVal, MSS_CTRL_R5_CONTROL_R5_CONTROL_LOCK_STEP, 0x0);
191 CSL_FINS(regVal, MSS_CTRL_R5_CONTROL_R5_CONTROL_LOCK_STEP_SWITCH_WAIT, 0x7);
192 mssCtrl->R5_CONTROL = regVal;
195 }
197 static void SBL_lockStepBoot(CSL_mss_ctrlRegs *mssCtrl, CSL_mss_rcmRegs *rcmRegs)
198 {
199 uint32_t regVal;
201 /* WR_MEM_32(MSS_RCM_U_BASE+RST2ASSERTDLY, 0x0); */ //RST2ASSERTDLY
202 regVal = rcmRegs->RST2ASSERTDLY;
203 CSL_FINS(regVal, MSS_RCM_RST2ASSERTDLY_RST2ASSERTDLY_R5SSA, 0x0);
204 CSL_FINS(regVal, MSS_RCM_RST2ASSERTDLY_RST2ASSERTDLY_R5SSB, 0x0);
205 CSL_FINS(regVal, MSS_RCM_RST2ASSERTDLY_RST2ASSERTDLY_R5A, 0x0);
206 CSL_FINS(regVal, MSS_RCM_RST2ASSERTDLY_RST2ASSERTDLY_R5B, 0x0);
207 rcmRegs->RST2ASSERTDLY = regVal;
209 /* WR_MEM_32(MSS_RCM_U_BASE+RST_WFICHECK, 0x00000707); */ //RSTWFI CHECK
210 regVal = rcmRegs->RST_WFICHECK;
211 CSL_FINS(regVal, MSS_RCM_RST_WFICHECK_RST_WFICHECK_R5SSA, 0x7);
212 CSL_FINS(regVal, MSS_RCM_RST_WFICHECK_RST_WFICHECK_R5SSB, 0x7);
213 CSL_FINS(regVal, MSS_RCM_RST_WFICHECK_RST_WFICHECK_R5A, 0x7);
214 CSL_FINS(regVal, MSS_RCM_RST_WFICHECK_RST_WFICHECK_R5B, 0x7);
215 rcmRegs->RST_WFICHECK = regVal;
217 regVal = mssCtrl->R5_CONTROL;
218 CSL_FINS(regVal, MSS_CTRL_R5_CONTROL_R5_CONTROL_LOCK_STEP, 0x7);
219 CSL_FINS(regVal, MSS_CTRL_R5_CONTROL_R5_CONTROL_LOCK_STEP_SWITCH_WAIT, 0x7);
220 mssCtrl->R5_CONTROL = regVal;
222 }
224 static void SBL_ConfigMcuLockStep(uint8_t enableLockStep)
225 {
227 SBL_ADD_PROFILE_POINT;
230 if (enableLockStep)
231 {
232 SBL_log(SBL_LOG_MAX, "SBL_procBootSetProcessorCfg, ProcId 0x%x, enabling Lockstep mode...\n");
233 SBL_lockStepBoot((CSL_mss_ctrlRegs *) CSL_MSS_CTRL_U_BASE , (CSL_mss_rcmRegs *)CSL_MSS_RCM_U_BASE);
235 }
236 else
237 {
238 SBL_log(SBL_LOG_MAX, "SBL_procBootSetProcessorCfg, ProcId 0x%x, enabling split mode...\n");
239 SBL_dualCoreBoot((CSL_mss_ctrlRegs *) CSL_MSS_CTRL_U_BASE , (CSL_mss_rcmRegs *)CSL_MSS_RCM_U_BASE);
240 }
242 SBL_ADD_PROFILE_POINT;
244 return;
245 }
247 int32_t SBL_ImageCopy(sblEntryPoint_t *pEntry)
248 {
249 int32_t retval = 0;
250 cpu_core_id_t core_id;
252 SBL_ADD_PROFILE_POINT;
254 /* Initialize the entry point array to 0. */
255 for (core_id = SBL_FIRST_CORE_ID; core_id < NUM_CORES; core_id ++)
256 pEntry->CpuEntryPoint[core_id] = SBL_INVALID_ENTRY_ADDR;
258 SBL_ADD_PROFILE_POINT;
260 #if defined(BOOT_UART)
261 if (SBL_UARTBootImage(pEntry) != E_PASS)
262 #elif defined(BOOT_QSPI)
263 if (SBL_QSPIBootImage(pEntry) != E_PASS)
264 #endif
265 {
266 retval = E_FAIL;
267 }
269 SBL_ADD_PROFILE_POINT;
271 return retval;
272 }
274 /**
275 * \brief SBL_SetupCoreMem function sets up the CPUs internal memory
276 *
277 * \param[in] core_id - CPU ID
278 * \param[in] pAppEntry - Core info struct
279 *
280 * \return none
281 */
282 void SBL_SetupCoreMem(uint32_t core_id)
283 {
284 uint8_t runLockStep = 0;
286 SBL_ADD_PROFILE_POINT;
288 /* Remap virtual core-ids if needed */
289 switch (core_id)
290 {
291 case MCU1_SMP_ID:
292 runLockStep = 1;
293 core_id = MCU1_CPU0_ID;
294 break;
295 default:
296 break;
297 }
299 if(runLockStep)
300 {
301 SBL_log(SBL_LOG_MAX, "Detected locktep for core_id %d\n", core_id);
302 SBL_ConfigMcuLockStep(SBL_ENABLE_MCU_LOCKSTEP);
303 }
305 switch (core_id)
306 {
307 case DSP1_C66X_ID:
308 SBL_log(SBL_LOG_MAX, "DSP Wakeup... \n");
309 SBL_c66xWakeup();
310 SBL_log(SBL_LOG_MAX, "DSP Meminit... \n");
311 SBL_memInitc66x();
312 break;
313 case MCU1_CPU1_ID:
314 SBL_log(SBL_LOG_MAX, "Switching core id %d to split mode... \n", core_id-1);
315 /* Image for second MCU core present, disable lock step for the cluster */
316 SBL_ConfigMcuLockStep(SBL_DISABLE_MCU_LOCKSTEP);
317 /* DOnt break, fall through for enabling TCMs */
318 case MCU1_CPU0_ID:
319 SBL_memInitTCMACR5();
320 SBL_memInitTCMBCR5();
321 break;
322 default:
323 /* No special memory setup needed */
324 break;
325 }
327 SBL_ADD_PROFILE_POINT;
329 return;
330 }
332 /**
333 * \brief SBL_SlaveCoreBoot function sets the entry point, sets up clocks
334 * and enable to core to start executing from entry point.
335 *
336 * \param core_id = Selects a core on the SOC, refer to cpu_core_id_t enum
337 * freqHz = Speed of core at boot up, 0 indicates use SBL default freqs.
338 * pAppEntry = SBL entry point struct
339 *
340 **/
341 void SBL_SlaveCoreBoot(cpu_core_id_t core_id, uint32_t freqHz, sblEntryPoint_t *pAppEntry)
342 {
343 SBL_ADD_PROFILE_POINT;
345 #if defined(SBL_SKIP_MCU_RESET)
346 /* Finished processing images for all cores, start MCU_0 */
347 if ((core_id == MCU1_CPU1_ID) &&
348 (pAppEntry->CpuEntryPoint[core_id] >= SBL_INVALID_ENTRY_ADDR))
349 {
350 /* Display profile logs */
351 SBL_printProfileLog();
353 SBL_log(SBL_LOG_MAX, "Starting app, branching to 0x0 \n");
354 /* Branch to start of ATCM */
355 ((void(*)(void))0x0)();
356 }
357 #endif
359 /* Power down and then power up each core*/
360 switch (core_id)
361 {
362 case MCU1_CPU1_ID:
363 /* Display profile logs */
364 SBL_printProfileLog();
366 #ifdef SBL_SKIP_MCU_RESET
367 SBL_log(SBL_LOG_MAX, "Starting app, branching to 0x0 \n");
368 /* Branch to start of ATCM */
369 ((void(*)(void))0x0)();
370 #else
372 #endif
373 break;
375 case MCU1_CPU0_ID:
377 break;
378 case DSP1_C66X_ID:
379 SBL_log(SBL_LOG_MAX, "SBL_procBootReleaseProcessor, ProcId 0x%x...\n", core_id);
380 SBL_c66xStart();
381 SBL_ADD_PROFILE_POINT;
382 break;
383 }
384 }
387 cpu_core_id_t SBL_getLocalCoreId(void)
388 {
389 #ifndef BUILD_MCU1_0
390 #error "Self Core address assumes SBL runs on MCU1_0"
391 #endif
392 return MCU1_CPU0_ID;
393 }
395 static void SBL_DspEntryPointSet(uint32_t entryPoint, uint32_t *pDspInstr)
396 {
397 uint32_t entryVal = 0U;
398 uint32_t dspOpcode = 0U;
400 entryVal = (entryPoint & 0x0000FFFF);
401 dspOpcode = *pDspInstr;
402 /*
403 ** Mask and update the lower 16 bits of entry address within the MVK
404 ** instruction opcode.
405 */
406 *pDspInstr = (((dspOpcode) & ~(0x007FFF80)) | (( (entryVal) << 0x7) & 0x007FFF80));
408 entryVal = ((entryPoint & 0xFFFF0000) >> 16);
409 dspOpcode = *(pDspInstr + 1);
410 /*
411 ** Mask and update the upper 16 bits of entry address within the MVK
412 ** instruction opcode.
413 */
414 *(pDspInstr + 1) = (((dspOpcode) & ~(0x007FFF80)) | (( (entryVal) << 0x7) & 0x007FFF80));
415 }
417 void SBL_SetDSPResetVec(uint8_t core, uint32_t entry)
418 {
419 CSL_dss_ctrlRegs * ptrDSSCTRLRegs = (CSL_dss_ctrlRegs *)CSL_DSS_CTRL_U_BASE;
420 /* TODO Local module reset assert */
422 SBL_DspEntryPointSet(entry, dspInstruction);
424 memcpy((void *) Utils_xlate2LocalAddr(DSP_ENTRY_ADDR, DSP1_C66X_ID), (void *)dspInstruction,
425 sizeof(dspInstruction));
427 CacheP_wbInv((void *) Utils_xlate2LocalAddr(DSP_ENTRY_ADDR, DSP1_C66X_ID), sizeof(dspInstruction));
428 /* Set DSP boot address to trampoline for both Secure and NS mode */
429 CSL_FINS(ptrDSSCTRLRegs->DSS_DSP_BOOTCFG , DSS_CTRL_DSS_DSP_BOOTCFG_DSS_DSP_BOOTCFG_ISTP_RST_VAL, (DSP_ENTRY_ADDR >> 10));
431 /* TODO Local module reset deassert */
432 }