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)
100 {
101 free (mem);
102 }
104 /**
105 * @brief
106 * The memset function used for both stages of the ibl
107 */
108 void *iblMemset (void *mem, Int32 ch, Uint32 n)
109 {
110 return (memset (mem, ch, n));
111 }
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)
118 {
119 return (memcpy (s1, s2, n));
121 }
123 /**
124 * @brief
125 * Ones complement addition
126 */
127 inline uint16 onesComplementAdd (uint16 value1, uint16 value2)
128 {
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);
136 }
139 /**
140 * @brief
141 * Ones complement checksum computation
142 */
143 uint16 onesComplementChksum (uint16 * restrict p_data, uint16 len)
144 {
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)
163 {
164 v = (((v >> 24) & 0xff) << 0) |
165 (((v >> 16) & 0xff) << 8) |
166 (((v >> 8) & 0xff) << 16) |
167 (((v >> 0) & 0xff) << 24);
169 return (v);
171 }
173 /**
174 * @brief
175 * Do a 2 byte endian swap
176 */
177 uint16 swap16val (uint16 v)
178 {
179 v = (((v >> 8) & 0xff) << 0) |
180 (((v >> 0) & 0xff) << 8);
182 return (v);
184 }
186 /**
187 * @brief
188 * Do an endian swap on the ibl structure
189 */
190 void iblSwap (void)
191 {
192 int i;
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);
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 = swap32val(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 }
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 = swap32val(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 = swap32val(ibl.bootModes[i].u.ethBoot.doBootp);
282 ibl.bootModes[i].u.ethBoot.useBootpServerIp = swap32val(ibl.bootModes[i].u.ethBoot.useBootpServerIp);
283 ibl.bootModes[i].u.ethBoot.useBootpFileName = swap32val(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 ibl.bootModes[i].u.nandBoot.bootAddress = swap32val(ibl.bootModes[i].u.nandBoot.bootAddress);
292 ibl.bootModes[i].u.nandBoot.interface = swap32val(ibl.bootModes[i].u.nandBoot.interface);
293 ibl.bootModes[i].u.nandBoot.blob.startAddress = swap32val(ibl.bootModes[i].u.nandBoot.blob.startAddress);
294 ibl.bootModes[i].u.nandBoot.blob.sizeBytes = swap32val(ibl.bootModes[i].u.nandBoot.blob.sizeBytes);
295 ibl.bootModes[i].u.nandBoot.blob.branchAddress = swap32val(ibl.bootModes[i].u.nandBoot.blob.branchAddress);
296 ibl.bootModes[i].u.nandBoot.nandInfo.busWidthBits = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.busWidthBits);
297 ibl.bootModes[i].u.nandBoot.nandInfo.pageSizeBytes = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pageSizeBytes);
298 ibl.bootModes[i].u.nandBoot.nandInfo.pageEccBytes = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pageEccBytes);
299 ibl.bootModes[i].u.nandBoot.nandInfo.pagesPerBlock = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pagesPerBlock);
300 ibl.bootModes[i].u.nandBoot.nandInfo.totalBlocks = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.totalBlocks);
301 ibl.bootModes[i].u.nandBoot.nandInfo.addressBytes = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.addressBytes);
302 ibl.bootModes[i].u.nandBoot.nandInfo.lsbFirst = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.lsbFirst);
303 ibl.bootModes[i].u.nandBoot.nandInfo.blockOffset = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.blockOffset);
304 ibl.bootModes[i].u.nandBoot.nandInfo.pageOffset = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pageOffset);
305 ibl.bootModes[i].u.nandBoot.nandInfo.columnOffset = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.columnOffset);
306 ibl.bootModes[i].u.nandBoot.nandInfo.postCommand = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.postCommand);
308 } else if (ibl.bootModes[i].bootMode == ibl_BOOT_MODE_NOR) {
309 ibl.bootModes[i].u.norBoot.bootFormat = swap32val(ibl.bootModes[i].u.norBoot.bootFormat);
310 ibl.bootModes[i].u.norBoot.bootAddress = swap32val(ibl.bootModes[i].u.norBoot.bootAddress);
311 ibl.bootModes[i].u.norBoot.interface = swap32val(ibl.bootModes[i].u.norBoot.interface);
312 ibl.bootModes[i].u.norBoot.blob.startAddress = swap32val(ibl.bootModes[i].u.norBoot.blob.startAddress);
313 ibl.bootModes[i].u.norBoot.blob.sizeBytes = swap32val(ibl.bootModes[i].u.norBoot.blob.sizeBytes);
314 ibl.bootModes[i].u.norBoot.blob.branchAddress = swap32val(ibl.bootModes[i].u.norBoot.blob.branchAddress);
316 }
318 }
320 ibl.chkSum = swap16val (ibl.chkSum);
321 }
325 /**
326 * @brief
327 * The init load context consists of the address of the next block
328 * to read, and a simple fifo-ish structure holding any existing data.
329 *
330 * A full fifo is not defined here. The individual init load blocks
331 * (I2C, SPI NOR, SPI NAND) will poke the structure values directly
332 * to minimize the compiled code size. Most notably is the absence
333 * of the write function. This fifo will always be completely emptied
334 * before any writes are done, so writes are always done from the top.
335 */
336 uint32 iFifoIn = 0;
337 uint32 iFifoOut = 0;
338 uint8 iData[I_MAX_BLOCK_SIZE];
340 /**
341 * @brief
342 * Checkum calculation. 16 bit values constructed from received bytes
343 * always in big endian format, regardless of the endianness of the device
344 */
345 uint16 iSum[I_MAX_BLOCK_SIZE >> 1];
348 /**
349 * @brief
350 * Return the number of elements in the fifo
351 */
352 Uint32 iFifoCount (void)
353 {
354 Int32 count;
356 if (iFifoIn >= iFifoOut)
357 count = iFifoIn - iFifoOut;
358 else
359 count = iFifoIn + I_MAX_BLOCK_SIZE - iFifoOut;
361 return (count);
363 }
366 /**
367 * @brief
368 * Read a byte from the fifo
369 */
370 Uint8 iFifoRead(void)
371 {
372 Uint8 v;
374 v = iData[iFifoOut];
376 iFifoOut += 1;
378 if (iFifoOut == iFifoIn)
379 iFifoOut = iFifoIn = 0;
381 if (iFifoOut >= I_MAX_BLOCK_SIZE)
382 iFifoOut = 0;
384 return (v);
386 }
389 #define iblBITMASK(x,y) ( ( ( ((UINT32)1 << (((UINT32)x)-((UINT32)y)+(UINT32)1) ) - (UINT32)1 ) ) << ((UINT32)y) )
390 #define iblREAD_BITFIELD(z,x,y) (((UINT32)z) & iblBITMASK(x,y)) >> (y)
391 /**
392 * @brief
393 * Return the lower 16 bits of a 32 bit value. A function is used (with cross-function optomization off)
394 * which results in an endian independent version
395 */
396 uint16 readLower16 (uint32 v)
397 {
398 return (iblREAD_BITFIELD(v,15,0));
400 }
402 /**
403 * @brief
404 * Return the upper 16 bits of a 32 bit value. A function is used to force an endian independent version
405 */
406 uint16 readUpper16 (uint32 v)
407 {
408 return (iblREAD_BITFIELD(v,31,16));
409 }
413 /**
414 * @brief
415 * The main function
416 *
417 * @details
418 * The ibl configuration parameters are read from the i2c,
419 * followed by the i2c mapping information. The second stage
420 * of the IBL is then loaded, and execution transferred
421 * to the second stage.
422 */
423 void main (void)
424 {
426 int32 bootDevice;
427 uint32 entry;
428 void (*exit)();
430 BOOT_MODULE_FXN_TABLE *bFxnTbl;
432 memset (&iblStatus, 0, sizeof(iblStatus_t));
433 iblStatus.iblMagic = ibl_MAGIC_VALUE;
434 iblStatus.iblVersion = ibl_VERSION;
435 iblStatus.activeDevice = ibl_ACTIVE_DEVICE_I2C;
438 /* Determine the boot device to read from */
439 bootDevice = deviceReadBootDevice();
441 switch (bootDevice) {
443 #ifndef EXCLUDE_I2C
444 case BOOT_DEVICE_I2C: bFxnTbl = iblInitI2c ();
445 break;
446 #endif
448 #ifndef EXCLUDE_NOR_SPI
449 case BOOT_DEVICE_SPI_NOR: bFxnTbl = iblInitSpiNor ();
450 break;
451 #endif
454 default: iblStatus.iblFail = ibl_FAIL_CODE_INVALID_INIT_DEVICE;
455 for (;;);
457 }
460 /* Pll configuration is device specific */
461 devicePllConfig ();
463 /* Enable the EDC for local memory */
464 if (IBL_ENABLE_EDC)
465 {
466 iblEnableEDC ();
467 }
469 /* Check if need to enter Rom boot loader again */
470 if (IBL_ENTER_ROM)
471 {
472 iblEnterRom ();
473 }
475 /* Pass control to the boot table processor */
476 iblBootBtbl (bFxnTbl, &entry);
478 if (btblWrapEcode != 0) {
479 iblStatus.iblFail = ibl_FAIL_CODE_BTBL_FAIL;
480 for (;;);
481 }
483 /* jump to the exit point, which will be the entry point for the full IBL */
484 exit = (void (*)())entry;
485 (*exit)();
488 }