9d907125c0b89c50e1b56b66972dcdee72687484
[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 #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 */
69     
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 */
88     
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;
103         
104         iblStatus.i2cDataRetries += 1;
106     }
109     i2cReadAddress += len;
110     
111     iFifoIn  = len;
112     iFifoOut = 4;    /* The i2c header is effectively removed */
116              
119 /**
120  *  @brief
121  *      Read data from the I2C to pass to the interpreter
122  */
123 Int32 iblI2cRead (Uint8 *buf, Uint32 num_bytes)
125     int i;
127     for (i = 0; i < num_bytes; i++)  {
129         if (iFifoCount() == 0)
130             i2cReadBlock ();
132         buf[i] = iFifoRead();
133     }
135     return (0);
140 /**
141  *  @brief
142  *      The module function table used for boot from i2c
143  */
144 BOOT_MODULE_FXN_TABLE i2cinit_boot_module = 
146     NULL,           /* Open  API */
147     NULL,           /* Close API */
148     iblI2cRead,     /* Read  API */
149     NULL,           /* Write API */
150     NULL,           /* Peek  API */
151     NULL,           /* Seek  API */
152     NULL            /* Query API */
153 };
156 /**
157  *  @brief
158  *      Configure the I2C, then read the parameters from I2C and pass
159  *      to the second stage boot
160  */
161 BOOT_MODULE_FXN_TABLE *iblInitI2c (void)
163     uint16       v;
164     uint16       configAddrLsw;
165     uint16       configAddrMsw;
166     iblBootMap_t map;
167     bool         littleEndian;
169     /* Read the endianness setting of the device */
170     littleEndian = deviceIsLittleEndian();
172     /* Load the default configuration table from the i2c. The actual speed of the device
173      * isn't really known here, since it is part of the table, so a compile time
174      * value is used (the pll may have been configured during the initial load) */
175     hwI2Cinit (IBL_CFG_I2C_DEV_FREQ_MHZ,        /* The CPU frequency during I2C data load */
176                DEVICE_I2C_MODULE_DIVISOR,       /* The divide down of CPU that drives the i2c */
177                IBL_CFG_I2C_CLK_FREQ_KHZ,        /* The I2C data rate used during table load */
178                IBL_CFG_I2C_OWN_ADDR);           /* The address used by this device on the i2c bus */
181     /* Read the I2C mapping information from the eeprom */
182     for (;;)  {
183         if (hwI2cMasterRead (IBL_CFG_I2C_MAP_TABLE_DATA_ADDR,     /* The address on the eeprom of the data mapping */
184                              sizeof(iblBootMap_t),                /* The number of bytes to read */
185                              (UINT8 *)&map,                       /* Where to store the bytes */
186                              IBL_CFG_I2C_MAP_TABLE_DATA_BUS_ADDR, /* The bus address of the eeprom */
187                              IBL_CFG_I2C_ADDR_DELAY)              /* The delay between sending the address and reading data */
189              == I2C_RET_OK)  {
191                 /* On the I2C EEPROM the table is always formatted with the most significant
192                  * byte first. So if the device is running little endain the endian must be
193                  * swapped */
194                 if (littleEndian == TRUE)  {
195                     map.length   = swap16val (map.length);
196                     map.chkSum   = swap16val (map.chkSum);
197                     map.addrLe   = swap32val (map.addrLe);
198                     map.configLe = swap32val (map.configLe);
199                     map.addrBe   = swap32val (map.addrBe);
200                     map.configBe = swap32val (map.configBe);
202                     configAddrLsw  = readLower16 (map.configLe);
203                     configAddrMsw  = readUpper16 (map.configLe);
204                     i2cReadAddress = map.addrLe;
206                 }  else  {
207                     configAddrLsw = readLower16 (map.configBe);
208                     configAddrMsw = readUpper16 (map.configBe);
209                     i2cReadAddress = map.addrBe;
211                 }
213                 i2cBusAddress = i2cReadAddress >>16;
215                 if (map.length != sizeof(iblBootMap_t))  {
216                     iblStatus.mapSizeFail += 1;
217                     continue;
218                 }
220                 if (map.chkSum != 0)  {
221                     
222                     v = onesComplementChksum ((UINT16 *)&map, sizeof(iblBootMap_t));
223                     if ((v != 0) && (v != 0xffff))  {
224                         iblStatus.mapRetries += 1;
225                         continue;
226                     }
227                 }
229                 break;
230         }
232         iblStatus.mapRetries += 1;
234     }
237     /* Read the i2c configuration tables until the checksum passes and the magic number
238      * matches. The checksum must be verified before the endian re-ordering is done */
239     for (;;)  {
241         if (hwI2cMasterRead (configAddrLsw,                  /* The address on the eeprom of the table */
242                              sizeof(ibl_t),                  /* The number of bytes to read */
243                              (UINT8 *)&ibl,                  /* Where to store the bytes */
244                              configAddrMsw,                  /* The bus address of the eeprom */
245                              IBL_CFG_I2C_ADDR_DELAY)         /* The delay between sending the address and reading data */
247              == I2C_RET_OK)  {
249                  if (ibl.chkSum != 0)  {
251                     v = onesComplementChksum ((UINT16 *)&ibl, sizeof(ibl_t) / sizeof(UINT16));
252                     if ((v != 0) && (v != 0xffff))  {
253                         iblStatus.i2cRetries += 1;
254                         continue;
255                     }
257                  }  
260                 if (ibl.iblMagic == ibl_MAGIC_VALUE)
261                     break;
263                 if (swap32val (ibl.iblMagic) == ibl_MAGIC_VALUE)  {
264                     iblSwap ();
265                     break;
266                 }
268                 iblStatus.magicRetries += 1;
270             }
272             iblStatus.i2cRetries += 1;
273     }
275     /* The rest of the IBL is in boot table format. Read and process the data */
276     if (i2cReadAddress == 0xffffffff)  {
277         iblStatus.iblFail = ibl_FAIL_CODE_INVALID_I2C_ADDRESS;
278         for (;;);
279     }
281     return (&i2cinit_boot_module);
285 #endif /* EXCLUDE_I2C */