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 "spi_api.h"
42 #include "iblinit.h"
43 #include <string.h>
45 #if (!defined(EXCLUDE_NOR_SPI) || !defined(EXCLUDE_NAND_SPI))
47 /**
48 * @brief
49 * The next read address on the SPI flash is stored in a global for
50 * access through the boot call chain.
51 */
52 uint32 spiReadAddress;
54 /**
55 * @brief
56 * Read a block of data from the SPI eeprom and put it in the fifo
57 */
58 void spiReadBlock (void)
59 {
60 uint16 len;
61 int32 i, j;
62 uint32 v;
64 for (;;) {
65 while (hwSpiRead (spiReadAddress, /* The address on the eeprom of the table */
66 4, /* The number of bytes to read */
67 iData) /* Where to store the bytes */
69 != 0) {
71 iblStatus.spiDataRetries += 1;
72 }
74 /* Form the length. The received bytes are always in big endian format */
75 len = (iData[0] << 8) | iData[1];
78 if (len > I_MAX_BLOCK_SIZE)
79 continue;
82 while (hwSpiRead (spiReadAddress, /* The address on the eeprom of the table */
83 len, /* The number of bytes to read */
84 iData) /* Where to store the bytes */
86 != 0) {
88 iblStatus.spiDataRetries += 1;
89 }
92 /* Must do endian conversion to verify the checksum */
93 for (i = j = 0; i < len; i += 2, j += 1)
94 iSum[j] = (iData[i+0] << 8) | iData[i+1];
96 v = onesComplementChksum (iSum, j);
97 if ((v == 0) || (v == 0xffff))
98 break;
101 iblStatus.spiDataRetries += 1;
103 }
106 spiReadAddress += len;
108 iFifoIn = len;
109 iFifoOut = 4; /* The spi header is effectively removed */
111 }
115 /**
116 * @brief
117 * Read data from the SPI to pass to the interpreter
118 */
119 Int32 iblSpiRead (Uint8 *buf, Uint32 num_bytes)
120 {
121 int i;
123 for (i = 0; i < num_bytes; i++) {
125 if (iFifoCount() == 0)
126 spiReadBlock ();
128 buf[i] = iFifoRead();
129 }
131 return (0);
133 }
136 /**
137 * @brief
138 * The module function table used for boot from spi
139 */
140 BOOT_MODULE_FXN_TABLE spiinit_boot_module =
141 {
142 NULL, /* Open API */
143 NULL, /* Close API */
144 iblSpiRead, /* Read API */
145 NULL, /* Write API */
146 NULL, /* Peek API */
147 NULL, /* Seek API */
148 NULL /* Query API */
149 };
154 /**
155 * @brief
156 * Configure the SPI, then read the parameters from the SPI and
157 * pass them to the second stage boot
158 */
159 BOOT_MODULE_FXN_TABLE *iblInitSpiNor (void)
160 {
161 iblBootMap_t map;
162 spiConfig_t cfg;
163 uint32 configAddr;
165 bool littleEndian;
166 uint16 v;
168 /* Read the endianness of the device */
169 littleEndian = deviceIsLittleEndian();
171 /* Load the default configuration table from the SPI. The actual speed of
172 * the device isn't really known here, since it is part of the table, so a
173 * compile time value is used (the pll may have been configured during the initial load) */
174 deviceLoadInitSpiConfig ((void *)&cfg);
176 if (hwSpiConfig (&cfg) != 0) {
178 iblStatus.iblFail = ibl_FAIL_CODE_SPI_PARAMS;
179 for (;;);
181 }
184 /* Read the SPI mapping information from the nor flash */
185 for (;;) {
187 if (hwSpiRead ((IBL_CFG_SPI_MAP_TABLE_DATA_ADDR_MSW << 16) | /* The address on the flash of the data mapping */
188 IBL_CFG_SPI_MAP_TABLE_DATA_ADDR_LSW,
189 sizeof(iblBootMap_t), /* The number of bytes to read */
190 (UINT8 *)&map) /* Where to store the data */
192 == 0) {
194 /* On the flash the table is always formatted with the most significant
195 * byte first. So if the device is running little endian, the endian
196 * must be swapped */
197 if (littleEndian == TRUE) {
198 map.length = swap16val (map.length);
199 map.chkSum = swap16val (map.chkSum);
200 map.addrLe = swap32val (map.addrLe);
201 map.configLe = swap32val (map.configLe);
202 map.addrBe = swap32val (map.addrBe);
203 map.configBe = swap32val (map.configBe);
205 configAddr = map.configLe;
206 spiReadAddress = map.addrLe;
208 } else {
210 configAddr = map.configBe;
211 spiReadAddress = map.addrBe;
213 }
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;
232 }
234 iblStatus.mapRetries += 1;
236 }
239 /* Read the SPI configuration tables until the checksum passes and the magic
240 * number matches. The checksum must be verified before the endian re-ordering */
241 for (;;) {
243 if (hwSpiRead (configAddr, /* The address on the flash of the table */
244 sizeof(ibl_t), /* The number of bytes to read */
245 (UINT8 *)&ibl) /* Where to store the bytes */
246 == 0) {
248 if (ibl.chkSum != 0) {
250 v = onesComplementChksum ((UINT16 *)&ibl, sizeof(ibl_t) / sizeof(UINT16));
251 if ((v != 0) && (v != 0xffff)) {
252 iblStatus.spiRetries += 1;
253 continue;
254 }
255 }
257 if (ibl.iblMagic == ibl_MAGIC_VALUE)
258 break;
260 if (swap32val (ibl.iblMagic) == ibl_MAGIC_VALUE) {
261 iblSwap ();
262 break;
263 }
265 iblStatus.magicRetries += 1;
267 }
269 iblStatus.spiRetries += 1;
271 }
274 /* the rest of the IBL is in boot table format. Read and process the data */
275 if (spiReadAddress == 0xffffffff) {
276 iblStatus.iblFail = ibl_FAIL_CODE_INVALID_SPI_ADDRESS;
277 for (;;);
278 }
280 return (&spiinit_boot_module);
282 }
285 #endif /* (!defined(EXCLUDE_NOR_SPI) || !defined(EXCLUDE_NAND_SPI)) */