Fixes for Big endian mode on C6472
[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     i2cBusAddress = i2cReadAddress >>16;
111     
112     iFifoIn  = len;
113     iFifoOut = 4;    /* The i2c header is effectively removed */
117              
120 /**
121  *  @brief
122  *      Read data from the I2C to pass to the interpreter
123  */
124 Int32 iblI2cRead (Uint8 *buf, Uint32 num_bytes)
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);
141 /**
142  *  @brief
143  *      The module function table used for boot from i2c
144  */
145 BOOT_MODULE_FXN_TABLE i2cinit_boot_module = 
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)
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)  {
222                     
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);
286 #endif /* EXCLUDE_I2C */