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 #include "ibl.h"
37 #include "iblloc.h"
38 #include "iblcfg.h"
39 #include "device.h"
40 #include "iblbtbl.h"
41 #include "i2c.h"
42 #include "iblinit.h"
43 #include <string.h>
45 #ifndef EXCLUDE_I2C
46 /**
47 * @brief
48 * A global value is used to track the read through the i2c during
49 * the program load.
50 */
51 uint32 i2cReadAddress, i2cBusAddress;
53 /**
54 * @brief
55 * Read a block of data from the I2C eeprom and put it in the fifo
56 */
57 void i2cReadBlock (void)
58 {
59 uint16 len;
60 int32 i, j;
61 uint32 v;
63 for (;;) {
64 while (hwI2cMasterRead (i2cReadAddress, /* The address on the eeprom of the table */
65 4, /* The number of bytes to read */
66 iData, /* Where to store the bytes */
67 i2cBusAddress, /* The bus address of the eeprom */
68 IBL_CFG_I2C_ADDR_DELAY) /* The delay between sending the address and reading data */
70 != I2C_RET_OK) {
72 iblStatus.i2cDataRetries += 1;
73 }
75 /* Form the length. The received bytes are always in big endian format */
76 len = (iData[0] << 8) | iData[1];
79 if (len > I_MAX_BLOCK_SIZE)
80 continue;
83 while (hwI2cMasterRead (i2cReadAddress, /* The address on the eeprom of the table */
84 len, /* The number of bytes to read */
85 iData, /* Where to store the bytes */
86 i2cBusAddress, /* The bus address of the eeprom */
87 IBL_CFG_I2C_ADDR_DELAY) /* The delay between sending the address and reading data */
89 != I2C_RET_OK) {
91 iblStatus.i2cDataRetries += 1;
92 }
95 /* Must do endian conversion to verify the checksum */
96 for (i = j = 0; i < len; i += 2, j += 1)
97 iSum[j] = (iData[i+0] << 8) | iData[i+1];
99 v = onesComplementChksum (iSum, j);
100 if ((v == 0) || (v == 0xffff))
101 break;
104 iblStatus.i2cDataRetries += 1;
106 }
109 i2cReadAddress += len;
110 i2cBusAddress = i2cReadAddress >>16;
112 iFifoIn = len;
113 iFifoOut = 4; /* The i2c header is effectively removed */
115 }
120 /**
121 * @brief
122 * Read data from the I2C to pass to the interpreter
123 */
124 Int32 iblI2cRead (Uint8 *buf, Uint32 num_bytes)
125 {
126 int i;
128 for (i = 0; i < num_bytes; i++) {
130 if (iFifoCount() == 0)
131 i2cReadBlock ();
133 buf[i] = iFifoRead();
134 }
136 return (0);
138 }
141 /**
142 * @brief
143 * The module function table used for boot from i2c
144 */
145 BOOT_MODULE_FXN_TABLE i2cinit_boot_module =
146 {
147 NULL, /* Open API */
148 NULL, /* Close API */
149 iblI2cRead, /* Read API */
150 NULL, /* Write API */
151 NULL, /* Peek API */
152 NULL, /* Seek API */
153 NULL /* Query API */
154 };
157 /**
158 * @brief
159 * Configure the I2C, then read the parameters from I2C and pass
160 * to the second stage boot
161 */
162 BOOT_MODULE_FXN_TABLE *iblInitI2c (void)
163 {
164 uint16 v;
165 uint16 configAddrLsw;
166 uint16 configAddrMsw;
167 iblBootMap_t map;
168 bool littleEndian;
170 /* Read the endianness setting of the device */
171 littleEndian = deviceIsLittleEndian();
173 /* Load the default configuration table from the i2c. The actual speed of the device
174 * isn't really known here, since it is part of the table, so a compile time
175 * value is used (the pll may have been configured during the initial load) */
176 hwI2Cinit (IBL_CFG_I2C_DEV_FREQ_MHZ, /* The CPU frequency during I2C data load */
177 DEVICE_I2C_MODULE_DIVISOR, /* The divide down of CPU that drives the i2c */
178 IBL_CFG_I2C_CLK_FREQ_KHZ, /* The I2C data rate used during table load */
179 IBL_CFG_I2C_OWN_ADDR); /* The address used by this device on the i2c bus */
182 /* Read the I2C mapping information from the eeprom */
183 for (;;) {
184 if (hwI2cMasterRead (IBL_CFG_I2C_MAP_TABLE_DATA_ADDR, /* The address on the eeprom of the data mapping */
185 sizeof(iblBootMap_t), /* The number of bytes to read */
186 (UINT8 *)&map, /* Where to store the bytes */
187 IBL_CFG_I2C_MAP_TABLE_DATA_BUS_ADDR, /* The bus address of the eeprom */
188 IBL_CFG_I2C_ADDR_DELAY) /* The delay between sending the address and reading data */
190 == I2C_RET_OK) {
192 /* On the I2C EEPROM the table is always formatted with the most significant
193 * byte first. So if the device is running little endain the endian must be
194 * swapped */
195 if (littleEndian == TRUE) {
196 map.length = swap16val (map.length);
197 map.chkSum = swap16val (map.chkSum);
198 map.addrLe = swap32val (map.addrLe);
199 map.configLe = swap32val (map.configLe);
200 map.addrBe = swap32val (map.addrBe);
201 map.configBe = swap32val (map.configBe);
203 configAddrLsw = readLower16 (map.configLe);
204 configAddrMsw = readUpper16 (map.configLe);
205 i2cReadAddress = map.addrLe;
207 } else {
208 configAddrLsw = readLower16 (map.configBe);
209 configAddrMsw = readUpper16 (map.configBe);
210 i2cReadAddress = map.addrBe;
212 }
214 i2cBusAddress = i2cReadAddress >>16;
216 if (map.length != sizeof(iblBootMap_t)) {
217 iblStatus.mapSizeFail += 1;
218 continue;
219 }
221 if (map.chkSum != 0) {
223 v = onesComplementChksum ((UINT16 *)&map, sizeof(iblBootMap_t));
224 if ((v != 0) && (v != 0xffff)) {
225 iblStatus.mapRetries += 1;
226 continue;
227 }
228 }
230 break;
231 }
233 iblStatus.mapRetries += 1;
235 }
238 /* Read the i2c configuration tables until the checksum passes and the magic number
239 * matches. The checksum must be verified before the endian re-ordering is done */
240 for (;;) {
242 if (hwI2cMasterRead (configAddrLsw, /* The address on the eeprom of the table */
243 sizeof(ibl_t), /* The number of bytes to read */
244 (UINT8 *)&ibl, /* Where to store the bytes */
245 configAddrMsw, /* The bus address of the eeprom */
246 IBL_CFG_I2C_ADDR_DELAY) /* The delay between sending the address and reading data */
248 == I2C_RET_OK) {
250 if (ibl.chkSum != 0) {
252 v = onesComplementChksum ((UINT16 *)&ibl, sizeof(ibl_t) / sizeof(UINT16));
253 if ((v != 0) && (v != 0xffff)) {
254 iblStatus.i2cRetries += 1;
255 continue;
256 }
258 }
261 if (ibl.iblMagic == ibl_MAGIC_VALUE)
262 break;
264 if (swap32val (ibl.iblMagic) == ibl_MAGIC_VALUE) {
265 iblSwap ();
266 break;
267 }
269 iblStatus.magicRetries += 1;
271 }
273 iblStatus.i2cRetries += 1;
274 }
276 /* The rest of the IBL is in boot table format. Read and process the data */
277 if (i2cReadAddress == 0xffffffff) {
278 iblStatus.iblFail = ibl_FAIL_CODE_INVALID_I2C_ADDRESS;
279 for (;;);
280 }
282 return (&i2cinit_boot_module);
284 }
286 #endif /* EXCLUDE_I2C */