Added loading of second stage through SPI
[keystone-rtos/ibl.git] / src / main / ibliniti2c.c
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 /**
46  *  @brief
47  *      A global value is used to track the read through the i2c during
48  *      the program load.
49  */
50 uint32 i2cReadAddress;
52 /**
53  *  @brief
54  *      Read a block of data from the I2C eeprom and put it in the fifo
55  */
56 void i2cReadBlock (void)
57 {
58     uint16 len;
59     int32  i, j;
60     uint32 v;
62     for (;;) {
63         while (hwI2cMasterRead (i2cReadAddress & 0xffff,    /* The address on the eeprom of the table */
64                                 4,                          /* The number of bytes to read */
65                                 iData,                      /* Where to store the bytes */
66                                 i2cReadAddress >> 16,       /* The bus address of the eeprom */
67                                 IBL_CFG_I2C_ADDR_DELAY)     /* The delay between sending the address and reading data */
68     
69              != I2C_RET_OK)  {
71             iblStatus.i2cDataRetries += 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 (hwI2cMasterRead (i2cReadAddress & 0xffff,    /* The address on the eeprom of the table */
83                                 len,                        /* The number of bytes to read */
84                                 iData,                      /* Where to store the bytes */
85                                 i2cReadAddress >> 16,       /* The bus address of the eeprom */
86                                 IBL_CFG_I2C_ADDR_DELAY)     /* The delay between sending the address and reading data */
87     
88              != I2C_RET_OK)  {
90             iblStatus.i2cDataRetries += 1;
91         }
94         /* Must do endian conversion to verify the checksum */
95         for (i = j = 0; i < len; i += 2, j += 1) 
96             iSum[j] = (iData[i+0] << 8) | iData[i+1];
98         v = onesComplementChksum (iSum, j);
99         if ((v == 0) || (v == 0xffff))
100             break;
102         
103         iblStatus.i2cDataRetries += 1;
105     }
108     i2cReadAddress += len;
109     
110     iFifoIn  = len;
111     iFifoOut = 4;    /* The i2c header is effectively removed */
115              
118 /**
119  *  @brief
120  *      Read data from the I2C to pass to the interpreter
121  */
122 Int32 iblI2cRead (Uint8 *buf, Uint32 num_bytes)
124     int i;
126     for (i = 0; i < num_bytes; i++)  {
128         if (iFifoCount() == 0)
129             i2cReadBlock ();
131         buf[i] = iFifoRead();
132     }
134     return (0);
139 /**
140  *  @brief
141  *      The module function table used for boot from i2c
142  */
143 BOOT_MODULE_FXN_TABLE i2cinit_boot_module = 
145     NULL,           /* Open  API */
146     NULL,           /* Close API */
147     iblI2cRead,     /* Read  API */
148     NULL,           /* Write API */
149     NULL,           /* Peek  API */
150     NULL,           /* Seek  API */
151     NULL            /* Query API */
152 };
155 /**
156  *  @brief
157  *      Configure the I2C, then read the parameters from I2C and pass
158  *      to the second stage boot
159  */
160 BOOT_MODULE_FXN_TABLE *iblInitI2c (void)
162     uint16       v;
163     uint16       configAddrLsw;
164     uint16       configAddrMsw;
165     iblBootMap_t map;
166     bool         littleEndian;
168     /* Read the endianness setting of the device */
169     littleEndian = deviceIsLittleEndian();
171     /* Load the default configuration table from the i2c. The actual speed of the device
172      * isn't really known here, since it is part of the table, so a compile time
173      * value is used (the pll may have been configured during the initial load) */
174     hwI2Cinit (IBL_CFG_I2C_DEV_FREQ_MHZ,        /* The CPU frequency during I2C data load */
175                DEVICE_I2C_MODULE_DIVISOR,       /* The divide down of CPU that drives the i2c */
176                IBL_CFG_I2C_CLK_FREQ_KHZ,        /* The I2C data rate used during table load */
177                IBL_CFG_I2C_OWN_ADDR);           /* The address used by this device on the i2c bus */
180     /* Read the I2C mapping information from the eeprom */
181     for (;;)  {
182         if (hwI2cMasterRead (IBL_CFG_I2C_MAP_TABLE_DATA_ADDR,     /* The address on the eeprom of the data mapping */
183                              sizeof(iblBootMap_t),                /* The number of bytes to read */
184                              (UINT8 *)&map,                       /* Where to store the bytes */
185                              IBL_CFG_I2C_MAP_TABLE_DATA_BUS_ADDR, /* The bus address of the eeprom */
186                              IBL_CFG_I2C_ADDR_DELAY)              /* The delay between sending the address and reading data */
188              == I2C_RET_OK)  {
190                 /* On the I2C EEPROM the table is always formatted with the most significant
191                  * byte first. So if the device is running little endain the endian must be
192                  * swapped */
193                 if (littleEndian == TRUE)  {
194                     map.length   = swap16val (map.length);
195                     map.chkSum   = swap16val (map.chkSum);
196                     map.addrLe   = swap32val (map.addrLe);
197                     map.configLe = swap32val (map.configLe);
198                     map.addrBe   = swap32val (map.addrBe);
199                     map.configBe = swap32val (map.configBe);
201                     configAddrLsw  = readLower16 (map.configLe);
202                     configAddrMsw  = readUpper16 (map.configLe);
203                     i2cReadAddress = map.addrLe;
205                 }  else  {
206                     configAddrLsw = readLower16 (map.configBe);
207                     configAddrMsw = readUpper16 (map.configBe);
208                     i2cReadAddress = map.addrBe;
210                 }
213                 if (map.length != sizeof(iblBootMap_t))  {
214                     iblStatus.mapSizeFail += 1;
215                     continue;
216                 }
218                 if (map.chkSum != 0)  {
219                     
220                     v = onesComplementChksum ((UINT16 *)&map, sizeof(iblBootMap_t));
221                     if ((v != 0) && (v != 0xffff))  {
222                         iblStatus.mapRetries += 1;
223                         continue;
224                     }
225                 }
227                 break;
228         }
230         iblStatus.mapRetries += 1;
232     }
235     /* Read the i2c configuration tables until the checksum passes and the magic number
236      * matches. The checksum must be verified before the endian re-ordering is done */
237     for (;;)  {
239         if (hwI2cMasterRead (configAddrLsw,                  /* The address on the eeprom of the table */
240                              sizeof(ibl_t),                  /* The number of bytes to read */
241                              (UINT8 *)&ibl,                  /* Where to store the bytes */
242                              configAddrMsw,                  /* The bus address of the eeprom */
243                              IBL_CFG_I2C_ADDR_DELAY)         /* The delay between sending the address and reading data */
245              == I2C_RET_OK)  {
247                  if (ibl.chkSum != 0)  {
249                     v = onesComplementChksum ((UINT16 *)&ibl, sizeof(ibl_t) / sizeof(UINT16));
250                     if ((v != 0) && (v != 0xffff))  {
251                         iblStatus.i2cRetries += 1;
252                         continue;
253                     }
255                  }  
258                 if (ibl.iblMagic == ibl_MAGIC_VALUE)
259                     break;
261                 if (swap32val (ibl.iblMagic) == ibl_MAGIC_VALUE)  {
262                     iblSwap ();
263                     break;
264                 }
266                 iblStatus.magicRetries += 1;
268             }
270             iblStatus.i2cRetries += 1;
271     }
273     /* The rest of the IBL is in boot table format. Read and process the data */
274     if (i2cReadAddress == 0xffffffff)  {
275         iblStatus.iblFail = ibl_FAIL_CODE_INVALID_I2C_ADDRESS;
276         for (;;);
277     }
279     return (&i2cinit_boot_module);