fa0b61b9d6336e5415c0781f28a4e19ff4bd412c
[keystone-rtos/ibl.git] / src / main / iblmain.c
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)
109     int32 i;
111     for (i = 0; i < 6; i++)
112         if (maddr[i] != 0)
113             return (FALSE);
115     return (TRUE);
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)
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;
187                         
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     }
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)
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 */
326     
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     }
415     
417     return (entry);