1c5a20b08b23c631b4d89dd74ec25d2c453d8194
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>
69 extern cregister unsigned int IER;
71 uint32 iblEndianIdx = 0;
72 uint32 iblImageIdx = 0;
74 /**
75 * @brief
76 * Data structures shared between the 1st and 2nd stage IBL load
77 * are declared in a single header file, included in both stages
78 */
79 #include "iblStage.h"
83 /* Eat printfs */
84 void mprintf(char *x, ...) { }
86 /**
87 * @b Description
88 * @n
89 *
90 * Returns TRUE if the input priority is valid and enabled
91 */
92 BOOL iblPriorityIsValid (uint32 priority)
93 {
94 if ( (priority >= ibl_HIGHEST_PRIORITY) &&
95 (priority <= ibl_LOWEST_PRIORITY) )
97 return (TRUE);
100 return (FALSE);
102 }
104 /**
105 * @b Description
106 * @n
107 *
108 * Returns TRUE if the mac address is 0
109 */
110 BOOL iblMacAddrIsZero (uint8 *maddr)
111 {
112 int32 i;
114 for (i = 0; i < 6; i++)
115 if (maddr[i] != 0)
116 return (FALSE);
118 return (TRUE);
120 }
122 /**
123 * @b Description
124 * @n
125 *
126 * For NAND and NOR boots, configure the specified peripheral or memory interface
127 */
128 void iblPmemCfg (int32 interface, int32 port, bool enableNand)
129 {
130 int32 ret;
132 switch (interface) {
134 #if (!defined(EXCLUDE_NAND_GPIO))
136 case ibl_PMEM_IF_GPIO:
137 ret = devicePowerPeriph (TARGET_PWR_GPIO);
138 break;
139 #endif
141 #if (!defined(EXCLUDE_NOR_SPI) && !defined(EXCLUDE_NAND_SPI))
143 case ibl_PMEM_IF_SPI: {
145 Uint32 v;
146 spiConfig_t cfg;
148 ret = devicePowerPeriph (TARGET_PWR_SPI);
149 if (ret != 0)
150 break;
152 cfg.port = port;
153 cfg.mode = ibl.spiConfig.mode;
154 cfg.addrWidth = ibl.spiConfig.addrWidth;
155 cfg.npin = ibl.spiConfig.nPins;
156 cfg.csel = ibl.spiConfig.csel;
157 cfg.c2tdelay = ibl.spiConfig.c2tdelay;
159 /* On c661x devices the PLL module has a built in divide by 6, and the SPI
160 * has a maximum clock divider value of 0xff */
161 v = ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz / (DEVICE_SPI_MOD_DIVIDER * ibl.spiConfig.busFreqMHz);
162 if (v > 0xff)
163 v = 0xff;
165 cfg.clkdiv = (UINT16) v;
167 ret = hwSpiConfig (&cfg);
168 if (ret != 0) {
169 iblStatus.iblFail = ibl_FAIL_CODE_SPI_PARAMS;
170 return;
171 }
173 }
174 break;
175 #endif
177 #if (!defined(EXCLUDE_NOR_EMIF) || !defined(EXCLUDE_NAND_EMIF))
179 case ibl_PMEM_IF_CHIPSEL_2:
180 case ibl_PMEM_IF_CHIPSEL_3:
181 case ibl_PMEM_IF_CHIPSEL_4:
182 case ibl_PMEM_IF_CHIPSEL_5: {
184 int i;
186 /* Locate the configuration corresponding to this chip select space */
187 for (i = 0; i < ibl_MAX_EMIF_PMEM; i++)
188 if (ibl.emifConfig[i].csSpace == interface)
189 break;
191 if (i == ibl_MAX_EMIF_PMEM) {
192 iblStatus.iblFail = ibl_FAIL_CODE_NO_EMIF_CFG;
193 return;
194 }
196 ret = devicePowerPeriph (TARGET_PWR_EMIF);
197 if (ret != 0)
198 break;
200 if (hwEmif25Init (interface, ibl.emifConfig[i].busWidth, ibl.emifConfig[i].waitEnable, enableNand) != 0)
201 iblStatus.iblFail = ibl_FAIL_CODE_EMIF_CFG_FAIL;
203 }
204 break;
206 #endif
208 default:
212 iblStatus.iblFail = ibl_FAIL_CODE_INVALID_NAND_PERIPH;
213 return;
214 }
216 if (ret != 0) {
217 iblStatus.iblFail = ibl_FAIL_CODE_PERIPH_POWER_UP;
218 return;
219 }
221 }
225 /**
226 * @b Description
227 * @n
228 *
229 * The main function kicks off the boot. If it does not find the magic value in the
230 * configuration array then default values are loaded. This default load
231 * is done only once at the start of boot.
232 *
233 * @retval
234 * None
235 */
236 void main (void)
237 {
238 int32 i, j;
239 UINT32 v, boot_mode_idx, boot_para_idx;
241 /* Initialize the status structure */
242 iblMemset (&iblStatus, 0, sizeof(iblStatus_t));
243 iblStatus.iblMagic = ibl_MAGIC_VALUE;
244 iblStatus.iblVersion = ibl_VERSION;
247 /* Power up the timer */
248 devicePowerPeriph (TARGET_PWR_TIMER_0);
250 /* Initialize the system timer (software tracking of the hardware timer state) */
251 timer_init ();
253 /* Load default mac addresses for ethernet boot if requested */
254 for (i = 0; i < ibl_N_BOOT_MODES; i++) {
256 if (ibl.bootModes[i].bootMode == ibl_BOOT_MODE_TFTP) {
258 if (iblMacAddrIsZero (ibl.bootModes[i].u.ethBoot.ethInfo.hwAddress))
260 deviceLoadDefaultEthAddress (ibl.bootModes[i].u.ethBoot.ethInfo.hwAddress);
261 }
262 }
265 /* DDR configuration is device specific */
266 deviceDdrConfig ();
268 /* Try booting forever */
269 for (;;) {
271 #ifndef EXCLUDE_MULTI_BOOT
272 v = DEVICE_REG32_R(DEVICE_JTAG_ID_REG);
273 v &= DEVICE_JTAG_ID_MASK;
274 if (
275 (v == DEVICE_C6678_JTAG_ID_VAL) ||
276 (v == DEVICE_C6670_JTAG_ID_VAL)
277 )
278 {
279 IER = 0;
281 /* For C66x devices, check the DEVSTAT register to find which image on which device to boot. */
282 v = DEVICE_REG32_R(DEVICE_REG_DEVSTAT);
284 /* Get the Endianness */
285 if (ibl_N_ENDIANS == 1)
286 {
287 iblEndianIdx = 0;
288 }
289 else
290 {
291 if (v & ibl_ENDIAN_LITTLE)
292 {
293 iblEndianIdx = 0;
294 }
295 else
296 {
297 iblEndianIdx = 1;
298 }
299 }
301 /* Get the boot mode index */
302 boot_para_idx = BOOT_READ_BITFIELD(v,8,4);
304 /* Only 1 image supported for TFTP boot */
305 if (boot_para_idx > (ibl_N_IMAGES*(ibl_N_BOOT_MODES-1)))
306 {
307 /* boot parameter index not supported */
308 continue;
309 }
310 boot_mode_idx = boot_para_idx/ibl_N_IMAGES;
311 /* Get the boot image index */
312 iblImageIdx == boot_para_idx & (ibl_N_IMAGES - 1);
314 iblStatus.activeBoot = ibl.bootModes[boot_mode_idx].bootMode;
316 switch (ibl.bootModes[boot_mode_idx].bootMode)
317 {
318 #ifndef EXCLUDE_ETH
319 case ibl_BOOT_MODE_TFTP:
320 iblStatus.activeDevice = ibl_ACTIVE_DEVICE_ETH;
321 iblMemcpy (&iblStatus.ethParams, &ibl.bootModes[boot_mode_idx].u.ethBoot.ethInfo, sizeof(iblEthBootInfo_t));
322 iblEthBoot (boot_mode_idx);
323 break;
324 #endif
326 #if ((!defined(EXCLUDE_NAND_EMIF)) || (!defined(EXCLUDE_NAND_GPIO)))
327 case ibl_BOOT_MODE_NAND:
328 iblPmemCfg (ibl.bootModes[boot_mode_idx].u.nandBoot.interface, ibl.bootModes[boot_mode_idx].port, TRUE);
329 memset ((void *)0x80000000, 0, 0x20000000);
330 iblNandBoot (boot_mode_idx);
331 break;
332 #endif
334 #if (!defined(EXCLUDE_NOR_EMIF) && !defined(EXCLUDE_NOR_SPI))
335 case ibl_BOOT_MODE_NOR:
336 iblPmemCfg (ibl.bootModes[boot_mode_idx].u.norBoot.interface, ibl.bootModes[boot_mode_idx].port, TRUE);
337 iblNorBoot (boot_mode_idx);
338 break;
339 #endif
340 }
341 iblStatus.heartBeat += 1;
342 }
343 else
344 #endif
345 {
347 /* For C64x devices, loop through the boot modes to find the one with the highest priority
348 * value, and try to boot it. */
349 for (i = ibl_HIGHEST_PRIORITY; i < ibl_LOWEST_PRIORITY; i++) {
351 for (j = 0; j < ibl_N_BOOT_MODES; j++) {
353 if (ibl.bootModes[j].priority == i) {
355 iblStatus.activeBoot = ibl.bootModes[j].bootMode;
357 switch (ibl.bootModes[j].bootMode) {
360 #ifndef EXCLUDE_ETH
361 case ibl_BOOT_MODE_TFTP:
362 iblStatus.activeDevice = ibl_ACTIVE_DEVICE_ETH;
363 iblMemcpy (&iblStatus.ethParams, &ibl.bootModes[j].u.ethBoot.ethInfo, sizeof(iblEthBootInfo_t));
364 iblEthBoot (j);
365 break;
366 #endif
368 #if ((!defined(EXCLUDE_NAND_EMIF)) || (!defined(EXCLUDE_NAND_GPIO)))
369 case ibl_BOOT_MODE_NAND:
370 iblPmemCfg (ibl.bootModes[j].u.nandBoot.interface, ibl.bootModes[j].port, TRUE);
371 iblNandBoot (j);
372 break;
373 #endif
375 #if (!defined(EXCLUDE_NOR_EMIF) && !defined(EXCLUDE_NOR_SPI))
376 case ibl_BOOT_MODE_NOR:
377 iblPmemCfg (ibl.bootModes[j].u.norBoot.interface, ibl.bootModes[j].port, TRUE);
378 iblNorBoot (j);
379 break;
380 #endif
382 }
383 }
385 iblStatus.heartBeat += 1;
387 }
388 }
389 }
390 }
393 } /* main */
397 /**
398 * @b Description
399 * @n
400 *
401 * The ibl boot function links a device to a data format. The data format
402 * parser pulls data from the boot device
403 *
404 * @param[in] bootFxn The structure containing the boot device functions
405 *
406 * @retval
407 * None
408 */
409 Uint32 iblBoot (BOOT_MODULE_FXN_TABLE *bootFxn, Int32 dataFormat, void *formatParams)
410 {
411 Uint32 entry = 0;
412 Uint32 value32;
413 Uint8 dataBuf[4];
414 Uint16 value16;
416 /* Determine the data format if required */
417 if (dataFormat == ibl_BOOT_FORMAT_AUTO) {
419 (*bootFxn->peek)(dataBuf, sizeof(dataBuf));
420 value32 = (dataBuf[0] << 24) | (dataBuf[1] << 16) | (dataBuf[2] << 8) | (dataBuf[3] << 0);
421 value16 = (dataBuf[0] << 8) | (dataBuf[1] << 0);
423 /* BIS */
424 #ifndef EXCLUDE_BIS
425 if (value32 == BIS_MAGIC_NUMBER)
426 dataFormat = ibl_BOOT_FORMAT_BIS;
427 #endif
429 #ifndef EXCLUDE_COFF
430 if (iblIsCoff (value16))
431 dataFormat = ibl_BOOT_FORMAT_COFF;
432 #endif
434 #ifndef EXCLUDE_ELF
435 if (iblIsElf (dataBuf))
436 dataFormat = ibl_BOOT_FORMAT_ELF;
437 #endif
439 if (dataFormat == ibl_BOOT_FORMAT_AUTO) {
440 iblStatus.autoDetectFailCnt += 1;
441 return (0);
442 }
443 }
446 iblStatus.activeFileFormat = dataFormat;
449 /* Invoke the parser */
450 switch (dataFormat) {
452 #ifndef EXCLUDE_BIS
453 case ibl_BOOT_FORMAT_BIS:
454 iblBootBis (bootFxn, &entry);
455 break;
456 #endif
458 #ifndef EXCLUDE_COFF
459 case ibl_BOOT_FORMAT_COFF:
460 iblBootCoff (bootFxn, &entry);
461 break;
462 #endif
464 case ibl_BOOT_FORMAT_BTBL:
465 iblBootBtbl (bootFxn, &entry);
466 break;
468 #ifndef EXCLUDE_BLOB
469 case ibl_BOOT_FORMAT_BBLOB:
470 iblBootBlob (bootFxn, &entry, formatParams);
471 break;
472 #endif
474 #ifndef EXCLUDE_ELF
475 case ibl_BOOT_FORMAT_ELF:
476 iblBootElf (bootFxn, &entry);
477 break;
478 #endif
480 default:
481 iblStatus.invalidDataFormatSpec += 1;
482 break;
484 }
487 return (entry);
489 }