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 * The malloc function used for both boot stages of the ibl
60 */
61 void *iblMalloc (Uint32 size)
62 {
63 return (malloc (size));
64 }
66 /**
67 * @brief
68 * The free function used for both stages of the ibl
69 */
70 void iblFree (void *mem)
71 {
72 free (mem);
73 }
75 /**
76 * @brief
77 * The memset function used for both stages of the ibl
78 */
79 void *iblMemset (void *mem, Int32 ch, Uint32 n)
80 {
81 return (memset (mem, ch, n));
82 }
84 /**
85 * @brief
86 * The memcpy function used for both stages of the ibl
87 */
88 void *iblMemcpy (void *s1, const void *s2, Uint32 n)
89 {
90 return (memcpy (s1, s2, n));
92 }
94 /**
95 * @brief
96 * Ones complement addition
97 */
98 inline uint16 onesComplementAdd (uint16 value1, uint16 value2)
99 {
100 uint32 result;
102 result = (uint32)value1 + (uint32)value2;
104 result = (result >> 16) + (result & 0xFFFF); /* add in carry */
105 result += (result >> 16); /* maybe one more */
106 return ((uint16)result);
107 }
110 /**
111 * @brief
112 * Ones complement checksum computation
113 */
114 uint16 onesComplementChksum (uint16 * restrict p_data, uint16 len)
115 {
116 uint16 chksum = 0;
118 while (len > 0)
119 {
120 chksum = onesComplementAdd(chksum, *p_data);
121 p_data++;
122 len--;
123 }
124 return (chksum);
125 }
129 /**
130 * @brief
131 * Do a 4 byte endian swap
132 */
133 uint32 swap32val (uint32 v)
134 {
135 v = (((v >> 24) & 0xff) << 0) |
136 (((v >> 16) & 0xff) << 8) |
137 (((v >> 8) & 0xff) << 16) |
138 (((v >> 0) & 0xff) << 24);
140 return (v);
142 }
144 /**
145 * @brief
146 * Do a 2 byte endian swap
147 */
148 uint16 swap16val (uint16 v)
149 {
150 v = (((v >> 8) & 0xff) << 0) |
151 (((v >> 0) & 0xff) << 8);
153 return (v);
155 }
157 /**
158 * @brief
159 * Do an endian swap on the ibl structure
160 */
161 void iblSwap (void)
162 {
163 int i;
165 ibl.iblMagic = swap32val (ibl.iblMagic);
167 for (i = 0; i < ibl_N_PLL_CFGS; i++) {
168 ibl.pllConfig[i].doEnable = swap16val (ibl.pllConfig[i].doEnable);
169 ibl.pllConfig[i].prediv = swap32val (ibl.pllConfig[i].prediv);
170 ibl.pllConfig[i].mult = swap32val (ibl.pllConfig[i].mult);
171 ibl.pllConfig[i].postdiv = swap32val (ibl.pllConfig[i].postdiv);
172 ibl.pllConfig[i].pllOutFreqMhz = swap32val (ibl.pllConfig[i].pllOutFreqMhz);
173 }
175 ibl.ddrConfig.configDdr = swap16val (ibl.ddrConfig.configDdr);
177 #define targetEmifType() ibl_EMIF_TYPE_40
179 if (targetEmifType() == ibl_EMIF_TYPE_31) {
180 ibl.ddrConfig.uEmif.emif3p1.sdcfg = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdcfg);
181 ibl.ddrConfig.uEmif.emif3p1.sdrfc = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdrfc);
182 ibl.ddrConfig.uEmif.emif3p1.sdtim1 = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdtim1);
183 ibl.ddrConfig.uEmif.emif3p1.sdtim2 = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdtim2);
184 ibl.ddrConfig.uEmif.emif3p1.dmcctl = swap32val(ibl.ddrConfig.uEmif.emif3p1.dmcctl);
186 } else if (targetEmifType() == ibl_EMIF_TYPE_40) {
187 ibl.ddrConfig.uEmif.emif4p0.registerMask = swap32val(ibl.ddrConfig.uEmif.emif4p0.registerMask);
188 ibl.ddrConfig.uEmif.emif4p0.sdRamConfig = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamConfig);
189 ibl.ddrConfig.uEmif.emif4p0.sdRamConfig2 = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamConfig2);
190 ibl.ddrConfig.uEmif.emif4p0.sdRamRefreshCtl = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamRefreshCtl);
191 ibl.ddrConfig.uEmif.emif4p0.sdRamTiming1 = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamTiming1);
192 ibl.ddrConfig.uEmif.emif4p0.sdRamTiming2 = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamTiming2);
193 ibl.ddrConfig.uEmif.emif4p0.sdRamTiming3 = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamTiming3);
194 ibl.ddrConfig.uEmif.emif4p0.lpDdrNvmTiming = swap32val(ibl.ddrConfig.uEmif.emif4p0.lpDdrNvmTiming);
195 ibl.ddrConfig.uEmif.emif4p0.powerManageCtl = swap32val(ibl.ddrConfig.uEmif.emif4p0.powerManageCtl);
196 ibl.ddrConfig.uEmif.emif4p0.iODFTTestLogic = swap32val(ibl.ddrConfig.uEmif.emif4p0.iODFTTestLogic);
197 ibl.ddrConfig.uEmif.emif4p0.performCountCfg = swap32val(ibl.ddrConfig.uEmif.emif4p0.performCountCfg);
198 ibl.ddrConfig.uEmif.emif4p0.performCountMstRegSel = swap32val(ibl.ddrConfig.uEmif.emif4p0.performCountMstRegSel);
199 ibl.ddrConfig.uEmif.emif4p0.readIdleCtl = swap32val(ibl.ddrConfig.uEmif.emif4p0.readIdleCtl);
200 ibl.ddrConfig.uEmif.emif4p0.sysVbusmIntEnSet = swap32val(ibl.ddrConfig.uEmif.emif4p0.sysVbusmIntEnSet);
201 ibl.ddrConfig.uEmif.emif4p0.sdRamOutImpdedCalCfg = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamOutImpdedCalCfg);
202 ibl.ddrConfig.uEmif.emif4p0.tempAlterCfg = swap32val(ibl.ddrConfig.uEmif.emif4p0.tempAlterCfg);
203 ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl1 = swap32val(ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl1);
204 ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl2 = swap32val(ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl2);
205 ibl.ddrConfig.uEmif.emif4p0.priClassSvceMap = swap32val(ibl.ddrConfig.uEmif.emif4p0.priClassSvceMap);
206 ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce1Map = swap32val(ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce1Map);
207 ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce2Map = swap32val(ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce2Map);
208 ibl.ddrConfig.uEmif.emif4p0.eccCtl = swap32val(ibl.ddrConfig.uEmif.emif4p0.eccCtl);
209 ibl.ddrConfig.uEmif.emif4p0.eccRange1 = swap32val(ibl.ddrConfig.uEmif.emif4p0.eccRange1);
210 ibl.ddrConfig.uEmif.emif4p0.eccRange2 = swap32val(ibl.ddrConfig.uEmif.emif4p0.eccRange2);
211 ibl.ddrConfig.uEmif.emif4p0.rdWrtExcThresh = swap32val(ibl.ddrConfig.uEmif.emif4p0.rdWrtExcThresh);
212 }
215 for (i = 0; i < ibl_N_ETH_PORTS; i++) {
216 ibl.ethConfig[i].ethPriority = swap32val (ibl.ethConfig[i].ethPriority);
217 ibl.ethConfig[i].port = swap32val (ibl.ethConfig[i].port);
218 ibl.ethConfig[i].doBootp = swap16val (ibl.ethConfig[i].doBootp);
219 ibl.ethConfig[i].useBootpServerIp = swap16val (ibl.ethConfig[i].useBootpServerIp);
220 ibl.ethConfig[i].useBootpFileName = swap16val (ibl.ethConfig[i].useBootpFileName);
221 ibl.ethConfig[i].bootFormat = swap32val (ibl.ethConfig[i].bootFormat);
222 ibl.ethConfig[i].blob.startAddress = swap32val (ibl.ethConfig[i].blob.startAddress);
223 ibl.ethConfig[i].blob.sizeBytes = swap32val (ibl.ethConfig[i].blob.sizeBytes);
224 ibl.ethConfig[i].blob.branchAddress = swap32val (ibl.ethConfig[i].blob.branchAddress);
226 ibl.sgmiiConfig[i].adviseAbility = swap32val (ibl.sgmiiConfig[i].adviseAbility);
227 ibl.sgmiiConfig[i].control = swap32val (ibl.sgmiiConfig[i].control);
228 ibl.sgmiiConfig[i].txConfig = swap32val (ibl.sgmiiConfig[i].txConfig);
229 ibl.sgmiiConfig[i].rxConfig = swap32val (ibl.sgmiiConfig[i].rxConfig);
230 ibl.sgmiiConfig[i].auxConfig = swap32val (ibl.sgmiiConfig[i].auxConfig);
231 }
233 ibl.mdioConfig.nMdioOps = swap16val (ibl.mdioConfig.nMdioOps);
234 ibl.mdioConfig.mdioClkDiv = swap16val (ibl.mdioConfig.mdioClkDiv);
235 ibl.mdioConfig.interDelay = swap32val (ibl.mdioConfig.interDelay);
237 for (i = 0; i < ibl_N_MDIO_CFGS; i++)
238 ibl.mdioConfig.mdio[i] = swap32val (ibl.mdioConfig.mdio[i]);
240 ibl.nandConfig.nandPriority = swap32val (ibl.nandConfig.nandPriority);
241 ibl.nandConfig.bootFormat = swap32val (ibl.nandConfig.bootFormat);
242 ibl.nandConfig.blob.startAddress = swap32val (ibl.nandConfig.blob.startAddress);
243 ibl.nandConfig.blob.sizeBytes = swap32val (ibl.nandConfig.blob.sizeBytes);
244 ibl.nandConfig.blob.branchAddress = swap32val (ibl.nandConfig.blob.branchAddress);
246 ibl.nandConfig.nandInfo.busWidthBits = swap32val (ibl.nandConfig.nandInfo.busWidthBits);
247 ibl.nandConfig.nandInfo.pageSizeBytes = swap32val (ibl.nandConfig.nandInfo.pageSizeBytes);
248 ibl.nandConfig.nandInfo.pageEccBytes = swap32val (ibl.nandConfig.nandInfo.pageEccBytes);
249 ibl.nandConfig.nandInfo.pagesPerBlock = swap32val (ibl.nandConfig.nandInfo.pagesPerBlock);
250 ibl.nandConfig.nandInfo.totalBlocks = swap32val (ibl.nandConfig.nandInfo.totalBlocks);
251 ibl.nandConfig.nandInfo.addressBytes = swap32val (ibl.nandConfig.nandInfo.addressBytes);
252 ibl.nandConfig.nandInfo.lsbFirst = swap16val (ibl.nandConfig.nandInfo.lsbFirst);
253 ibl.nandConfig.nandInfo.blockOffset = swap32val (ibl.nandConfig.nandInfo.blockOffset);
254 ibl.nandConfig.nandInfo.pageOffset = swap32val (ibl.nandConfig.nandInfo.pageOffset);
255 ibl.nandConfig.nandInfo.columnOffset = swap32val (ibl.nandConfig.nandInfo.columnOffset);
256 ibl.nandConfig.nandInfo.postCommand = swap16val (ibl.nandConfig.nandInfo.postCommand);
258 ibl.chkSum = swap16val (ibl.chkSum);
259 }
263 /**
264 * @brief
265 * The i2c load context consists of the address of the next block
266 * to read, and a simple fifo holding any existing data.
267 */
268 #define I2C_MAX_BLOCK_SIZE 0x80
269 uint32 i2cReadAddress;
271 uint32 i2cFifoIn = 0;
272 uint32 i2cFifoOut = 0;
273 uint8 i2cData[I2C_MAX_BLOCK_SIZE];
274 uint16 i2cSum[I2C_MAX_BLOCK_SIZE >> 1];
277 /**
278 * @brief
279 * Return the number of elements in the fifo
280 */
281 Uint32 i2cFifoCount (void)
282 {
283 Int32 count;
285 if (i2cFifoIn >= i2cFifoOut)
286 count = i2cFifoIn - i2cFifoOut;
287 else
288 count = i2cFifoIn + I2C_MAX_BLOCK_SIZE - i2cFifoOut;
290 return (count);
292 }
295 /**
296 * @brief
297 * Read a byte from the fifo
298 */
299 Uint8 i2cFifoRead(void)
300 {
301 Uint8 v;
303 v = i2cData[i2cFifoOut];
305 i2cFifoOut += 1;
307 if (i2cFifoOut == i2cFifoIn)
308 i2cFifoOut = i2cFifoIn = 0;
310 if (i2cFifoOut >= I2C_MAX_BLOCK_SIZE)
311 i2cFifoOut = 0;
313 return (v);
315 }
317 /**
318 * @brief
319 * Read a block of data from the I2C eeprom and put it in the fifo
320 */
321 void i2cReadBlock (void)
322 {
323 uint16 len;
324 int32 i, j;
325 uint32 v;
327 for (;;) {
328 while (hwI2cMasterRead (i2cReadAddress & 0xffff, /* The address on the eeprom of the table */
329 4, /* The number of bytes to read */
330 i2cData, /* Where to store the bytes */
331 i2cReadAddress >> 16, /* The bus address of the eeprom */
332 IBL_CFG_I2C_ADDR_DELAY) /* The delay between sending the address and reading data */
334 != I2C_RET_OK) {
336 iblStatus.i2cDataRetries += 1;
337 }
339 /* Form the length. The received bytes are always in big endian format */
340 len = (i2cData[0] << 8) | i2cData[1];
343 if (len > I2C_MAX_BLOCK_SIZE)
344 continue;
347 while (hwI2cMasterRead (i2cReadAddress & 0xffff, /* The address on the eeprom of the table */
348 len, /* The number of bytes to read */
349 i2cData, /* Where to store the bytes */
350 i2cReadAddress >> 16, /* The bus address of the eeprom */
351 IBL_CFG_I2C_ADDR_DELAY) /* The delay between sending the address and reading data */
353 != I2C_RET_OK) {
355 iblStatus.i2cDataRetries += 1;
356 }
359 /* Must do endian conversion to verify the checksum */
360 for (i = j = 0; i < len; i += 2, j += 1)
361 i2cSum[j] = (i2cData[i+0] << 8) | i2cData[i+1];
363 v = onesComplementChksum (i2cSum, j);
364 if ((v == 0) || (v == 0xffff))
365 break;
368 iblStatus.i2cDataRetries += 1;
370 }
373 i2cReadAddress += len;
375 i2cFifoIn = len;
376 i2cFifoOut = 4; /* The i2c header is effectively removed */
378 }
383 /**
384 * @brief
385 * Read data from the I2C to pass to the interpreter
386 */
387 Int32 iblI2cRead (Uint8 *buf, Uint32 num_bytes)
388 {
389 int i;
391 for (i = 0; i < num_bytes; i++) {
393 if (i2cFifoCount() == 0)
394 i2cReadBlock ();
396 buf[i] = i2cFifoRead();
397 }
399 return (0);
401 }
403 #define iblBITMASK(x,y) ( ( ( ((UINT32)1 << (((UINT32)x)-((UINT32)y)+(UINT32)1) ) - (UINT32)1 ) ) << ((UINT32)y) )
404 #define iblREAD_BITFIELD(z,x,y) (((UINT32)z) & iblBITMASK(x,y)) >> (y)
405 /**
406 * @brief
407 * Return the lower 16 bits of a 32 bit value. A function is used (with cross-function optomization off)
408 * which results in an endian independent version
409 */
410 uint16 readLower16 (uint32 v)
411 {
412 return (iblREAD_BITFIELD(v,15,0));
414 }
416 /**
417 * @brief
418 * Return the upper 16 bits of a 32 bit value. A function is used to force an endian independent version
419 */
420 uint16 readUpper16 (uint32 v)
421 {
422 return (iblREAD_BITFIELD(v,31,16));
423 }
426 /**
427 * @brief
428 * The module function table used for boot from i2c
429 */
430 BOOT_MODULE_FXN_TABLE i2cinit_boot_module =
431 {
432 NULL, /* Open API */
433 NULL, /* Close API */
434 iblI2cRead, /* Read API */
435 NULL, /* Write API */
436 NULL, /* Peek API */
437 NULL, /* Seek API */
438 NULL /* Query API */
439 };
443 /**
444 * @brief
445 * The main function
446 *
447 * @details
448 * The ibl configuration parameters are read from the i2c,
449 * followed by the i2c mapping information. The second stage
450 * of the IBL is then loaded, and execution transferred
451 * to the second stage.
452 */
453 void main (void)
454 {
456 uint16 v;
457 uint16 configAddrLsw;
458 uint16 configAddrMsw;
459 uint32 entry;
460 void (*exit)();
461 iblI2cMap_t map;
463 memset (&iblStatus, 0, sizeof(iblStatus_t));
464 iblStatus.iblMagic = ibl_MAGIC_VALUE;
465 iblStatus.iblVersion = ibl_VERSION;
466 iblStatus.activePeriph = ibl_ACTIVE_PERIPH_I2C;
468 /* Read the endianness setting of the device */
469 littleEndian = deviceIsLittleEndian();
471 /* Load the default configuration table from the i2c. The actual speed of the device
472 * isn't really known here, since it is part of the table, so a compile time
473 * value is used (the pll may have been configured during the initial load) */
474 hwI2Cinit (IBL_CFG_I2C_DEV_FREQ_MHZ, /* The CPU frequency during I2C data load */
475 DEVICE_I2C_MODULE_DIVISOR, /* The divide down of CPU that drives the i2c */
476 IBL_CFG_I2C_CLK_FREQ_KHZ, /* The I2C data rate used during table load */
477 IBL_CFG_I2C_OWN_ADDR); /* The address used by this device on the i2c bus */
480 /* Read the I2C mapping information from the eeprom */
481 for (;;) {
482 if (hwI2cMasterRead (IBL_CFG_I2C_MAP_TABLE_DATA_ADDR, /* The address on the eeprom of the data mapping */
483 sizeof(iblI2cMap_t), /* The number of bytes to read */
484 (UINT8 *)&map, /* Where to store the bytes */
485 IBL_CFG_I2C_MAP_TABLE_DATA_BUS_ADDR, /* The bus address of the eeprom */
486 IBL_CFG_I2C_ADDR_DELAY) /* The delay between sending the address and reading data */
488 == I2C_RET_OK) {
490 /* On the I2C EEPROM the table is always formatted with the most significant
491 * byte first. So if the device is running little endain the endian must be
492 * swapped */
493 if (littleEndian == TRUE) {
494 map.length = swap16val (map.length);
495 map.chkSum = swap16val (map.chkSum);
496 map.addrLe = swap32val (map.addrLe);
497 map.configLe = swap32val (map.configLe);
498 map.addrBe = swap32val (map.addrBe);
499 map.configBe = swap32val (map.configBe);
501 configAddrLsw = readLower16 (map.configLe);
502 configAddrMsw = readUpper16 (map.configLe);
504 } else {
505 configAddrLsw = readLower16 (map.configBe);
506 configAddrMsw = readUpper16 (map.configLe);
508 }
511 if (map.length != sizeof(iblI2cMap_t)) {
512 iblStatus.mapSizeFail += 1;
513 continue;
514 }
516 if (map.chkSum != 0) {
518 v = onesComplementChksum ((UINT16 *)&map, sizeof(iblI2cMap_t));
519 if ((v != 0) && (v != 0xffff)) {
520 iblStatus.mapRetries += 1;
521 continue;
522 }
523 }
525 break;
526 }
528 iblStatus.mapRetries += 1;
530 }
533 /* Read the i2c configuration tables until the checksum passes and the magic number
534 * matches. The checksum must be verified before the endian re-ordering is done */
535 for (;;) {
537 if (hwI2cMasterRead (configAddrLsw, /* The address on the eeprom of the table */
538 sizeof(ibl_t), /* The number of bytes to read */
539 (UINT8 *)&ibl, /* Where to store the bytes */
540 configAddrMsw, /* The bus address of the eeprom */
541 IBL_CFG_I2C_ADDR_DELAY) /* The delay between sending the address and reading data */
543 == I2C_RET_OK) {
545 if (ibl.chkSum != 0) {
547 v = onesComplementChksum ((UINT16 *)&ibl, sizeof(ibl_t) / sizeof(UINT16));
548 if ((v != 0) && (v != 0xffff)) {
549 iblStatus.i2cRetries += 1;
550 continue;
551 }
553 }
556 if (ibl.iblMagic == ibl_MAGIC_VALUE)
557 break;
559 if (swap32val (ibl.iblMagic) == ibl_MAGIC_VALUE) {
560 iblSwap ();
561 break;
562 }
564 iblStatus.magicRetries += 1;
566 }
568 iblStatus.i2cRetries += 1;
569 }
571 /* Pll configuration is device specific */
572 devicePllConfig ();
575 /* The rest of the IBL is in boot table format. Read and process the data */
576 if (littleEndian == TRUE)
577 i2cReadAddress = map.addrLe;
578 else
579 i2cReadAddress = map.addrBe;
581 if (i2cReadAddress == 0xffffffff) {
582 iblStatus.iblFail = ibl_FAIL_CODE_INVALID_I2C_ADDRESS;
583 for (;;);
584 }
587 /* Pass control to the boot table processor */
588 iblBootBtbl (&i2cinit_boot_module, &entry);
590 if (btblWrapEcode != 0) {
591 iblStatus.iblFail = ibl_FAIL_CODE_BTBL_FAIL;
592 for (;;);
593 }
595 /* jump to the exit point, which will be the entry point for the full IBL */
596 exit = (void (*)())entry;
597 (*exit)();
600 }