1 /*
2 *
3 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the
16 * distribution.
17 *
18 * Neither the name of Texas Instruments Incorporated nor the names of
19 * its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
38 /*****************************************************************************************
39 * FILE PURPOSE: Perform the top level boot
40 *****************************************************************************************
41 * FILE NAME: iblmain.c
42 *
43 * DESCRIPTION: The top level boot examines the boot configuration and performs boot
44 * based on this configuration
45 *
46 * @file iblmain.c
47 *
48 * @brief
49 * This file is used to launch a boot based on the boot configuration structure
50 *
51 *****************************************************************************************/
52 #include "ibl.h"
53 #include "iblloc.h"
54 #include "iblcfg.h"
55 #include "device.h"
56 #include "ethboot.h"
57 #include "nandboot.h"
58 #include "norboot.h"
59 #include "bis.h"
60 #include "coffwrap.h"
61 #include "iblbtbl.h"
62 #include "iblblob.h"
63 #include "timer.h"
64 #include "i2c.h"
65 #include "spi_api.h"
66 #include "ibl_elf.h"
67 #include <string.h>
68 #include "uart.h"
70 extern cregister unsigned int IER;
72 uint32 iblEndianIdx = 0;
73 uint32 iblImageIdx = 0;
75 /**
76 * @brief
77 * Data structures shared between the 1st and 2nd stage IBL load
78 * are declared in a single header file, included in both stages
79 */
80 #include "iblStage.h"
84 /* Eat printfs */
85 void mprintf(char *x, ...) { }
87 /**
88 * @b Description
89 * @n
90 *
91 * Returns TRUE if the input priority is valid and enabled
92 */
93 BOOL iblPriorityIsValid (uint32 priority)
94 {
95 if ( (priority >= ibl_HIGHEST_PRIORITY) &&
96 (priority <= ibl_LOWEST_PRIORITY) )
98 return (TRUE);
101 return (FALSE);
103 }
105 /**
106 * @b Description
107 * @n
108 *
109 * Returns TRUE if the mac address is 0
110 */
111 BOOL iblMacAddrIsZero (uint8 *maddr)
112 {
113 int32 i;
115 for (i = 0; i < 6; i++)
116 if (maddr[i] != 0)
117 return (FALSE);
119 return (TRUE);
121 }
123 /**
124 * @b Description
125 * @n
126 *
127 * For NAND and NOR boots, configure the specified peripheral or memory interface
128 */
129 void iblPmemCfg (int32 interface, int32 port, bool enableNand)
130 {
131 int32 ret;
133 switch (interface) {
135 #if (!defined(EXCLUDE_NAND_GPIO))
137 case ibl_PMEM_IF_GPIO:
138 ret = devicePowerPeriph (TARGET_PWR_GPIO);
139 break;
140 #endif
142 #if (!defined(EXCLUDE_NOR_SPI) && !defined(EXCLUDE_NAND_SPI))
144 case ibl_PMEM_IF_SPI: {
146 Uint32 v;
147 spiConfig_t cfg;
149 ret = devicePowerPeriph (TARGET_PWR_SPI);
150 if (ret != 0)
151 break;
153 cfg.port = port;
154 cfg.mode = ibl.spiConfig.mode;
155 cfg.addrWidth = ibl.spiConfig.addrWidth;
156 cfg.npin = ibl.spiConfig.nPins;
157 cfg.csel = ibl.spiConfig.csel;
158 cfg.c2tdelay = ibl.spiConfig.c2tdelay;
160 /* On c66x devices the PLL module has a built in divide by 6, and the SPI
161 * has a maximum clock divider value of 0xff */
162 v = ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz / (DEVICE_SPI_MOD_DIVIDER * ibl.spiConfig.busFreqMHz);
163 if (v > 0xff)
164 v = 0xff;
166 cfg.clkdiv = (UINT16) v;
168 ret = hwSpiConfig (&cfg);
169 if (ret != 0) {
170 iblStatus.iblFail = ibl_FAIL_CODE_SPI_PARAMS;
171 return;
172 }
174 }
175 break;
176 #endif
178 #if (!defined(EXCLUDE_NOR_EMIF) || !defined(EXCLUDE_NAND_EMIF))
180 case ibl_PMEM_IF_CHIPSEL_2:
181 case ibl_PMEM_IF_CHIPSEL_3:
182 case ibl_PMEM_IF_CHIPSEL_4:
183 case ibl_PMEM_IF_CHIPSEL_5: {
185 int i;
187 /* Locate the configuration corresponding to this chip select space */
188 for (i = 0; i < ibl_MAX_EMIF_PMEM; i++)
189 if (ibl.emifConfig[i].csSpace == interface)
190 break;
192 if (i == ibl_MAX_EMIF_PMEM) {
193 iblStatus.iblFail = ibl_FAIL_CODE_NO_EMIF_CFG;
194 return;
195 }
196 #ifdef C665x
197 ret = devicePowerPeriph (TARGET_PWR_EMIF_C6657);
198 #else
199 ret = devicePowerPeriph (TARGET_PWR_EMIF);
200 #endif
201 if (ret != 0)
202 break;
204 if (hwEmif25Init (interface, ibl.emifConfig[i].busWidth, ibl.emifConfig[i].waitEnable, enableNand) != 0)
205 iblStatus.iblFail = ibl_FAIL_CODE_EMIF_CFG_FAIL;
207 }
208 break;
210 #endif
212 default:
216 iblStatus.iblFail = ibl_FAIL_CODE_INVALID_NAND_PERIPH;
217 return;
218 }
220 if (ret != 0) {
221 iblStatus.iblFail = ibl_FAIL_CODE_PERIPH_POWER_UP;
222 return;
223 }
225 }
229 /**
230 * @b Description
231 * @n
232 *
233 * The main function kicks off the boot. If it does not find the magic value in the
234 * configuration array then default values are loaded. This default load
235 * is done only once at the start of boot.
236 *
237 * @retval
238 * None
239 */
240 void main (void)
241 {
242 int32 i, j;
243 UINT32 v, boot_mode_idx, boot_para_idx;
244 unsigned int dip_setting;
246 /* Initialize the status structure */
247 iblMemset (&iblStatus, 0, sizeof(iblStatus_t));
248 iblStatus.iblMagic = ibl_MAGIC_VALUE;
249 iblStatus.iblVersion = ibl_VERSION;
251 /* Init UART */
252 uart_init();
253 uart_write_string("", 0);
254 uart_write_string("IBL version: "ibl_VERSION_STR, 0);
256 /* Power up the timer */
257 devicePowerPeriph (TARGET_PWR_TIMER_0);
259 /* Initialize the system timer (software tracking of the hardware timer state) */
260 timer_init ();
262 /* Load default mac addresses for ethernet boot if requested */
263 for (i = 0; i < ibl_N_BOOT_MODES; i++) {
265 if (ibl.bootModes[i].bootMode == ibl_BOOT_MODE_TFTP) {
267 if (iblMacAddrIsZero (ibl.bootModes[i].u.ethBoot.ethInfo.hwAddress))
269 deviceLoadDefaultEthAddress (ibl.bootModes[i].u.ethBoot.ethInfo.hwAddress);
270 }
271 }
274 /* DDR configuration is device specific */
275 deviceDdrConfig ();
277 /* Try booting forever */
278 for (;;) {
280 #ifndef EXCLUDE_MULTI_BOOT
281 v = DEVICE_REG32_R(DEVICE_JTAG_ID_REG);
282 v &= DEVICE_JTAG_ID_MASK;
283 if (
284 (v == DEVICE_C6678_JTAG_ID_VAL) ||
285 (v == DEVICE_C6670_JTAG_ID_VAL) ||
286 (v == DEVICE_C6657_JTAG_ID_VAL) ||
287 (v == DEVICE_TCI6636K2H_JTAG_ID_VAL)
288 )
289 {
290 IER = 0;
292 /* For C66x devices, check the DEVSTAT register to find which image on which device to boot. */
293 v = DEVICE_REG32_R(DEVICE_REG_DEVSTAT);
295 /* Get the Endianness */
296 if (ibl_N_ENDIANS == 1)
297 {
298 iblEndianIdx = 0;
299 }
300 else
301 {
302 if (v & ibl_ENDIAN_LITTLE)
303 {
304 iblEndianIdx = 0;
305 }
306 else
307 {
308 iblEndianIdx = 1;
309 }
310 }
312 /* Get the boot mode index */
313 boot_para_idx = BOOT_READ_BITFIELD(v,8,4);
315 /* Only 1 image supported for TFTP boot */
316 if (boot_para_idx > (ibl_N_IMAGES*(ibl_N_BOOT_MODES-1)))
317 {
318 /* boot parameter index not supported */
319 continue;
320 }
321 boot_mode_idx = boot_para_idx/ibl_N_IMAGES;
322 /* Get the boot image index */
323 iblImageIdx = boot_para_idx & (ibl_N_IMAGES - 1);
325 iblStatus.activeBoot = ibl.bootModes[boot_mode_idx].bootMode;
327 switch (ibl.bootModes[boot_mode_idx].bootMode)
328 {
329 #ifndef EXCLUDE_ETH
330 case ibl_BOOT_MODE_TFTP:
331 iblStatus.activeDevice = ibl_ACTIVE_DEVICE_ETH;
332 /*Print something to UART, max len=80, if len is pased as 0 UART prints entire string upto '\n' or max len */
333 uart_write_string("IBL: Booting from ethernet",0);
334 iblMemcpy (&iblStatus.ethParams, &ibl.bootModes[boot_mode_idx].u.ethBoot.ethInfo, sizeof(iblEthBootInfo_t));
335 iblEthBoot (boot_mode_idx);
336 break;
337 #endif
339 #if ((!defined(EXCLUDE_NAND_EMIF)) || (!defined(EXCLUDE_NAND_GPIO)))
340 case ibl_BOOT_MODE_NAND:
341 iblPmemCfg (ibl.bootModes[boot_mode_idx].u.nandBoot.interface, ibl.bootModes[boot_mode_idx].port, TRUE);
342 memset ((void *)0x80000000, 0, 0x20000000);
343 /*Print something to UART, max len=80, if len is pased as 0 UART prints entire string upto '\n' or max len */
344 uart_write_string("IBL: Booting from NAND",0);
345 iblNandBoot (boot_mode_idx);
346 break;
347 #endif
349 #if (!defined(EXCLUDE_NOR_EMIF) && !defined(EXCLUDE_NOR_SPI))
350 case ibl_BOOT_MODE_NOR:
351 iblPmemCfg (ibl.bootModes[boot_mode_idx].u.norBoot.interface, ibl.bootModes[boot_mode_idx].port, TRUE);
352 /*Print something to UART, max len=80, if len is pased as 0 UART prints entire string upto '\n' or max len */
353 uart_write_string("IBL: Booting from NOR",0);
354 iblNorBoot (boot_mode_idx);
355 break;
356 #endif
357 }
358 iblStatus.heartBeat += 1;
359 }
360 #else
362 dip_setting = get_device_switch_setting();
364 if (dip_setting == 0)
365 boot_mode_idx = 0;
366 else if (dip_setting == 1)
367 boot_mode_idx = 1;
369 iblStatus.activeBoot = ibl.bootModes[boot_mode_idx].bootMode;
371 switch (ibl.bootModes[boot_mode_idx].bootMode) {
372 #ifndef EXCLUDE_ETH
373 case ibl_BOOT_MODE_TFTP:
374 iblStatus.activeDevice = ibl_ACTIVE_DEVICE_ETH;
375 iblMemcpy (&iblStatus.ethParams, &ibl.bootModes[boot_mode_idx].u.ethBoot.ethInfo, sizeof(iblEthBootInfo_t));
376 /*Print something to UART, max len=80, if len is pased as 0 UART prints entire string upto '\n' or max len */
377 uart_write_string("IBL: Booting from Ethernet",0);
378 iblEthBoot (boot_mode_idx);
379 break;
380 #endif
382 #if ((!defined(EXCLUDE_NAND_EMIF)) || (!defined(EXCLUDE_NAND_GPIO)))
383 case ibl_BOOT_MODE_NAND:
384 iblPmemCfg (ibl.bootModes[boot_mode_idx].u.nandBoot.interface, ibl.bootModes[boot_mode_idx].port, TRUE);
385 /*Print something to UART, max len=80, if len is pased as 0 UART prints entire string upto '\n' or max len */
386 uart_write_string("IBL: Booting from NAND",0);
387 iblNandBoot (boot_mode_idx);
388 break;
389 #endif
390 }
391 iblStatus.heartBeat += 1;
392 #endif
394 }
395 } /* main */
399 /**
400 * @b Description
401 * @n
402 *
403 * The ibl boot function links a device to a data format. The data format
404 * parser pulls data from the boot device
405 *
406 * @param[in] bootFxn The structure containing the boot device functions
407 *
408 * @retval
409 * None
410 */
411 Uint32 iblBoot (BOOT_MODULE_FXN_TABLE *bootFxn, Int32 dataFormat, void *formatParams)
412 {
413 Uint32 entry = 0;
414 Uint32 value32;
415 Uint8 dataBuf[4];
416 Uint16 value16;
418 /* Determine the data format if required */
419 if (dataFormat == ibl_BOOT_FORMAT_AUTO) {
421 (*bootFxn->peek)(dataBuf, sizeof(dataBuf));
422 value32 = (dataBuf[0] << 24) | (dataBuf[1] << 16) | (dataBuf[2] << 8) | (dataBuf[3] << 0);
423 value16 = (dataBuf[0] << 8) | (dataBuf[1] << 0);
425 /* BIS */
426 #ifndef EXCLUDE_BIS
427 if (value32 == BIS_MAGIC_NUMBER)
428 dataFormat = ibl_BOOT_FORMAT_BIS;
429 #endif
431 #ifndef EXCLUDE_COFF
432 if (iblIsCoff (value16))
433 dataFormat = ibl_BOOT_FORMAT_COFF;
434 #endif
436 #ifndef EXCLUDE_ELF
437 if (iblIsElf (dataBuf))
438 dataFormat = ibl_BOOT_FORMAT_ELF;
439 #endif
441 if (dataFormat == ibl_BOOT_FORMAT_AUTO) {
442 iblStatus.autoDetectFailCnt += 1;
443 return (0);
444 }
445 }
448 iblStatus.activeFileFormat = dataFormat;
451 /* Invoke the parser */
452 switch (dataFormat) {
454 #ifndef EXCLUDE_BIS
455 case ibl_BOOT_FORMAT_BIS:
456 iblBootBis (bootFxn, &entry);
457 break;
458 #endif
460 #ifndef EXCLUDE_COFF
461 case ibl_BOOT_FORMAT_COFF:
462 iblBootCoff (bootFxn, &entry);
463 break;
464 #endif
466 case ibl_BOOT_FORMAT_BTBL:
467 iblBootBtbl (bootFxn, &entry);
468 break;
470 #ifndef EXCLUDE_BLOB
471 case ibl_BOOT_FORMAT_BBLOB:
472 iblBootBlob (bootFxn, &entry, formatParams);
473 break;
474 #endif
476 #ifndef EXCLUDE_ELF
477 case ibl_BOOT_FORMAT_ELF:
478 iblBootElf (bootFxn, &entry);
479 break;
480 #endif
482 default:
483 iblStatus.invalidDataFormatSpec += 1;
484 break;
486 }
489 return (entry);
491 }