Bug fix - added endian swap for MDIO parameters
[keystone-rtos/ibl.git] / src / main / iblinit.c
1 /**
2  *  @file iblinit.c
3  *
4  *  @brief
5  *              This file contains code which runs prior to loading the full IBL
6  *
7  *  @details
8  *              The IBL loads itself in a two stage process. The ROM boot loader
9  *              loads this first stage IBL first. This entire program must be
10  *              endian independent in execution.
11  *
12  *      This first loader reads the IBL parameters, and will endian
13  *      switch them if required. The PLL is configured if indicated
14  *      by the parameters.
15  *
16  *      The I2C block which contains the I2C EEPROM address for both
17  *      the big and little endian images is then read. Based on the
18  *      endianness of the device the rest of the IBL is read from
19  *      the I2C EEPROM, and execution is transferred to the full
20  *      IBL.
21  *
22  *      The subsequent reads are allowed to cross 16 bit i2c EEPROM
23  *      addresses. When the boundary is crossed the i2c address
24  *      field is incremented.
25  *
26  */
28 #include "ibl.h"
29 #include "iblloc.h"
30 #include "iblcfg.h"
31 #include "device.h"
32 #include "iblbtbl.h"
33 #include "i2c.h"
34 #include <string.h>
37 /**
38  *  @brief
39  *      Data structures shared between the 1st and 2nd stage IBL load
40  *      are declared in a single header file, included in both stages
41  */
42 #include "iblStage.h"
44 /**
45  *  @brief
46  *      byte swapping of i2c data must be done when in little endian mode
47  */
48 bool littleEndian;
50 /**
51  *  @brief
52  *      The boot table processing status is declared in the boot table wrapper,
53  *      and used here in the main status fields.
54  */
55 extern Int32 btblWrapEcode;
57 /**
58  *  @brief
59  *      Ones complement addition
60  */
61 inline uint16 onesComplementAdd (uint16 value1, uint16 value2)
62 {
63   uint32 result;
65   result = (uint32)value1 + (uint32)value2;
67   result = (result >> 16) + (result & 0xFFFF); /* add in carry   */
68   result += (result >> 16);                    /* maybe one more */
69   return ((uint16)result);
70 }
73 /**
74  *  @brief
75  *      Ones complement checksum computation 
76  */
77 uint16 onesComplementChksum (uint16 * restrict p_data, uint16 len)
78 {
79   uint16 chksum = 0;
81   while (len > 0)
82   {
83     chksum = onesComplementAdd(chksum, *p_data);
84     p_data++;
85     len--;
86   }
87   return (chksum);
88
92 /**
93  *  @brief
94  *      Do a 4 byte endian swap
95  */
96 uint32 swap32val (uint32 v)
97 {
98     v =  (((v >> 24) & 0xff) <<  0)  |
99          (((v >> 16) & 0xff) <<  8)  |
100          (((v >>  8) & 0xff) << 16)  |
101          (((v >>  0) & 0xff) << 24);
103     return (v);
107 /**
108  *  @brief
109  *      Do a 2 byte endian swap
110  */
111 uint16 swap16val (uint16 v)
113     v = (((v >> 8) & 0xff) << 0)  |
114         (((v >> 0) & 0xff) << 8);
116     return (v);
120 /**
121  *  @brief
122  *  Do an endian swap on the ibl structure
123  */
124 void iblSwap (void)
126     int i;
128     ibl.iblMagic = swap32val (ibl.iblMagic);
130     for (i = 0; i < ibl_N_PLL_CFGS; i++)  {
131         ibl.pllConfig[i].doEnable      = swap16val (ibl.pllConfig[i].doEnable);
132         ibl.pllConfig[i].prediv        = swap32val (ibl.pllConfig[i].prediv);
133         ibl.pllConfig[i].mult          = swap32val (ibl.pllConfig[i].mult);
134         ibl.pllConfig[i].postdiv       = swap32val (ibl.pllConfig[i].postdiv);
135         ibl.pllConfig[i].pllOutFreqMhz = swap32val (ibl.pllConfig[i].pllOutFreqMhz);
136     }
138     ibl.ddrConfig.configDdr = swap16val (ibl.ddrConfig.configDdr);
140     ibl.ddrConfig.uEmif.emif3p1.sdcfg  = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdcfg);
141     ibl.ddrConfig.uEmif.emif3p1.sdrfc  = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdrfc);
142     ibl.ddrConfig.uEmif.emif3p1.sdtim1 = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdtim1);
143     ibl.ddrConfig.uEmif.emif3p1.sdtim2 = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdtim2);
144     ibl.ddrConfig.uEmif.emif3p1.dmcctl = swap32val(ibl.ddrConfig.uEmif.emif3p1.dmcctl);
146     for (i = 0; i < ibl_N_ETH_PORTS; i++)  {
147         ibl.ethConfig[i].ethPriority        = swap32val (ibl.ethConfig[i].ethPriority);
148         ibl.ethConfig[i].port               = swap32val (ibl.ethConfig[i].port);
149         ibl.ethConfig[i].doBootp            = swap16val (ibl.ethConfig[i].doBootp);
150         ibl.ethConfig[i].useBootpServerIp   = swap16val (ibl.ethConfig[i].useBootpServerIp);
151         ibl.ethConfig[i].useBootpFileName   = swap16val (ibl.ethConfig[i].useBootpFileName);
152         ibl.ethConfig[i].bootFormat         = swap32val (ibl.ethConfig[i].bootFormat);
153         ibl.ethConfig[i].blob.startAddress  = swap32val (ibl.ethConfig[i].blob.startAddress);
154         ibl.ethConfig[i].blob.sizeBytes     = swap32val (ibl.ethConfig[i].blob.sizeBytes);
155         ibl.ethConfig[i].blob.branchAddress = swap32val (ibl.ethConfig[i].blob.branchAddress);
157         ibl.sgmiiConfig[i].adviseAbility = swap32val (ibl.sgmiiConfig[i].adviseAbility);
158         ibl.sgmiiConfig[i].control       = swap32val (ibl.sgmiiConfig[i].control);
159         ibl.sgmiiConfig[i].txConfig      = swap32val (ibl.sgmiiConfig[i].txConfig);
160         ibl.sgmiiConfig[i].rxConfig      = swap32val (ibl.sgmiiConfig[i].rxConfig);
161         ibl.sgmiiConfig[i].auxConfig     = swap32val (ibl.sgmiiConfig[i].auxConfig);
162     }
164     ibl.mdioConfig.nMdioOps   = swap16val (ibl.mdioConfig.nMdioOps);
165     ibl.mdioConfig.mdioClkDiv = swap16val (ibl.mdioConfig.mdioClkDiv);
166     ibl.mdioConfig.interDelay = swap32val (ibl.mdioConfig.interDelay);
168     for (i = 0; i < ibl_N_MDIO_CFGS; i++)
169         ibl.mdioConfig.mdio[i] = swap32val (ibl.mdioConfig.mdio[i]);
171     ibl.nandConfig.nandPriority       = swap32val (ibl.nandConfig.nandPriority);
172     ibl.nandConfig.bootFormat         = swap32val (ibl.nandConfig.bootFormat);
173     ibl.nandConfig.blob.startAddress  = swap32val (ibl.nandConfig.blob.startAddress);
174     ibl.nandConfig.blob.sizeBytes     = swap32val (ibl.nandConfig.blob.sizeBytes);
175     ibl.nandConfig.blob.branchAddress = swap32val (ibl.nandConfig.blob.branchAddress);
177     ibl.nandConfig.nandInfo.busWidthBits  = swap32val (ibl.nandConfig.nandInfo.busWidthBits);
178     ibl.nandConfig.nandInfo.pageSizeBytes = swap32val (ibl.nandConfig.nandInfo.pageSizeBytes);
179     ibl.nandConfig.nandInfo.pageEccBytes  = swap32val (ibl.nandConfig.nandInfo.pageEccBytes);
180     ibl.nandConfig.nandInfo.pagesPerBlock = swap32val (ibl.nandConfig.nandInfo.pagesPerBlock);
181     ibl.nandConfig.nandInfo.totalBlocks   = swap32val (ibl.nandConfig.nandInfo.totalBlocks);
182     ibl.nandConfig.nandInfo.addressBytes  = swap32val (ibl.nandConfig.nandInfo.addressBytes);
183     ibl.nandConfig.nandInfo.lsbFirst      = swap16val (ibl.nandConfig.nandInfo.lsbFirst);
184     ibl.nandConfig.nandInfo.blockOffset   = swap32val (ibl.nandConfig.nandInfo.blockOffset);
185     ibl.nandConfig.nandInfo.pageOffset    = swap32val (ibl.nandConfig.nandInfo.pageOffset);
186     ibl.nandConfig.nandInfo.columnOffset  = swap32val (ibl.nandConfig.nandInfo.columnOffset);
187     ibl.nandConfig.nandInfo.postCommand   = swap16val (ibl.nandConfig.nandInfo.postCommand);
189     ibl.chkSum = swap16val (ibl.chkSum);
192         
194 /**
195  *  @brief
196  *      The i2c load context consists of the address of the next block 
197  *      to read, and a simple fifo holding any existing data.
198  */
199 #define I2C_MAX_BLOCK_SIZE      0x80
200 uint32 i2cReadAddress;
202 uint32 i2cFifoIn  = 0;
203 uint32 i2cFifoOut = 0;
204 uint8  i2cData[I2C_MAX_BLOCK_SIZE];
205 uint16 i2cSum[I2C_MAX_BLOCK_SIZE >> 1];
208 /**
209  *  @brief
210  *      Return the number of elements in the fifo
211  */
212 Uint32 i2cFifoCount (void)
214     Int32 count;
216     if (i2cFifoIn >= i2cFifoOut)
217         count = i2cFifoIn - i2cFifoOut;
218     else
219         count = i2cFifoIn + I2C_MAX_BLOCK_SIZE - i2cFifoOut;
221     return (count);
225     
226 /**
227  *  @brief
228  *      Read a byte from the fifo
229  */
230 Uint8 i2cFifoRead(void)
232     Uint8 v;
234     v = i2cData[i2cFifoOut];
236     i2cFifoOut += 1;
238     if (i2cFifoOut == i2cFifoIn)
239         i2cFifoOut = i2cFifoIn = 0;
241     if (i2cFifoOut >= I2C_MAX_BLOCK_SIZE)
242         i2cFifoOut = 0;
244     return (v);
248 /**
249  *  @brief
250  *      Read a block of data from the I2C eeprom and put it in the fifo
251  */
252 void i2cReadBlock (void)
254     uint16 len;
255     int32  i, j;
256     uint32 v;
258     for (;;) {
259         while (hwI2cMasterRead (i2cReadAddress & 0xffff,    /* The address on the eeprom of the table */
260                                 4,                          /* The number of bytes to read */
261                                 i2cData,                    /* Where to store the bytes */
262                                 i2cReadAddress >> 16,       /* The bus address of the eeprom */
263                                 IBL_I2C_CFG_ADDR_DELAY)     /* The delay between sending the address and reading data */
264     
265              != I2C_RET_OK)  {
267             iblStatus.i2cDataRetries += 1;
268         }
270         /* Form the length. The received bytes are always in big endian format */
271         len    = (i2cData[0] << 8) | i2cData[1];
274         if (len > I2C_MAX_BLOCK_SIZE)
275             continue;
278         while (hwI2cMasterRead (i2cReadAddress & 0xffff,    /* The address on the eeprom of the table */
279                                 len,                        /* The number of bytes to read */
280                                 i2cData,                    /* Where to store the bytes */
281                                 i2cReadAddress >> 16,       /* The bus address of the eeprom */
282                                 IBL_I2C_CFG_ADDR_DELAY)     /* The delay between sending the address and reading data */
283     
284              != I2C_RET_OK)  {
286             iblStatus.i2cDataRetries += 1;
287         }
290         /* Must do endian conversion to verify the checksum */
291         for (i = j = 0; i < len; i += 2, j += 1) 
292             i2cSum[j] = (i2cData[i+0] << 8) | i2cData[i+1];
294         v = onesComplementChksum (i2cSum, j);
295         if ((v == 0) || (v == 0xffff))
296             break;
298         
299         iblStatus.i2cDataRetries += 1;
301     }
304     i2cReadAddress += len;
305     
306     i2cFifoIn  = len;
307     i2cFifoOut = 4;    /* The i2c header is effectively removed */
311              
314 /**
315  *  @brief
316  *      Read data from the I2C to pass to the interpreter
317  */
318 Int32 iblI2cRead (Uint8 *buf, Uint32 num_bytes)
320     int i;
322     for (i = 0; i < num_bytes; i++)  {
324         if (i2cFifoCount() == 0)
325             i2cReadBlock ();
327         buf[i] = i2cFifoRead();
328     }
330     return (0);
336 /**
337  *  @brief
338  *      The module function table used for boot from i2c
339  */
340 BOOT_MODULE_FXN_TABLE i2cinit_boot_module = 
342     NULL,           /* Open  API */
343     NULL,           /* Close API */
344     iblI2cRead,     /* Read  API */
345     NULL,           /* Write API */
346     NULL,           /* Peek  API */
347     NULL,           /* Seek  API */
348     NULL            /* Query API */
349 };
353 /**
354  *  @brief
355  *      The main function
356  *
357  *  @details
358  *      The ibl configuration parameters are read from the i2c, 
359  *      followed by the i2c mapping information. The second stage
360  *      of the IBL is then loaded, and execution transferred 
361  *      to the second stage.
362  */
363 void main (void)
366     uint16       v;
367     uint32       entry;
368     void         (*exit)();
369     iblI2cMap_t  map;
371     memset (&iblStatus, 0, sizeof(iblStatus_t));
372     iblStatus.iblMagic = ibl_MAGIC_VALUE;
374     /* Read the endianness setting of the device */
375     littleEndian = deviceIsLittleEndian();
376     
377     /* Load the default configuration table from the i2c. The actual speed of the device
378      * isn't really known here, since it is part of the table, so a compile time
379      * value is used (the pll may have been configured during the initial load) */
380     hwI2Cinit (IBL_I2C_DEV_FREQ_MHZ,        /* The CPU frequency during I2C data load */
381                DEVICE_I2C_MODULE_DIVISOR,   /* The divide down of CPU that drives the i2c */
382                IBL_I2C_CLK_FREQ_KHZ,        /* The I2C data rate used during table load */
383                IBL_I2C_OWN_ADDR);           /* The address used by this device on the i2c bus */
386     /* Read the i2c configuration tables until the checksum passes and the magic number
387      * matches. The checksum must be verified before the endian re-ordering is done */
388     for (;;)  {
390         if (hwI2cMasterRead (IBL_I2C_CFG_TABLE_DATA_ADDR,    /* The address on the eeprom of the table */
391                              sizeof(ibl_t),                  /* The number of bytes to read */
392                              (UINT8 *)&ibl,                  /* Where to store the bytes */
393                              IBL_I2C_CFG_EEPROM_BUS_ADDR,    /* The bus address of the eeprom */
394                              IBL_I2C_CFG_ADDR_DELAY)         /* The delay between sending the address and reading data */
396              == I2C_RET_OK)  {
398                  if (ibl.chkSum != 0)  {
400                     v = onesComplementChksum ((UINT16 *)&ibl, sizeof(ibl_t) / sizeof(UINT16));
401                     if ((v != 0) && (v != 0xffff))  {
402                         iblStatus.i2cRetries += 1;
403                         continue;
404                     }
406                  }  
409                 if (ibl.iblMagic == ibl_MAGIC_VALUE)
410                     break;
412                 if (swap32val (ibl.iblMagic) == ibl_MAGIC_VALUE)  {
413                     iblSwap ();
414                     break;
415                 }
417                 iblStatus.magicRetries += 1;
419             }
421             iblStatus.i2cRetries += 1;
422     }
424     /* Pll configuration is device specific */
425     devicePllConfig ();
427     /* The IBL table is in place. Read the I2C map information from the eeprom */
428     for (;;)  {
429         if (hwI2cMasterRead (IBL_I2C_MAP_TABLE_DATA_ADDR,    /* The address on the eeprom of the data mapping */
430                              sizeof(iblI2cMap_t),            /* The number of bytes to read */
431                              (UINT8 *)&map,                  /* Where to store the bytes */
432                              IBL_I2C_CFG_EEPROM_BUS_ADDR,    /* The bus address of the eeprom */
433                              IBL_I2C_CFG_ADDR_DELAY)         /* The delay between sending the address and reading data */
435              == I2C_RET_OK)  {
437                 /* On the I2C EEPROM the table is always formatted with the most significant
438                  * byte first. So if the device is running little endain the endian must be
439                  * swapped */
440                 if (littleEndian == TRUE)  {
441                     map.length = swap16val (map.length);
442                     map.chkSum = swap16val (map.chkSum);
443                     map.addrLe = swap32val (map.addrLe);
444                     map.addrBe = swap32val (map.addrBe);
445                 }
447                 if (map.length != sizeof(iblI2cMap_t))  {
448                     iblStatus.mapSizeFail += 1;
449                     continue;
450                 }
452                 if (map.chkSum != 0)  {
453                     
454                     v = onesComplementChksum ((UINT16 *)&map, sizeof(iblI2cMap_t));
455                     if ((v != 0) && (v != 0xffff))  {
456                         iblStatus.mapRetries += 1;
457                         continue;
458                     }
459                 }
461                 break;
462         }
464         iblStatus.mapRetries += 1;
466     }
469     /* The rest of the IBL is in boot table format. Read and process the data */
470     if (littleEndian == TRUE) 
471         i2cReadAddress = map.addrLe;
472     else
473         i2cReadAddress = map.addrBe;
475     if (i2cReadAddress == 0xffffffff)  {
476         iblStatus.iblFail = ibl_FAIL_CODE_INVALID_I2C_ADDRESS;
477         for (;;);
478     }
481     /* Pass control to the boot table processor */
482     iblBootBtbl (&i2cinit_boot_module, &entry);
484     if (btblWrapEcode != 0)  {
485         iblStatus.iblFail = ibl_FAIL_CODE_BTBL_FAIL;
486         for (;;);
487     }
489     /* jump to the exit point, which will be the entry point for the full IBL */
490     exit = (void (*)())entry;
491     (*exit)();