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);
105 }
107 /**
108 * @brief
109 * Do a 2 byte endian swap
110 */
111 uint16 swap16val (uint16 v)
112 {
113 v = (((v >> 8) & 0xff) << 0) |
114 (((v >> 0) & 0xff) << 8);
116 return (v);
118 }
120 /**
121 * @brief
122 * Do an endian swap on the ibl structure
123 */
124 void iblSwap (void)
125 {
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);
190 }
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)
213 {
214 Int32 count;
216 if (i2cFifoIn >= i2cFifoOut)
217 count = i2cFifoIn - i2cFifoOut;
218 else
219 count = i2cFifoIn + I2C_MAX_BLOCK_SIZE - i2cFifoOut;
221 return (count);
223 }
226 /**
227 * @brief
228 * Read a byte from the fifo
229 */
230 Uint8 i2cFifoRead(void)
231 {
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);
246 }
248 /**
249 * @brief
250 * Read a block of data from the I2C eeprom and put it in the fifo
251 */
252 void i2cReadBlock (void)
253 {
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 */
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 */
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;
299 iblStatus.i2cDataRetries += 1;
301 }
304 i2cReadAddress += len;
306 i2cFifoIn = len;
307 i2cFifoOut = 4; /* The i2c header is effectively removed */
309 }
314 /**
315 * @brief
316 * Read data from the I2C to pass to the interpreter
317 */
318 Int32 iblI2cRead (Uint8 *buf, Uint32 num_bytes)
319 {
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);
332 }
336 /**
337 * @brief
338 * The module function table used for boot from i2c
339 */
340 BOOT_MODULE_FXN_TABLE i2cinit_boot_module =
341 {
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)
364 {
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();
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) {
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)();
494 }