b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | /****************************************************************************** |
| 2 | * |
| 3 | * (C)Copyright 2005 - 2011 Marvell. All Rights Reserved. |
| 4 | * |
| 5 | * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL. |
| 6 | * The copyright notice above does not evidence any actual or intended |
| 7 | * publication of such source code. |
| 8 | * This Module contains Proprietary Information of Marvell and should be |
| 9 | * treated as Confidential. |
| 10 | * The information in this file is provided for the exclusive use of the |
| 11 | * licensees of Marvell. |
| 12 | * Such users have the right to use, modify, and incorporate this code into |
| 13 | * products for purposes authorized by the license agreement provided they |
| 14 | * include this notice and the associated copyright notice with any such |
| 15 | * product. |
| 16 | * The information in this file is provided "AS IS" without warranty. |
| 17 | * |
| 18 | ****************************************************************************** |
| 19 | ** |
| 20 | ** FILENAME: OBM.c |
| 21 | ** |
| 22 | ** PURPOSE: OBM main routine |
| 23 | ** |
| 24 | ** History: Initial Creation 4/23/06 |
| 25 | ******************************************************************************/ |
| 26 | |
| 27 | ////////////////////////////////////////////////////////////////////// |
| 28 | // Include the main BootLoader header file |
| 29 | // IMPORTANT: |
| 30 | // DO NOT include anything from here. Include any header that is |
| 31 | // needed in the BootLoader.h file. |
| 32 | ////////////////////////////////////////////////////////////////////// |
| 33 | #include "BootLoader.h" |
| 34 | #include "obm2osl.h" |
| 35 | #include "fota.h" |
| 36 | #include "serial.h" |
| 37 | |
| 38 | extern UINT_T isDownload; |
| 39 | extern UINT_T time_count_enable; |
| 40 | extern UINT8_T time_count_in_sec; |
| 41 | extern OBM2OSL *pOBM2OSL_h; |
| 42 | extern pTEEC_INFO pAsrTeec; |
| 43 | extern UINT_T Reset; |
| 44 | UINT8_T FlashInitDone = 0; |
| 45 | BOOTING_MODE product_mode_select = FUNCTION_MODE; |
| 46 | |
| 47 | #if NZA3 || NZAS |
| 48 | /* |
| 49 | * If the obm size is not 4bytes aligned, it will cause data abort in bootrom |
| 50 | * raw nand/spi-flash read API. To workaround this bug, we put a one-dummy-word |
| 51 | * data section at the end of obm so that its size is always 4bytes aligned. |
| 52 | */ |
| 53 | volatile UINT_T dummy4align __attribute__((section("align_data"))) = 0xdeadbeef; |
| 54 | #endif |
| 55 | |
| 56 | ////////////////////////////////////////////////////////////////////// |
| 57 | // This is the entry point for the Boot Loader. |
| 58 | // |
| 59 | // Inputs: A pointer to the Transfer Struct that is passed in from BootROM. |
| 60 | // Outputs: NONE. Transfers control to OS Loader. |
| 61 | // |
| 62 | // It mainly functions as following: |
| 63 | // |
| 64 | // 1) Initial Setup |
| 65 | // 2) Validate TIM. |
| 66 | // 3) Perform TIM based setup. |
| 67 | // 4) Determine operating mode. |
| 68 | // a) If Download Path (SW Upgrade or Download) |
| 69 | // i. Download Descriptor File |
| 70 | // ii. Validate TIM |
| 71 | // iii. Download TIM Images |
| 72 | // b) If BOOT Path (Single TIM or Dual TIM boot) |
| 73 | // i. Single TIM Boot |
| 74 | // Configure Flashes and FM |
| 75 | // Load Images |
| 76 | // Validate images |
| 77 | // ii. Dual TIM Boot |
| 78 | // Configure Flashes and FM |
| 79 | // Load 2nd TIM |
| 80 | // Set TIM Pointers |
| 81 | // Validate 2nd TIM |
| 82 | // Load Images |
| 83 | // Validate images |
| 84 | // 5) BL Finalization setup |
| 85 | // 6) Transfer Control |
| 86 | ////////////////////////////////////////////////////////////////////// |
| 87 | void BootLoaderMain( P_TRANSFER_STRUCT pTS_h ) |
| 88 | { |
| 89 | FUSE_SET fuses; // Fuse information passed in from BootROM |
| 90 | IMAGE_INFO_3_4_0 *pBootImageInfo = NULL; |
| 91 | UINT_T Retval = GeneralError; |
| 92 | UINT_T ErrorCode = NoError; // Error Code variable |
| 93 | OPERATING_MODE_T bootMode = UPGRADESW; // initalized so that coverity doesn't complain |
| 94 | UINT_T LoadAddr, ImageSize, ImageID; |
| 95 | |
| 96 | // Transfer struct related parameters |
| 97 | UINT_T startOfDayTimerVal = 0; // pTS_h->SOD_ACCR0; |
| 98 | UINT_T TIM_Address = 0; // pTS_h->data_pairs[0].location; |
| 99 | pTIM pTIM_h = GetTimPointer(); |
| 100 | |
| 101 | // Initial setup |
| 102 | SetupEnvironment(&TIM_Address, pTS_h, &startOfDayTimerVal, pTIM_h, &fuses); |
| 103 | |
| 104 | // Perform TIM based setup |
| 105 | PerformTIMBasedSetup(pTIM_h, &fuses); |
| 106 | |
| 107 | #if NZA3 || NZAS |
| 108 | dummy4align = 0; |
| 109 | #endif |
| 110 | |
| 111 | // Determine operating mode |
| 112 | bootMode = DetermineOperatingMode(&fuses, pTIM_h); |
| 113 | |
| 114 | switch (bootMode) { |
| 115 | // DOWNLOAD PATH |
| 116 | case UPGRADESW: |
| 117 | case DOWNLOAD: |
| 118 | // Download Descriptor File |
| 119 | PlatformReleaseEMMDStatus(); |
| 120 | pBootImageInfo = DownloadModeMain( &fuses, pTIM_h, bootMode); |
| 121 | break; |
| 122 | // BOOT PATH |
| 123 | case SINGLE_TIM_BOOT: |
| 124 | case PRODUCT_USB_BOOT: |
| 125 | case PRODUCT_UART_BOOT: |
| 126 | case RECOVERY_MODE_BOOT: |
| 127 | case MENU_MODE_BOOT: |
| 128 | pBootImageInfo = BootModeMain(pTIM_h, bootMode, &fuses); |
| 129 | break; |
| 130 | default: |
| 131 | break; |
| 132 | } |
| 133 | |
| 134 | // If there is an error or no image is found for booting, we FAIL. |
| 135 | if ((pBootImageInfo == NULL) && (!isDownload)) // if it is download, no print this error code |
| 136 | { |
| 137 | FatalError(NULLPointer, "BLM", NULL); |
| 138 | } |
| 139 | // Finalization Setup |
| 140 | FinalizeSetup(&fuses, pTIM_h); |
| 141 | |
| 142 | #if USE_SERIAL_DEBUG |
| 143 | obm_printf("end...\n\r"); |
| 144 | #endif |
| 145 | // Transfer control to the next image. |
| 146 | if ((bootMode == UPGRADESW) || (bootMode == DOWNLOAD)) |
| 147 | { |
| 148 | if ( isDownload ) |
| 149 | { /* Pure Download */ |
| 150 | if (Reset == 1) |
| 151 | { |
| 152 | memset(pOBM2OSL_h, 0, sizeof(OBM2OSL)); |
| 153 | pOBM2OSL_h->booting_mode = OBMNODL; |
| 154 | OBMNODL_RST_FLAG = OBMNODL; |
| 155 | |
| 156 | do_wdt_reset(); // reset after download as default |
| 157 | } |
| 158 | |
| 159 | ErrorCode = 1; |
| 160 | // Infinite loop! |
| 161 | while(ErrorCode&1) |
| 162 | ErrorCode+=2;// need debugger to step beyond this loop after inspecting input args... |
| 163 | } |
| 164 | /* bootMode could be UPGRADESW or DOWNLOAD for upload or just a USB enum |
| 165 | After upload is finished or time out occurs after usb enum, keep booting to |
| 166 | next image, such as uboot or TOS. |
| 167 | Reboot or dead loop only for successful download. |
| 168 | */ |
| 169 | } |
| 170 | |
| 171 | if (pBootImageInfo) { |
| 172 | LoadAddr = pBootImageInfo->LoadAddr; |
| 173 | ImageSize = pBootImageInfo->ImageSize; |
| 174 | ImageID = pBootImageInfo->ImageID; |
| 175 | } |
| 176 | |
| 177 | /* Transfer control to next image, uboot or TOS */ |
| 178 | obm_printf("Jump to %s at 0x%x (size 0x%x)\n\r", |
| 179 | (ImageID == TZSWIDENTIFIER)?"Trusted OS":"OS-loader", |
| 180 | LoadAddr, ImageSize); |
| 181 | pOBM2OSL_h->quiet = serial_get_quiet(); |
| 182 | |
| 183 | #if defined(CONFIG_TEE_OS) |
| 184 | /* When TEE_OS is involved, use sw_scratch_reg to pass obm2oslo parameters instead of r11 */ |
| 185 | BU_REG_WRITE(OBM2OSLO_PARA_REG, (UINT_T)pOBM2OSL_h); |
| 186 | if (ImageID == TZSWIDENTIFIER) |
| 187 | TransferControl2TOS(LoadAddr, (UINT_T)GetNsEntryLoadAddress(), |
| 188 | (UINT_T)pOBM2OSL_h, (UINT_T)pAsrTeec); |
| 189 | #else |
| 190 | TransferControl(LoadAddr, ImageSize, LoadAddr, (UINT_T)pOBM2OSL_h); |
| 191 | #endif |
| 192 | } |
| 193 | |
| 194 | |
| 195 | ////////////////////////////////////////////////////////////////////// |
| 196 | // This is the Environment Setup function for the Boot Loader. |
| 197 | // |
| 198 | // Inputs: Pointer to the address of TIM, Pointer the Transfer Struct |
| 199 | // coming from the BootROM, Pointer to the Timer value, Pointer to the |
| 200 | // Fuses. |
| 201 | // Outputs: None |
| 202 | // |
| 203 | // It mainly functions as following: |
| 204 | // 1) If IPC read is required, gets the transfer struct from IPC. |
| 205 | // 2) Parses the transfer struct. |
| 206 | // 3) Sets the TIM pointers. |
| 207 | // 4) Initializes the SOD Timer interface. |
| 208 | // 5) Enables default clocks. |
| 209 | // 6) Initializes the fuses using platform settings passed in from BootROM. |
| 210 | // 7) Initializes the Keypad required for SW upgrade. |
| 211 | // 8) Initializes the Platform Message Queue. |
| 212 | // 9) Init Security API. |
| 213 | ////////////////////////////////////////////////////////////////////// |
| 214 | void SetupEnvironment(UINT_T *TIM_Address, P_TRANSFER_STRUCT pTS_h, UINT_T *startOfDayTimerVal, TIM *pTIM_h, pFUSE_SET pFuses) |
| 215 | { |
| 216 | UINT_T retval = NoError; |
| 217 | |
| 218 | // Enable the clocks for the peripherals that will be used |
| 219 | CheckDefaultClocks(); |
| 220 | |
| 221 | // Initialize the SOD timer interface |
| 222 | InitSODTimer(); |
| 223 | |
| 224 | ParseTransferStruct(TIM_Address, pTS_h, pFuses, startOfDayTimerVal); |
| 225 | |
| 226 | // serial debug |
| 227 | #if USE_SERIAL_DEBUG |
| 228 | PlatformUARTConfig(); |
| 229 | serial_init(); |
| 230 | obm_printf("start at 0x%x\n\r", OBM_USE_DDR_ADDR); |
| 231 | obm_printf("%s OBM with SWD >= %s\n\r", PLAT_NAME, HexToSwdObmVersion(SWD_VERSION)); |
| 232 | OBM_HeapInit(); |
| 233 | obm_printf(OBM_COMPILE_INFO); |
| 234 | #endif |
| 235 | |
| 236 | SetTIMPointers((UINT8_T*)*TIM_Address, pTIM_h); |
| 237 | if( pTIM_h->pConsTIM->VersionBind.Identifier != TIMIDENTIFIER ) |
| 238 | { |
| 239 | // Set error to indicate no TIM is found and make it a fatal error. |
| 240 | FatalError(TIMNotFound, "SE", 1); |
| 241 | } |
| 242 | |
| 243 | // Initialize any fuse information passed in by the BootROM |
| 244 | obm_printf("pFuses->value[0]: 0x%x\n\r", pFuses->value[0]); |
| 245 | obm_printf("pFuses->value[1]: 0x%x\n\r", pFuses->value[1]); |
| 246 | //pFuses->bits.SBE = 1; |
| 247 | obm_printf("pFuses->bits.SBE: %d\n\r", pFuses->bits.SBE); |
| 248 | |
| 249 | #if TRUSTED && PRODUCT_BUILD |
| 250 | obm_printf("Trusted OBM with ProductBuild\n\r"); |
| 251 | #elif TRUSTED && !PRODUCT_BUILD |
| 252 | obm_printf("Trusted OBM without ProductBuild\n\r"); |
| 253 | #else |
| 254 | obm_printf("Non-Trusted OBM\n\r"); |
| 255 | #endif |
| 256 | |
| 257 | #if ENABLE_MMU |
| 258 | obm_printf("MMU Enabled\n\r"); |
| 259 | #else |
| 260 | obm_printf("MMU Disabled\n\r"); |
| 261 | #endif |
| 262 | |
| 263 | #if I2C |
| 264 | I2CInit(); |
| 265 | #endif |
| 266 | |
| 267 | // Keypad initialization: Required for detecting software upgrade request from the keypad. |
| 268 | //These two lines of code conflict with SDMMC on MMP3,hence commenting them out |
| 269 | #if UPDATE_USE_GPIO |
| 270 | PlatformGPIOKeyConfig(); |
| 271 | #endif |
| 272 | |
| 273 | PlatformLateInit(); |
| 274 | |
| 275 | #if TRUSTED |
| 276 | // Init Security API. |
| 277 | //if (pFuses->bits.SBE) |
| 278 | { |
| 279 | obm_printf("SecurityInitialization\n\r"); |
| 280 | retval = SecurityInitialization(0); |
| 281 | if(retval != NoError) |
| 282 | { |
| 283 | FatalError(retval, "SE", 2); |
| 284 | } |
| 285 | |
| 286 | // Init Provisioning API. |
| 287 | ProvisioningInitialization(); |
| 288 | } |
| 289 | #endif |
| 290 | |
| 291 | } |
| 292 | |
| 293 | |
| 294 | ////////////////////////////////////////////////////////////////////// |
| 295 | // This is the Parse Transfer Struct function for the Boot Loader. |
| 296 | // |
| 297 | // Inputs: Pointer to the address of TIM, Pointer the Transfer Struct |
| 298 | // coming from the BootROM, Pointer to the Timer value, Pointer to the |
| 299 | // Fuses. |
| 300 | // Outputs: NONE. |
| 301 | // |
| 302 | // It mainly functions as following: |
| 303 | // 1) If the passed in Transfer Struct is not NULL, parse it and initialize |
| 304 | // the platform settings, the timer value, and the TIM address. |
| 305 | // 2) Else if it is NULL, look at a fixed location. |
| 306 | ////////////////////////////////////////////////////////////////////// |
| 307 | void ParseTransferStruct(UINT_T *TIM_Address, P_TRANSFER_STRUCT pTS_h, pFUSE_SET pFuses, UINT_T *startOfDayTimerVal) |
| 308 | { |
| 309 | UINT_T i, TS_Version; |
| 310 | P_TRANSFER_STRUCT_v2 pTS_v2; |
| 311 | |
| 312 | // If the passed in Transfer Struct is not NULL, parse it and initialize |
| 313 | // the platform settings, the timer value, and the TIM address. |
| 314 | if( pTS_h ) |
| 315 | { |
| 316 | TS_Version = pTS_h->TransferID; |
| 317 | if (TS_Version == TBR_XFER) // v1 of transfer struct is used by BootRom |
| 318 | { |
| 319 | pFuses->value[0] = (UINT_T) pTS_h->FuseVal; |
| 320 | pFuses->value[1] = 0x0; |
| 321 | *startOfDayTimerVal = pTS_h->SOD_ACCR0; |
| 322 | #if LAPW |
| 323 | ParseBR_ExtraState(pTS_h->ResumeParam[0]); |
| 324 | #endif |
| 325 | |
| 326 | // For the case where the TIM is not in TS coming from the IPC, |
| 327 | // TS includes random values. In this case, this loop can take a |
| 328 | // long time. With MAX_NUMBER_OF_DATA_PAIRS, we put a limit on this. |
| 329 | for( i=0; i<pTS_h->num_data_pairs && i<MAX_NUMBER_OF_DATA_PAIRS; i++) |
| 330 | { |
| 331 | if(pTS_h->data_pairs[i].data_id == TIM_DATA ) |
| 332 | { |
| 333 | *TIM_Address = pTS_h->data_pairs[i].location; |
| 334 | return; |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | else // v2 of transfer struct is used by OBM |
| 339 | { |
| 340 | pTS_v2 = (P_TRANSFER_STRUCT_v2) pTS_h; // cast to v2 of the xfer struct |
| 341 | pFuses->value[0] = pTS_v2->FuseVal[0]; |
| 342 | pFuses->value[1] = pTS_v2->FuseVal[1]; |
| 343 | *startOfDayTimerVal = pTS_v2->SOD_ACCR0; |
| 344 | |
| 345 | // For the case where the TIM is not in TS coming from the IPC, |
| 346 | // TS includes random values. In this case, this loop can take a |
| 347 | // long time. With MAX_NUMBER_OF_DATA_PAIRS, we put a limit on this. |
| 348 | for( i=0; i<pTS_v2->num_data_pairs && i<MAX_NUMBER_OF_DATA_PAIRS; i++) |
| 349 | { |
| 350 | if( pTS_v2->data_pairs[i].data_id == TIM_DATA ) |
| 351 | { |
| 352 | *TIM_Address = pTS_v2->data_pairs[i].location; |
| 353 | return; |
| 354 | } |
| 355 | } |
| 356 | } |
| 357 | } //end if( pTS_h ) |
| 358 | |
| 359 | *TIM_Address = 0; // should never be here! |
| 360 | } |
| 361 | |
| 362 | |
| 363 | ////////////////////////////////////////////////////////////////////// |
| 364 | // This is the Fatal Error function for the Boot Loader. |
| 365 | // |
| 366 | // Inputs: Error code,cause, sub code. |
| 367 | // Outputs: NONE. |
| 368 | // |
| 369 | // It mainly stays here in an infinite loop. |
| 370 | ////////////////////////////////////////////////////////////////////// |
| 371 | void FatalError(UINT_T ErrorCode, const CHAR* ErrStr, UINT_T ErrSubCode) |
| 372 | { |
| 373 | UINT_T odd = 1; |
| 374 | |
| 375 | // Print out why we failed if it is not a port error. |
| 376 | if (ErrorCode != DownloadPortError) |
| 377 | { |
| 378 | AddMessageError(REPORT_ERROR, ErrorCode); |
| 379 | } |
| 380 | |
| 381 | #if USE_SERIAL_DEBUG |
| 382 | err_msg("Fatal Error Code: 0x%x\n\r", ErrorCode); |
| 383 | |
| 384 | if (ErrStr != NULL) |
| 385 | { |
| 386 | err_msg("Error cause: %s\n\r", ErrStr); |
| 387 | } |
| 388 | |
| 389 | if (ErrSubCode != NULL) |
| 390 | err_msg("Error sub code: 0x%x\n\r", ErrSubCode); |
| 391 | |
| 392 | #endif |
| 393 | |
| 394 | //if( !isDownload ) // no reset for downloading |
| 395 | // do_wdt_reset(); |
| 396 | |
| 397 | #if SPINOR_CODE |
| 398 | SPINOR_Disable4BytesMode(); |
| 399 | #endif |
| 400 | |
| 401 | // Infinite loop! |
| 402 | while(odd&1) |
| 403 | { |
| 404 | // need debugger to step beyond this loop after inspecting input args... |
| 405 | odd+=2; |
| 406 | } |
| 407 | |
| 408 | return; |
| 409 | } |
| 410 | |
| 411 | ////////////////////////////////////////////////////////////////////// |
| 412 | // This is the function that performs TIM based setup in the Boot Loader. |
| 413 | // |
| 414 | // Inputs: A pointer to the TIM and a pointer to the Fuses. |
| 415 | // Outputs: NONE. |
| 416 | // |
| 417 | // It mainly functions as following: |
| 418 | // 1) Configures the operating mode. |
| 419 | // 2) Configures the DDR. |
| 420 | // 3) Enables the interrupts. |
| 421 | // 4) Enables the global interrupts. |
| 422 | // 5) Checks the TIM for port over-writes. If this fails, initializes |
| 423 | // the default ports. |
| 424 | ////////////////////////////////////////////////////////////////////// |
| 425 | void PerformTIMBasedSetup(pTIM pTIM_h, pFUSE_SET pFuses) |
| 426 | { |
| 427 | UINT_T Retval = NoError; |
| 428 | |
| 429 | #if REPORT_DDR_INFO |
| 430 | MCK5_Check_LPDDR2_Info(pTIM_h); |
| 431 | #endif |
| 432 | |
| 433 | // Configure DDR if BootROM doesn't configure it. |
| 434 | if (pFuses->bits.DDRInitialized == FALSE) |
| 435 | { |
| 436 | Retval = CheckAndConfigureDDR(pTIM_h, pFuses); |
| 437 | if (Retval != NoError) |
| 438 | { |
| 439 | FatalError(Retval, "PTBS", NULL); |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | // Interrupts may be required, so enable them. |
| 444 | // For example, downloading over USB requires interrupts. |
| 445 | |
| 446 | // point the interrupt exception handler to our routine. |
| 447 | // this allows us to run in-place out of isram |
| 448 | // without having to enable the enable the mmu. |
| 449 | SetInterruptVector(VECTOR_SRAM_BASE_ADDR); |
| 450 | IRQ_Glb_Dis(); // turns off all interrupts... |
| 451 | EnableIrqInterrupts(); // Enable Interrupts at the core |
| 452 | IRQ_Glb_Ena(); // Enable Global Ints using the AP Global Interrupt Mask Register |
| 453 | |
| 454 | //if (NoFrequencyChange == 0) // change pp as default |
| 455 | // pp_set(); |
| 456 | #if CP_BOOT |
| 457 | /* ASR1803S boot to MSA L2SRAM */ |
| 458 | #if FLCN || FACT |
| 459 | BU_REG_WRITE(0xD4050020, 0x23); |
| 460 | SetupL2SRAMMPU(); |
| 461 | #endif |
| 462 | #endif |
| 463 | } |
| 464 | |
| 465 | static INT FindDkbiPatternInTIM(pTIM pTIM_h) |
| 466 | { |
| 467 | pIMAGE_INFO_3_4_0 pImgInfo = NULL; |
| 468 | UINT_T TimSize; |
| 469 | UINT_T DkbiPatternAddr; |
| 470 | |
| 471 | pImgInfo = FindImageInTIM(pTIM_h, TIMIDENTIFIER); |
| 472 | if(pImgInfo == NULL){ |
| 473 | return 0; |
| 474 | } |
| 475 | |
| 476 | TimSize = (pImgInfo->ImageSize + 3) & (~3); //4byte align |
| 477 | DkbiPatternAddr = 0xD1000000 + TimSize; |
| 478 | |
| 479 | if(BU_REG_READ(DkbiPatternAddr) == DKBIDENTIFIER && |
| 480 | BU_REG_READ(DkbiPatternAddr+4) == DKBIDENTIFIER) |
| 481 | { |
| 482 | BU_REG_WRITE(DkbiPatternAddr, 0); |
| 483 | BU_REG_WRITE(DkbiPatternAddr+4, 0); |
| 484 | return 1; |
| 485 | } |
| 486 | |
| 487 | return 0; |
| 488 | } |
| 489 | |
| 490 | UINT_T PlatformInitFlash(pTIM pTIM_h) |
| 491 | { |
| 492 | UINT_T Retval = NoError; |
| 493 | UINT_T FlashNumber; |
| 494 | |
| 495 | if(IsTim4DKBI(pTIM_h)) { |
| 496 | /* No valid flash ID in TIMH for DKBI */ |
| 497 | return NoError; |
| 498 | } |
| 499 | |
| 500 | FlashNumber = (pTIM_h->pConsTIM->FlashInfo.BootFlashSign) & 0xFF; |
| 501 | if(!FlashInitDone) |
| 502 | { |
| 503 | // Determine the Flash that will be used to store the downloaded images. |
| 504 | Retval = Configure_Flashes (FlashNumber, BOOT_FLASH); |
| 505 | if( Retval == NoError) |
| 506 | { |
| 507 | InitializeDualTimEarly(pTIM_h); |
| 508 | |
| 509 | //turn on the flash management |
| 510 | InitializeFM(LEGACY_METHOD, BOOT_FLASH); |
| 511 | |
| 512 | #if !UPDATER |
| 513 | InitializeDualTimLate(pTIM_h); |
| 514 | #endif |
| 515 | |
| 516 | #ifdef BBM_LEGACY_EXT && !UPDATER |
| 517 | DetectScrubBitflipBlocks(); |
| 518 | #endif |
| 519 | FlashInitDone = 1; |
| 520 | |
| 521 | obm_printf("Flash Init Done\n\r"); |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | return Retval; |
| 526 | } |
| 527 | |
| 528 | ////////////////////////////////////////////////////////////////////// |
| 529 | // This is the Mode Determining function for the Boot Loader. |
| 530 | // |
| 531 | // Inputs: A pointer to the Fuses and a pointer to the TIM. |
| 532 | // Outputs: Returns one of the following operationg modes: |
| 533 | // UPGRADESW, DOWNLOAD, SINGLE_TIM_BOOT, or DUAL_TIM_BOOT |
| 534 | // |
| 535 | // It mainly functions as following: |
| 536 | // 1) Sets running as identifier. |
| 537 | // 2) Check if the HW upgrade request button is pressed. If so, mode = UPGRADESW. |
| 538 | // 3) Else if there is a DKB ID in the TIM, then mode = DOWNLOAD. |
| 539 | // 4) Else if there is a DUAL TIM ID in the TIM, then mode = DUAL_TIM_BOOT. |
| 540 | // 5) Else by default, we have mode = SINGLE_TIM_BOOT. |
| 541 | ////////////////////////////////////////////////////////////////////// |
| 542 | OPERATING_MODE_T DetermineOperatingMode(FUSE_SET *pFuses, pTIM pTIM_h) |
| 543 | { |
| 544 | OPERATING_MODE_T mode = SINGLE_TIM_BOOT; |
| 545 | UINT_T loops; |
| 546 | UINT gotkey = 0, Retval; |
| 547 | P_FOTA_Firmware pFOTA_T = NULL; |
| 548 | UINT_T ATDL_Cfg = 0; |
| 549 | |
| 550 | PlatformInitFlash(pTIM_h); |
| 551 | |
| 552 | // No user request for software update. |
| 553 | // Deterimine from TIM headers what to do. |
| 554 | // If DKB Identifier is found then we have download mode. |
| 555 | if (IsTim4DKBI(pTIM_h) || FindDkbiPatternInTIM(pTIM_h)) |
| 556 | { |
| 557 | mode = DOWNLOAD; |
| 558 | time_count_enable = FALSE; |
| 559 | obm_printf("Empty Board or Force Download\n\r"); |
| 560 | return mode; |
| 561 | } |
| 562 | |
| 563 | ATDL_Cfg = GetAutoDownloadConfig(pTIM_h); |
| 564 | if (ATDL_Cfg) { |
| 565 | mode = UPGRADESW; |
| 566 | time_count_enable = TRUE; |
| 567 | time_count_in_sec = ATDL_Cfg; |
| 568 | obm_printf("ATDL download\n\r"); |
| 569 | return mode; |
| 570 | } |
| 571 | |
| 572 | if(PlatformCheckForceUSBEnumFlag()) |
| 573 | { |
| 574 | mode = UPGRADESW; |
| 575 | time_count_enable = TRUE; |
| 576 | PlatformClearForceUSBEnumFlag(); |
| 577 | obm_printf("Download due to force usb enum flag\n\r"); |
| 578 | return mode; |
| 579 | } |
| 580 | |
| 581 | if(serial_read_byte() == 0x0D) /* CR pressed */ |
| 582 | { |
| 583 | mode = UPGRADESW; |
| 584 | time_count_enable = TRUE; |
| 585 | obm_printf("Uart force to download\n\r"); |
| 586 | return mode; |
| 587 | } |
| 588 | |
| 589 | pFOTA_T = OTAGetConfig(pTIM_h); |
| 590 | if(pFOTA_T && (pFOTA_T->dlflag[0] == DLFLG) && (pFOTA_T->dlflag[1] != DLDONE)) |
| 591 | { |
| 592 | mode = UPGRADESW; |
| 593 | time_count_enable = FALSE; |
| 594 | obm_printf("Wait for unfinished download...\n\r"); |
| 595 | return mode; |
| 596 | } |
| 597 | |
| 598 | #if TRUSTED |
| 599 | if (pFOTA_T && (pFOTA_T->TrustBootStatus != 0) && (pFOTA_T->TrustBootStatus != -1)) |
| 600 | { |
| 601 | Retval = pFOTA_T->TrustBootStatus; |
| 602 | pFOTA_T->TrustBootStatus = TB_NO_ERROR; |
| 603 | OTA_Save_Config(pTIM_h); |
| 604 | #if TB_ERROR_DOWNLOAD |
| 605 | obm_printf("Force Download Due to Trust Boot Error: %d\n\r", Retval); |
| 606 | mode = UPGRADESW; |
| 607 | time_count_enable = FALSE; |
| 608 | return mode; |
| 609 | #else |
| 610 | obm_printf("Dead Loop Due to Trust Boot Error: %d\n\r", Retval); |
| 611 | while(1); |
| 612 | #endif |
| 613 | } |
| 614 | #endif |
| 615 | |
| 616 | if ( PlatformUSBPluggedIn() ) |
| 617 | { |
| 618 | obm_printf("USB cable plugged in\n\r"); |
| 619 | if(ASRFlag_InProductionMode(pTIM_h)) |
| 620 | { |
| 621 | if(pOBM2OSL_h->booting_mode != OBMNODL && OBMNODL_RST_FLAG != OBMNODL) |
| 622 | { |
| 623 | mode = UPGRADESW; |
| 624 | time_count_enable = TRUE; // this is active enumeration by OBM if USB is connect, need to set timeout |
| 625 | obm_printf("[PROD]Enum USB port\n\r"); |
| 626 | }else{ |
| 627 | obm_printf("[PROD]Don't enum USB port\n\r"); |
| 628 | } |
| 629 | OBMNODL_RST_FLAG= 0; |
| 630 | } else { |
| 631 | UINT_T DlFlag = BU_REG_READ(OBMDL_DDR_ADDRES); |
| 632 | if(DlFlag == OBMDL) |
| 633 | { |
| 634 | BU_REG_WRITE(OBMDL_DDR_ADDRES, 0x0); |
| 635 | mode = UPGRADESW; |
| 636 | time_count_enable = FALSE; |
| 637 | obm_printf("[Non-Prod]Wait for download(AT)...\n\r"); |
| 638 | }else { |
| 639 | obm_printf("[Non-Prod]Don't enum USB port\n\r"); |
| 640 | } |
| 641 | } |
| 642 | return mode; |
| 643 | } |
| 644 | |
| 645 | #if UPDATE_USE_GPIO |
| 646 | for(loops = 0; loops < 10; loops++) |
| 647 | { |
| 648 | gotkey = PlatformCheckGPIOKey(); |
| 649 | if (gotkey) |
| 650 | break; |
| 651 | } |
| 652 | switch (gotkey) |
| 653 | { |
| 654 | case KEYID_UPGRADESW_REQUEST: |
| 655 | mode = UPGRADESW; |
| 656 | time_count_enable = TRUE; |
| 657 | break; |
| 658 | case KEYID_PRODUCT_USB_MODE_REQUEST: |
| 659 | product_mode_select = PRODUCT_USB_MODE; |
| 660 | obm_printf("Production mode detected\n\r"); |
| 661 | break; |
| 662 | default: |
| 663 | break; |
| 664 | } |
| 665 | #endif |
| 666 | return mode; |
| 667 | } |
| 668 | |
| 669 | |
| 670 | ////////////////////////////////////////////////////////////////////// |
| 671 | // This is the Finalization Setup function for the Boot Loader. |
| 672 | // |
| 673 | // Inputs: A pointer to the fuses and a pointer to the TIM. |
| 674 | // Outputs: NONE. |
| 675 | // |
| 676 | // It mainly functions as following: |
| 677 | // 1) Shut down all the ports. |
| 678 | // 2) Shuts down the security API. |
| 679 | // 3) Finalize Flashes. |
| 680 | // 4) Disable interrupts. |
| 681 | // 5) Restore platform default configuration. |
| 682 | ////////////////////////////////////////////////////////////////////// |
| 683 | void FinalizeSetup(pFUSE_SET pFuses, pTIM pTIM_h ) |
| 684 | { |
| 685 | UINT_T retval = NoError; |
| 686 | |
| 687 | #if TRUSTED |
| 688 | // Shut down the security API. |
| 689 | //if (pFuses->bits.SBE) |
| 690 | { |
| 691 | retval = SecurityShutdown(); |
| 692 | if( retval != NoError) |
| 693 | { |
| 694 | FatalError(retval, "FS", NULL); |
| 695 | } |
| 696 | } |
| 697 | #endif |
| 698 | |
| 699 | // Finalize the Flashes. |
| 700 | Finalize_Flashes(BOOT_FLASH); // this will flush the BBT information if necessary. |
| 701 | |
| 702 | // Disable interrupts. |
| 703 | DisableIrqInterrupts(); |
| 704 | } |
| 705 | |