Corrected merge for 6657 ibl
[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>
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);
105 /**
106  * @b Description
107  * @n
108  *
109  *  Returns TRUE if the mac address is 0
110  */
111 BOOL iblMacAddrIsZero (uint8 *maddr)
113     int32 i;
115     for (i = 0; i < 6; i++)
116         if (maddr[i] != 0)
117             return (FALSE);
119     return (TRUE);
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)
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;
191                         
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     }
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)
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            )
288         {
289             IER = 0;
291             /* For C66x devices, check the DEVSTAT register to find which image on which device to boot. */
292             v = DEVICE_REG32_R(DEVICE_REG_DEVSTAT);
293             
294             /* Get the Endianness */
295             if (ibl_N_ENDIANS == 1)
296             {
297                 iblEndianIdx = 0;
298             }
299             else
300             {
301                 if (v & ibl_ENDIAN_LITTLE)
302                 {
303                     iblEndianIdx = 0;
304                 }
305                 else
306                 {
307                     iblEndianIdx = 1;
308                 }
309             }
311             /* Get the boot mode index */
312             boot_para_idx = BOOT_READ_BITFIELD(v,8,4);
314             /* Only 1 image supported for TFTP boot */
315             if (boot_para_idx > (ibl_N_IMAGES*(ibl_N_BOOT_MODES-1)))
316             {
317                 /* boot parameter index not supported */
318                 continue;
319             }
320             boot_mode_idx = boot_para_idx/ibl_N_IMAGES;
321             /* Get the boot image index */
322             iblImageIdx = boot_para_idx & (ibl_N_IMAGES - 1);
324             iblStatus.activeBoot = ibl.bootModes[boot_mode_idx].bootMode;
326             switch (ibl.bootModes[boot_mode_idx].bootMode)  
327             {
328 #ifndef EXCLUDE_ETH
329             case ibl_BOOT_MODE_TFTP:
330                 iblStatus.activeDevice = ibl_ACTIVE_DEVICE_ETH;
331                 /*Print something to UART, max len=80, if len is pased as 0 UART prints entire string upto '\n' or max len */
332                 uart_write_string("IBL: Booting from ethernet",0);
333                 iblMemcpy (&iblStatus.ethParams, &ibl.bootModes[boot_mode_idx].u.ethBoot.ethInfo, sizeof(iblEthBootInfo_t));
334                 iblEthBoot (boot_mode_idx);
335                 break;
336 #endif
337                 
338 #if ((!defined(EXCLUDE_NAND_EMIF)) || (!defined(EXCLUDE_NAND_GPIO)))
339             case ibl_BOOT_MODE_NAND:
340                 iblPmemCfg (ibl.bootModes[boot_mode_idx].u.nandBoot.interface, ibl.bootModes[boot_mode_idx].port, TRUE);
341                 memset ((void *)0x80000000, 0, 0x20000000);
342                 /*Print something to UART, max len=80, if len is pased as 0 UART prints entire string upto '\n' or max len */
343                 uart_write_string("IBL: Booting from NAND",0);
344                 iblNandBoot (boot_mode_idx);
345                 break;
346 #endif
347                 
348 #if (!defined(EXCLUDE_NOR_EMIF) && !defined(EXCLUDE_NOR_SPI))
349             case ibl_BOOT_MODE_NOR:
350                 iblPmemCfg (ibl.bootModes[boot_mode_idx].u.norBoot.interface, ibl.bootModes[boot_mode_idx].port, TRUE);
351                 /*Print something to UART, max len=80, if len is pased as 0 UART prints entire string upto '\n' or max len */
352                 uart_write_string("IBL: Booting from NOR",0);
353                 iblNorBoot (boot_mode_idx);
354                 break;
355 #endif
356             }
357             iblStatus.heartBeat += 1;
358         }
359 #else
361         dip_setting = get_device_switch_setting();
362         
363         if (dip_setting == 0)
364                 boot_mode_idx = 0;
365         else if (dip_setting == 1)
366                 boot_mode_idx = 1;
367         
368         iblStatus.activeBoot = ibl.bootModes[boot_mode_idx].bootMode;
369         
370         switch (ibl.bootModes[boot_mode_idx].bootMode) {                            
371 #ifndef EXCLUDE_ETH
372                 case ibl_BOOT_MODE_TFTP:
373                         iblStatus.activeDevice = ibl_ACTIVE_DEVICE_ETH;
374                         iblMemcpy (&iblStatus.ethParams, &ibl.bootModes[boot_mode_idx].u.ethBoot.ethInfo, sizeof(iblEthBootInfo_t));
375                         /*Print something to UART, max len=80, if len is pased as 0 UART prints entire string upto '\n' or max len */
376                         uart_write_string("IBL: Booting from Ethernet",0);
377                         iblEthBoot (boot_mode_idx);
378                         break;
379 #endif
380                             
381 #if ((!defined(EXCLUDE_NAND_EMIF)) || (!defined(EXCLUDE_NAND_GPIO)))
382                 case ibl_BOOT_MODE_NAND:
383                         iblPmemCfg (ibl.bootModes[boot_mode_idx].u.nandBoot.interface, ibl.bootModes[boot_mode_idx].port, TRUE);
384                         /*Print something to UART, max len=80, if len is pased as 0 UART prints entire string upto '\n' or max len */
385                         uart_write_string("IBL: Booting from NAND",0);
386                         iblNandBoot (boot_mode_idx);
387                         break;
388 #endif
389         }
390         iblStatus.heartBeat += 1;
391 #endif
393     }
394 } /* main */
397     
398 /**
399  * @b Description
400  * @n
401  * 
402  * The ibl boot function links a device to a data format. The data format
403  * parser pulls data from the boot device
404  *
405  * @param[in] bootFxn      The structure containing the boot device functions
406  *
407  * @retval
408  *  None
409  */
410 Uint32 iblBoot (BOOT_MODULE_FXN_TABLE *bootFxn, Int32 dataFormat, void *formatParams)
411
412     Uint32  entry = 0;
413     Uint32  value32;
414     Uint8   dataBuf[4];   
415     Uint16  value16;
417     /* Determine the data format if required */
418     if (dataFormat == ibl_BOOT_FORMAT_AUTO)  {
420         (*bootFxn->peek)(dataBuf, sizeof(dataBuf));
421         value32 = (dataBuf[0] << 24) | (dataBuf[1] << 16) | (dataBuf[2] << 8) | (dataBuf[3] << 0);
422         value16 = (dataBuf[0] <<  8) | (dataBuf[1] <<  0);
424         /* BIS */
425 #ifndef EXCLUDE_BIS
426         if (value32 == BIS_MAGIC_NUMBER)
427             dataFormat = ibl_BOOT_FORMAT_BIS;
428 #endif
430 #ifndef EXCLUDE_COFF
431         if (iblIsCoff (value16))
432             dataFormat = ibl_BOOT_FORMAT_COFF;
433 #endif
435 #ifndef EXCLUDE_ELF
436         if (iblIsElf (dataBuf))
437             dataFormat = ibl_BOOT_FORMAT_ELF;
438 #endif
440         if (dataFormat == ibl_BOOT_FORMAT_AUTO)  {
441             iblStatus.autoDetectFailCnt += 1;
442             return (0);
443         }
444     }        
447     iblStatus.activeFileFormat = dataFormat;
450     /* Invoke the parser */
451     switch (dataFormat)  {
453 #ifndef EXCLUDE_BIS
454         case ibl_BOOT_FORMAT_BIS:
455             iblBootBis (bootFxn, &entry);
456             break;
457 #endif
459 #ifndef EXCLUDE_COFF
460         case ibl_BOOT_FORMAT_COFF:
461             iblBootCoff (bootFxn, &entry);
462             break;
463 #endif
465         case ibl_BOOT_FORMAT_BTBL:
466             iblBootBtbl (bootFxn, &entry);
467             break;
469 #ifndef EXCLUDE_BLOB
470         case ibl_BOOT_FORMAT_BBLOB:
471             iblBootBlob (bootFxn, &entry, formatParams);
472             break;
473 #endif
475 #ifndef EXCLUDE_ELF
476         case ibl_BOOT_FORMAT_ELF:
477             iblBootElf (bootFxn, &entry);
478             break;
479 #endif
481         default:
482             iblStatus.invalidDataFormatSpec += 1;
483             break;
485     }
486     
488     return (entry);