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 /**
72 * @brief
73 * Data structures shared between the 1st and 2nd stage IBL load
74 * are declared in a single header file, included in both stages
75 */
76 #include "iblStage.h"
80 /* Eat printfs */
81 void mprintf(char *x, ...) { }
83 /**
84 * @b Description
85 * @n
86 *
87 * Returns TRUE if the input priority is valid and enabled
88 */
89 BOOL iblPriorityIsValid (uint32 priority)
90 {
91 if ( (priority >= ibl_HIGHEST_PRIORITY) &&
92 (priority <= ibl_LOWEST_PRIORITY) )
94 return (TRUE);
97 return (FALSE);
99 }
101 /**
102 * @b Description
103 * @n
104 *
105 * Returns TRUE if the mac address is 0
106 */
107 BOOL iblMacAddrIsZero (uint8 *maddr)
108 {
109 int32 i;
111 for (i = 0; i < 6; i++)
112 if (maddr[i] != 0)
113 return (FALSE);
115 return (TRUE);
117 }
119 /**
120 * @b Description
121 * @n
122 *
123 * For NAND and NOR boots, configure the specified peripheral or memory interface
124 */
125 void iblPmemCfg (int32 interface, int32 port, bool enableNand)
126 {
127 int32 ret;
129 switch (interface) {
131 #if (!defined(EXCLUDE_NAND_GPIO))
133 case ibl_PMEM_IF_GPIO:
134 ret = devicePowerPeriph (TARGET_PWR_GPIO);
135 break;
136 #endif
138 #if (!defined(EXCLUDE_NOR_SPI) && !defined(EXCLUDE_NAND_SPI))
140 case ibl_PMEM_IF_SPI: {
142 Uint32 v;
143 spiConfig_t cfg;
145 ret = devicePowerPeriph (TARGET_PWR_SPI);
146 if (ret != 0)
147 break;
149 cfg.port = port;
150 cfg.mode = ibl.spiConfig.mode;
151 cfg.addrWidth = ibl.spiConfig.addrWidth;
152 cfg.npin = ibl.spiConfig.nPins;
153 cfg.csel = ibl.spiConfig.csel;
154 cfg.c2tdelay = ibl.spiConfig.c2tdelay;
156 /* On c661x devices the PLL module has a built in divide by 6, and the SPI
157 * has a maximum clock divider value of 0xff */
158 v = ibl.pllConfig[ibl_MAIN_PLL].pllOutFreqMhz / (DEVICE_SPI_MOD_DIVIDER * ibl.spiConfig.busFreqMHz);
159 if (v > 0xff)
160 v = 0xff;
162 cfg.clkdiv = (UINT16) v;
164 ret = hwSpiConfig (&cfg);
165 if (ret != 0) {
166 iblStatus.iblFail = ibl_FAIL_CODE_SPI_PARAMS;
167 return;
168 }
170 }
171 break;
172 #endif
174 #if (!defined(EXCLUDE_NOR_EMIF) || !defined(EXCLUDE_NAND_EMIF))
176 case ibl_PMEM_IF_CHIPSEL_2:
177 case ibl_PMEM_IF_CHIPSEL_3:
178 case ibl_PMEM_IF_CHIPSEL_4:
179 case ibl_PMEM_IF_CHIPSEL_5: {
181 int i;
183 /* Locate the configuration corresponding to this chip select space */
184 for (i = 0; i < ibl_MAX_EMIF_PMEM; i++)
185 if (ibl.emifConfig[i].csSpace == interface)
186 break;
188 if (i == ibl_MAX_EMIF_PMEM) {
189 iblStatus.iblFail = ibl_FAIL_CODE_NO_EMIF_CFG;
190 return;
191 }
193 ret = devicePowerPeriph (TARGET_PWR_EMIF);
194 if (ret != 0)
195 break;
197 if (hwEmif25Init (interface, ibl.emifConfig[i].busWidth, ibl.emifConfig[i].waitEnable, enableNand) != 0)
198 iblStatus.iblFail = ibl_FAIL_CODE_EMIF_CFG_FAIL;
200 }
201 break;
203 #endif
205 default:
209 iblStatus.iblFail = ibl_FAIL_CODE_INVALID_NAND_PERIPH;
210 return;
211 }
213 if (ret != 0) {
214 iblStatus.iblFail = ibl_FAIL_CODE_PERIPH_POWER_UP;
215 return;
216 }
218 }
222 /**
223 * @b Description
224 * @n
225 *
226 * The main function kicks off the boot. If it does not find the magic value in the
227 * configuration array then default values are loaded. This default load
228 * is done only once at the start of boot.
229 *
230 * @retval
231 * None
232 */
233 void main (void)
234 {
235 int32 i, j;
236 UINT32 v;
238 /* Initialize the status structure */
239 iblMemset (&iblStatus, 0, sizeof(iblStatus_t));
240 iblStatus.iblMagic = ibl_MAGIC_VALUE;
241 iblStatus.iblVersion = ibl_VERSION;
244 /* Power up the timer */
245 devicePowerPeriph (TARGET_PWR_TIMER_0);
247 /* Initialize the system timer (software tracking of the hardware timer state) */
248 timer_init ();
250 /* Load default mac addresses for ethernet boot if requested */
251 for (i = 0; i < ibl_N_BOOT_MODES; i++) {
253 if (ibl.bootModes[i].bootMode == ibl_BOOT_MODE_TFTP) {
255 if (iblMacAddrIsZero (ibl.bootModes[i].u.ethBoot.ethInfo.hwAddress))
257 deviceLoadDefaultEthAddress (ibl.bootModes[i].u.ethBoot.ethInfo.hwAddress);
258 }
259 }
262 /* DDR configuration is device specific */
263 deviceDdrConfig ();
265 /* Try booting forever */
266 for (;;) {
267 v = DEVICE_REG32_R(DEVICE_JTAG_ID_REG);
268 if (
269 (v == DEVICE_C6618_JTAG_ID_VAL) ||
270 (v == DEVICE_C6616_JTAG_ID_VAL)
271 )
272 {
273 /* Disable interrupts, HUA does not work if IER is not cleared */
274 IER = 0;
275 }
277 /* Start looping through the boot modes to find the one with the highest priority
278 * value, and try to boot it. */
279 for (i = ibl_HIGHEST_PRIORITY; i < ibl_LOWEST_PRIORITY; i++) {
281 for (j = 0; j < ibl_N_BOOT_MODES; j++) {
283 if (ibl.bootModes[j].priority == i) {
285 iblStatus.activeBoot = ibl.bootModes[j].bootMode;
287 switch (ibl.bootModes[j].bootMode) {
290 #ifndef EXCLUDE_ETH
291 case ibl_BOOT_MODE_TFTP:
292 iblStatus.activeDevice = ibl_ACTIVE_DEVICE_ETH;
293 iblMemcpy (&iblStatus.ethParams, &ibl.bootModes[j].u.ethBoot.ethInfo, sizeof(iblEthBootInfo_t));
294 iblEthBoot (j);
295 break;
296 #endif
298 #if ((!defined(EXCLUDE_NAND_EMIF)) )
299 case ibl_BOOT_MODE_NAND:
300 iblPmemCfg (ibl.bootModes[j].u.nandBoot.interface, ibl.bootModes[j].port, TRUE);
301 iblNandBoot (j);
302 break;
303 #endif
305 #if (!defined(EXCLUDE_NOR_EMIF) && !defined(EXCLUDE_NOR_SPI))
306 case ibl_BOOT_MODE_NOR:
307 iblPmemCfg (ibl.bootModes[j].u.norBoot.interface, ibl.bootModes[j].port, TRUE);
308 iblNorBoot (j);
309 break;
310 #endif
312 }
313 }
315 iblStatus.heartBeat += 1;
317 }
318 }
320 }
323 } /* main */
327 /**
328 * @b Description
329 * @n
330 *
331 * The ibl boot function links a device to a data format. The data format
332 * parser pulls data from the boot device
333 *
334 * @param[in] bootFxn The structure containing the boot device functions
335 *
336 * @retval
337 * None
338 */
339 Uint32 iblBoot (BOOT_MODULE_FXN_TABLE *bootFxn, Int32 dataFormat, void *formatParams)
340 {
341 Uint32 entry = 0;
342 Uint32 value32;
343 Uint8 dataBuf[4];
344 Uint16 value16;
346 /* Determine the data format if required */
347 if (dataFormat == ibl_BOOT_FORMAT_AUTO) {
349 (*bootFxn->peek)(dataBuf, sizeof(dataBuf));
350 value32 = (dataBuf[0] << 24) | (dataBuf[1] << 16) | (dataBuf[2] << 8) | (dataBuf[3] << 0);
351 value16 = (dataBuf[0] << 8) | (dataBuf[1] << 0);
353 /* BIS */
354 #ifndef EXCLUDE_BIS
355 if (value32 == BIS_MAGIC_NUMBER)
356 dataFormat = ibl_BOOT_FORMAT_BIS;
357 #endif
359 #ifndef EXCLUDE_COFF
360 if (iblIsCoff (value16))
361 dataFormat = ibl_BOOT_FORMAT_COFF;
362 #endif
364 #ifndef EXCLUDE_ELF
365 if (iblIsElf (dataBuf))
366 dataFormat = ibl_BOOT_FORMAT_ELF;
367 #endif
369 if (dataFormat == ibl_BOOT_FORMAT_AUTO) {
370 iblStatus.autoDetectFailCnt += 1;
371 return (0);
372 }
373 }
376 iblStatus.activeFileFormat = dataFormat;
379 /* Invoke the parser */
380 switch (dataFormat) {
382 #ifndef EXCLUDE_BIS
383 case ibl_BOOT_FORMAT_BIS:
384 iblBootBis (bootFxn, &entry);
385 break;
386 #endif
388 #ifndef EXCLUDE_COFF
389 case ibl_BOOT_FORMAT_COFF:
390 iblBootCoff (bootFxn, &entry);
391 break;
392 #endif
394 case ibl_BOOT_FORMAT_BTBL:
395 iblBootBtbl (bootFxn, &entry);
396 break;
398 #ifndef EXCLUDE_BLOB
399 case ibl_BOOT_FORMAT_BBLOB:
400 iblBootBlob (bootFxn, &entry, formatParams);
401 break;
402 #endif
404 #ifndef EXCLUDE_ELF
405 case ibl_BOOT_FORMAT_ELF:
406 iblBootElf (bootFxn, &entry);
407 break;
408 #endif
410 default:
411 iblStatus.invalidDataFormatSpec += 1;
412 break;
414 }
417 return (entry);
419 }