]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/ibl.git/blob - src/main/iblinit.c
Merge pull request #3 in PROCESSOR-SDK/ibl from PRSDK-5675 to master
[keystone-rtos/ibl.git] / src / main / iblinit.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 */
36 /**
37  *  @file iblinit.c
38  *
39  *  @brief
40  *              This file contains code which runs prior to loading the full IBL
41  *
42  *  @details
43  *              The IBL loads itself in a two stage process. The ROM boot loader
44  *              loads this first stage IBL first. This entire program must be
45  *              endian independent in execution.
46  *
47  *      This first loader reads the IBL parameters, and will endian
48  *      switch them if required. The PLL is configured if indicated
49  *      by the parameters.
50  *
51  *      The I2C block which contains the I2C EEPROM address for both
52  *      the big and little endian images is then read. Based on the
53  *      endianness of the device the rest of the IBL is read from
54  *      the I2C EEPROM, and execution is transferred to the full
55  *      IBL.
56  *
57  *      The subsequent reads are allowed to cross 16 bit i2c EEPROM
58  *      addresses. When the boundary is crossed the i2c address
59  *      field is incremented.
60  *
61  */
63 #include "ibl.h"
64 #include "iblloc.h"
65 #include "iblcfg.h"
66 #include "device.h"
67 #include "iblbtbl.h"
68 #include "iblinit.h"
69 #include <string.h>
72 /**
73  *  @brief
74  *      Data structures shared between the 1st and 2nd stage IBL load
75  *      are declared in a single header file, included in both stages
76  */
77 #include "iblStage.h"
79 /**
80  *  @brief
81  *      The boot table processing status is declared in the boot table wrapper,
82  *      and used here in the main status fields.
83  */
84 extern Int32 btblWrapEcode;
86 /**
87  *  @brief
88  *      The malloc function used for both boot stages of the ibl
89  */
90 void *iblMalloc (Uint32 size)
91 {
92     return (malloc (size));
93 }
95 /**
96  *  @brief
97  *      The free function used for both stages of the ibl
98  */
99 void iblFree (void *mem)
101     free (mem);
104 /**
105  *  @brief
106  *      The memset function used for both stages of the ibl
107  */
108 void *iblMemset (void *mem, Int32 ch, Uint32 n)
110     return (memset (mem, ch, n));
113 /**
114  *  @brief
115  *      The memcpy function used for both stages of the ibl
116  */
117 void *iblMemcpy (void *s1, const void *s2, Uint32 n)
119     return (memcpy (s1, s2, n));
123 /**
124  *  @brief
125  *      Ones complement addition
126  */
127 inline uint16 onesComplementAdd (uint16 value1, uint16 value2)
129   uint32 result;
131   result = (uint32)value1 + (uint32)value2;
133   result = (result >> 16) + (result & 0xFFFF); /* add in carry   */
134   result += (result >> 16);                    /* maybe one more */
135   return ((uint16)result);
139 /**
140  *  @brief
141  *      Ones complement checksum computation 
142  */
143 uint16 onesComplementChksum (uint16 * restrict p_data, uint16 len)
145   uint16 chksum = 0;
147   while (len > 0)
148   {
149     chksum = onesComplementAdd(chksum, *p_data);
150     p_data++;
151     len--;
152   }
153   return (chksum);
154
158 /**
159  *  @brief
160  *      Do a 4 byte endian swap
161  */
162 uint32 swap32val (uint32 v)
164     v =  (((v >> 24) & 0xff) <<  0)  |
165          (((v >> 16) & 0xff) <<  8)  |
166          (((v >>  8) & 0xff) << 16)  |
167          (((v >>  0) & 0xff) << 24);
169     return (v);
173 /**
174  *  @brief
175  *      Do a 2 byte endian swap
176  */
177 uint16 swap16val (uint16 v)
179     v = (((v >> 8) & 0xff) << 0)  |
180         (((v >> 0) & 0xff) << 8);
182     return (v);
186 /**
187  *  @brief
188  *  Do an endian swap on the ibl structure
189  */
190 void iblSwap (void)
192     int i, j, k;
194     ibl.iblMagic = swap32val (ibl.iblMagic);
196     for (i = 0; i < ibl_N_PLL_CFGS; i++)  {
197         ibl.pllConfig[i].doEnable      = swap16val (ibl.pllConfig[i].doEnable);
198         ibl.pllConfig[i].prediv        = swap32val (ibl.pllConfig[i].prediv);
199         ibl.pllConfig[i].mult          = swap32val (ibl.pllConfig[i].mult);
200         ibl.pllConfig[i].postdiv       = swap32val (ibl.pllConfig[i].postdiv);
201         ibl.pllConfig[i].pllOutFreqMhz = swap32val (ibl.pllConfig[i].pllOutFreqMhz);
202     }
204     ibl.ddrConfig.configDdr = swap16val (ibl.ddrConfig.configDdr);
207     if (targetEmifType() == ibl_EMIF_TYPE_31)  { 
208         ibl.ddrConfig.uEmif.emif3p1.sdcfg  = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdcfg);
209         ibl.ddrConfig.uEmif.emif3p1.sdrfc  = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdrfc);
210         ibl.ddrConfig.uEmif.emif3p1.sdtim1 = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdtim1);
211         ibl.ddrConfig.uEmif.emif3p1.sdtim2 = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdtim2);
212         ibl.ddrConfig.uEmif.emif3p1.dmcctl = swap32val(ibl.ddrConfig.uEmif.emif3p1.dmcctl);
213        
214     } else if (targetEmifType() == ibl_EMIF_TYPE_40)  {
215         ibl.ddrConfig.uEmif.emif4p0.registerMask          = swap32val(ibl.ddrConfig.uEmif.emif4p0.registerMask);
216         ibl.ddrConfig.uEmif.emif4p0.sdRamConfig           = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamConfig);
217         ibl.ddrConfig.uEmif.emif4p0.sdRamConfig2          = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamConfig2);
218         ibl.ddrConfig.uEmif.emif4p0.sdRamRefreshCtl       = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamRefreshCtl);
219         ibl.ddrConfig.uEmif.emif4p0.sdRamTiming1          = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamTiming1);
220         ibl.ddrConfig.uEmif.emif4p0.sdRamTiming2          = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamTiming2);
221         ibl.ddrConfig.uEmif.emif4p0.sdRamTiming3          = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamTiming3);
222         ibl.ddrConfig.uEmif.emif4p0.lpDdrNvmTiming        = swap32val(ibl.ddrConfig.uEmif.emif4p0.lpDdrNvmTiming);
223         ibl.ddrConfig.uEmif.emif4p0.powerManageCtl        = swap32val(ibl.ddrConfig.uEmif.emif4p0.powerManageCtl);
224         ibl.ddrConfig.uEmif.emif4p0.iODFTTestLogic        = swap32val(ibl.ddrConfig.uEmif.emif4p0.iODFTTestLogic);
225         ibl.ddrConfig.uEmif.emif4p0.performCountCfg       = swap32val(ibl.ddrConfig.uEmif.emif4p0.performCountCfg);
226         ibl.ddrConfig.uEmif.emif4p0.performCountMstRegSel = swap32val(ibl.ddrConfig.uEmif.emif4p0.performCountMstRegSel);
227         ibl.ddrConfig.uEmif.emif4p0.readIdleCtl           = swap32val(ibl.ddrConfig.uEmif.emif4p0.readIdleCtl);
228         ibl.ddrConfig.uEmif.emif4p0.sysVbusmIntEnSet      = swap32val(ibl.ddrConfig.uEmif.emif4p0.sysVbusmIntEnSet);
229         ibl.ddrConfig.uEmif.emif4p0.sdRamOutImpdedCalCfg  = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamOutImpdedCalCfg);
230         ibl.ddrConfig.uEmif.emif4p0.tempAlterCfg          = swap32val(ibl.ddrConfig.uEmif.emif4p0.tempAlterCfg);
231         ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl1            = swap32val(ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl1);
232         ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl2            = swap32val(ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl2);
233         ibl.ddrConfig.uEmif.emif4p0.priClassSvceMap       = swap32val(ibl.ddrConfig.uEmif.emif4p0.priClassSvceMap);
234         ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce1Map     = swap32val(ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce1Map);
235         ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce2Map     = swap32val(ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce2Map);
236         ibl.ddrConfig.uEmif.emif4p0.eccCtl                = swap32val(ibl.ddrConfig.uEmif.emif4p0.eccCtl);
237         ibl.ddrConfig.uEmif.emif4p0.eccRange1             = swap32val(ibl.ddrConfig.uEmif.emif4p0.eccRange1);
238         ibl.ddrConfig.uEmif.emif4p0.eccRange2             = swap32val(ibl.ddrConfig.uEmif.emif4p0.eccRange2);
239         ibl.ddrConfig.uEmif.emif4p0.rdWrtExcThresh        = swap32val(ibl.ddrConfig.uEmif.emif4p0.rdWrtExcThresh);
240     }
243     for (i = 0; i < ibl_N_ETH_PORTS; i++)  {
244         ibl.sgmiiConfig[i].configure     = swap16val(ibl.sgmiiConfig[i].configure);
245         ibl.sgmiiConfig[i].adviseAbility = swap32val(ibl.sgmiiConfig[i].adviseAbility);
246         ibl.sgmiiConfig[i].control       = swap32val(ibl.sgmiiConfig[i].control);
247         ibl.sgmiiConfig[i].txConfig      = swap32val(ibl.sgmiiConfig[i].txConfig);
248         ibl.sgmiiConfig[i].rxConfig      = swap32val(ibl.sgmiiConfig[i].rxConfig);
249         ibl.sgmiiConfig[i].auxConfig     = swap32val(ibl.sgmiiConfig[i].auxConfig);
250     }
251     
253     ibl.mdioConfig.nMdioOps   = swap16val (ibl.mdioConfig.nMdioOps);
254     ibl.mdioConfig.mdioClkDiv = swap16val (ibl.mdioConfig.mdioClkDiv);
255     ibl.mdioConfig.interDelay = swap32val (ibl.mdioConfig.interDelay);
257     for (i = 0; i < ibl_N_MDIO_CFGS; i++)
258         ibl.mdioConfig.mdio[i] = swap32val (ibl.mdioConfig.mdio[i]);
261     ibl.spiConfig.addrWidth  = swap16val(ibl.spiConfig.addrWidth);
262     ibl.spiConfig.nPins      = swap16val(ibl.spiConfig.nPins);
263     ibl.spiConfig.mode       = swap16val(ibl.spiConfig.mode);
264     ibl.spiConfig.csel       = swap16val(ibl.spiConfig.csel);
265     ibl.spiConfig.c2tdelay   = swap16val(ibl.spiConfig.c2tdelay);
266     ibl.spiConfig.busFreqMHz = swap16val(ibl.spiConfig.busFreqMHz);
268     for (i = 0; i < ibl_MAX_EMIF_PMEM; i++)  {
269         ibl.emifConfig[i].csSpace    = swap16val(ibl.emifConfig[i].csSpace);
270         ibl.emifConfig[i].busWidth   = swap16val(ibl.emifConfig[i].busWidth);
271         ibl.emifConfig[i].waitEnable = swap16val(ibl.emifConfig[i].waitEnable);
272     }
275     for (i = 0; i < ibl_N_BOOT_MODES; i++)  {
276         ibl.bootModes[i].bootMode = swap32val(ibl.bootModes[i].bootMode);
277         ibl.bootModes[i].priority = swap32val(ibl.bootModes[i].priority);
278         ibl.bootModes[i].port     = swap32val(ibl.bootModes[i].port);
280         if (ibl.bootModes[i].bootMode == ibl_BOOT_MODE_TFTP)  {
281             ibl.bootModes[i].u.ethBoot.doBootp            = swap16val(ibl.bootModes[i].u.ethBoot.doBootp);
282             ibl.bootModes[i].u.ethBoot.useBootpServerIp   = swap16val(ibl.bootModes[i].u.ethBoot.useBootpServerIp);
283             ibl.bootModes[i].u.ethBoot.useBootpFileName   = swap16val(ibl.bootModes[i].u.ethBoot.useBootpFileName);
284             ibl.bootModes[i].u.ethBoot.bootFormat         = swap32val(ibl.bootModes[i].u.ethBoot.bootFormat);
285             ibl.bootModes[i].u.ethBoot.blob.startAddress  = swap32val(ibl.bootModes[i].u.ethBoot.blob.startAddress);
286             ibl.bootModes[i].u.ethBoot.blob.sizeBytes     = swap32val(ibl.bootModes[i].u.ethBoot.blob.sizeBytes);
287             ibl.bootModes[i].u.ethBoot.blob.branchAddress = swap32val(ibl.bootModes[i].u.ethBoot.blob.branchAddress);
289         }  else if (ibl.bootModes[i].bootMode == ibl_BOOT_MODE_NAND)  {
290             ibl.bootModes[i].u.nandBoot.bootFormat             = swap32val(ibl.bootModes[i].u.nandBoot.bootFormat);
291             for (j = 0; j < ibl_N_ENDIANS; j++)
292             {
293                 for (k = 0; k < ibl_N_IMAGES; k++)
294                 {
295                     ibl.bootModes[i].u.nandBoot.bootAddress[j][k] = swap32val(ibl.bootModes[i].u.nandBoot.bootAddress[j][k]);
296                 }
297             }
298             ibl.bootModes[i].u.nandBoot.interface              = swap32val(ibl.bootModes[i].u.nandBoot.interface);
299             for (j = 0; j < ibl_N_ENDIANS; j++)
300             {
301                 for (k = 0; k < ibl_N_IMAGES; k++)
302                 {
303                     ibl.bootModes[i].u.nandBoot.blob[j][k].startAddress  = swap32val(ibl.bootModes[i].u.nandBoot.blob[j][k].startAddress);
304                     ibl.bootModes[i].u.nandBoot.blob[j][k].sizeBytes     = swap32val(ibl.bootModes[i].u.nandBoot.blob[j][k].sizeBytes);
305                     ibl.bootModes[i].u.nandBoot.blob[j][k].branchAddress = swap32val(ibl.bootModes[i].u.nandBoot.blob[j][k].branchAddress);
306                 }
307             }
308             ibl.bootModes[i].u.nandBoot.nandInfo.busWidthBits  = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.busWidthBits);
309             ibl.bootModes[i].u.nandBoot.nandInfo.pageSizeBytes = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pageSizeBytes);
310             ibl.bootModes[i].u.nandBoot.nandInfo.pageEccBytes  = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pageEccBytes);
311             ibl.bootModes[i].u.nandBoot.nandInfo.pagesPerBlock = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pagesPerBlock);
312             ibl.bootModes[i].u.nandBoot.nandInfo.totalBlocks   = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.totalBlocks);
313             ibl.bootModes[i].u.nandBoot.nandInfo.addressBytes  = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.addressBytes);
314             ibl.bootModes[i].u.nandBoot.nandInfo.lsbFirst      = swap16val(ibl.bootModes[i].u.nandBoot.nandInfo.lsbFirst);
315             ibl.bootModes[i].u.nandBoot.nandInfo.blockOffset   = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.blockOffset);
316             ibl.bootModes[i].u.nandBoot.nandInfo.pageOffset    = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pageOffset);
317             ibl.bootModes[i].u.nandBoot.nandInfo.columnOffset  = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.columnOffset);
318             ibl.bootModes[i].u.nandBoot.nandInfo.postCommand   = swap16val(ibl.bootModes[i].u.nandBoot.nandInfo.postCommand);
319         }  else if (ibl.bootModes[i].bootMode == ibl_BOOT_MODE_NOR)  {
320             ibl.bootModes[i].u.norBoot.bootFormat         = swap32val(ibl.bootModes[i].u.norBoot.bootFormat);
321             for (j = 0; j < ibl_N_ENDIANS; j++)
322             {
323                 for (k = 0; k < ibl_N_IMAGES; k++)
324                 {
325                     ibl.bootModes[i].u.norBoot.bootAddress[j][k] = swap32val(ibl.bootModes[i].u.norBoot.bootAddress[j][k]);
326                 }
327             }
328             ibl.bootModes[i].u.norBoot.interface          = swap32val(ibl.bootModes[i].u.norBoot.interface);
329             for (j = 0; j < ibl_N_ENDIANS; j++)
330             {
331                 for (k = 0; k < ibl_N_IMAGES; k++)
332                 {
333                     ibl.bootModes[i].u.norBoot.blob[j][k].startAddress  = swap32val(ibl.bootModes[i].u.norBoot.blob[j][k].startAddress);
334                     ibl.bootModes[i].u.norBoot.blob[j][k].sizeBytes     = swap32val(ibl.bootModes[i].u.norBoot.blob[j][k].sizeBytes);
335                     ibl.bootModes[i].u.norBoot.blob[j][k].branchAddress = swap32val(ibl.bootModes[i].u.norBoot.blob[j][k].branchAddress);
336                 }
337             }
339         }
341     }
343     ibl.iblEvmType = swap16val (ibl.iblEvmType);
344     ibl.chkSum = swap16val (ibl.chkSum);
347         
349 /**
350  *  @brief
351  *      The init load context consists of the address of the next block 
352  *      to read, and a simple fifo-ish structure holding any existing data.
353  *
354  *      A full fifo is not defined here. The individual init load blocks
355  *      (I2C, SPI NOR, SPI NAND) will poke the structure values directly
356  *      to minimize the compiled code size. Most notably is the absence
357  *      of the write function. This fifo will always be completely emptied
358  *      before any writes are done, so writes are always done from the top.
359  */
360 uint32 iFifoIn  = 0;
361 uint32 iFifoOut = 0;
362 uint8  iData[I_MAX_BLOCK_SIZE];
364 /**
365  *  @brief
366  *      Checkum calculation. 16 bit values constructed from received bytes
367  *      always in big endian format, regardless of the endianness of the device 
368  */
369 uint16 iSum[I_MAX_BLOCK_SIZE >> 1];
372 /**
373  *  @brief
374  *      Return the number of elements in the fifo
375  */
376 Uint32 iFifoCount (void)
378     Int32 count;
380     if (iFifoIn >= iFifoOut)
381         count = iFifoIn - iFifoOut;
382     else
383         count = iFifoIn + I_MAX_BLOCK_SIZE - iFifoOut;
385     return (count);
389     
390 /**
391  *  @brief
392  *      Read a byte from the fifo
393  */
394 Uint8 iFifoRead(void)
396     Uint8 v;
398     v = iData[iFifoOut];
400     iFifoOut += 1;
402     if (iFifoOut == iFifoIn)
403         iFifoOut = iFifoIn = 0;
405     if (iFifoOut >= I_MAX_BLOCK_SIZE)
406         iFifoOut = 0;
408     return (v);
413 #define iblBITMASK(x,y)      (   (   (  ((UINT32)1 << (((UINT32)x)-((UINT32)y)+(UINT32)1) ) - (UINT32)1 )   )   <<  ((UINT32)y)   )
414 #define iblREAD_BITFIELD(z,x,y)   (((UINT32)z) & iblBITMASK(x,y)) >> (y)
415 /**
416  *  @brief
417  *      Return the lower 16 bits of a 32 bit value. A function is used (with cross-function optomization off)
418  *      which results in an endian independent version
419  */
420 uint16 readLower16 (uint32 v)
422     return (iblREAD_BITFIELD(v,15,0));
426 /**
427  * @brief
428  *      Return the upper 16 bits of a 32 bit value. A function is used to force an endian independent version
429  */
430 uint16 readUpper16 (uint32 v)
432   return (iblREAD_BITFIELD(v,31,16));
437 /**
438  *  @brief
439  *      The main function
440  *
441  *  @details
442  *      The ibl configuration parameters are read from the i2c, 
443  *      followed by the i2c mapping information. The second stage
444  *      of the IBL is then loaded, and execution transferred 
445  *      to the second stage.
446  */
447 void main (void)
450     int32        bootDevice;
451     uint32       entry;
452     void         (*exit)();
454     BOOT_MODULE_FXN_TABLE *bFxnTbl;
456     memset (&iblStatus, 0, sizeof(iblStatus_t));
457     iblStatus.iblMagic     = ibl_MAGIC_VALUE;
458     iblStatus.iblVersion   = ibl_VERSION;
459     iblStatus.activeDevice = ibl_ACTIVE_DEVICE_I2C;
461 #ifdef C665x
462      /*Set GPIO as SPI,UART*/
463     configureGPIO();
464 #endif
465     /* Determine the boot device to read from */
466     bootDevice = deviceReadBootDevice();
468     switch (bootDevice)  {
470 #ifndef EXCLUDE_I2C
471     case BOOT_DEVICE_I2C:       bFxnTbl = iblInitI2c ();
472                                 break;
473 #endif
475 #ifndef EXCLUDE_NOR_SPI
476     case BOOT_DEVICE_SPI_NOR:   bFxnTbl = iblInitSpiNor ();
477                                 break;
478 #endif
481     default:                    iblStatus.iblFail = ibl_FAIL_CODE_INVALID_INIT_DEVICE;
482                                 for (;;);
484     }
485     
487     /* Pll configuration is device specific */
488     devicePllConfig ();
490     /* Enable the EDC for local memory */
491     if (IBL_ENABLE_EDC)
492     {
493         iblEnableEDC ();
494     }
496     /* Check if need to enter Rom boot loader again */
497     if (IBL_ENTER_ROM)
498     {
499         iblEnterRom ();
500     }
502     /* Pass control to the boot table processor */
503     iblBootBtbl (bFxnTbl, &entry);
505     if (btblWrapEcode != 0)  {
506         iblStatus.iblFail = ibl_FAIL_CODE_BTBL_FAIL;
507         for (;;);
508     }
510     /* jump to the exit point, which will be the entry point for the full IBL */
511     exit = (void (*)())entry;
512     (*exit)();