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 */
38 /****************************************************************************
39 * FILE PURPOSE: An i2c driver for the rom boot loader
40 ****************************************************************************
41 * FILE NAME: i2c.c
42 *
43 * DESCRIPTION: Provides an i2c driver for the rom boot loader. The driver
44 * is adapted from the csl polling driver in the 64x csl.
45 *
46 ****************************************************************************/
47 #include "types.h"
48 #include "i2c.h"
49 #include "i2cloc.h"
50 #include "target.h"
52 #define DEVICE_REG32_W(x,y) *(volatile unsigned int *)(x)=(y)
53 #define DEVICE_REG32_R(x) (*(volatile unsigned int *)(x))
55 /**************************************************************************
56 * Global variables
57 *************************************************************************/
58 UINT32 i2cCoreFreqMhz;
59 UINT32 i2cBitPeriodCycles;
62 /***********************************************************************************
63 * FUNCTION PURPOSE: Provide an approximate delay
64 ***********************************************************************************
65 * DESCRIPTION: A delay in units of CPU cycles is executed
66 ***********************************************************************************/
67 static void chipDelay32 (uint32 del)
68 {
69 volatile unsigned int i;
71 for (i = 0; i < del/8; i++){
72 asm(" NOP ");
73 }
74 }
77 /***************************************************************************
78 * FUNCTION PURPOSE: Generate a delay
79 ***************************************************************************
80 * DESCRIPTION: Creates a delay specified in usec
81 ***************************************************************************/
82 void hw_i2c_delay_usec (UINT32 usec)
83 {
84 UINT32 delayCycles;
86 delayCycles = usec * i2cCoreFreqMhz;
88 chipDelay32 (delayCycles);
90 } /* hw_i2c_delay_usec */
93 /***************************************************************************
94 * FUNCTION PURPOSE: Initialize the I2C.
95 ***************************************************************************
96 * DESCRIPTION: Puts the I2C into reset, sets up the device and takes
97 * the device out of reset in slave receiver mode.
98 **************************************************************************/
99 void hwI2Cinit (UINT16 coreFreqMhz, UINT16 moduleDivisor, UINT16 clkFreqKhz, UINT16 ownAddr)
100 {
101 UINT32 psc;
102 UINT32 clkx;
103 UINT32 tmp;
104 UINT32 moduleFreqMhzQ1;
105 UINT32 trueModFreqHz;
106 UINT32 trueModFreqkHz;
108 /* Put the i2c peripheral into reset */
109 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_RESET);
111 /* To determine the module prescaler Q31.1 format will be used. This is just
112 * handled simply since the input module frequency is an integer it will just
113 * be multiplied by two. Dividing two Q31.1 result in a Q30.0, or the divider *
114 * Calculate module prescalars to get as close to target frequencies as possible */
115 moduleFreqMhzQ1 = (coreFreqMhz << 1) / moduleDivisor;
116 psc = moduleFreqMhzQ1 / I2C_TARGET_MODULE_FREQ_MHZ_Q1;
117 if (psc > 0)
118 psc = psc - 1;
119 trueModFreqHz = ((UINT32)coreFreqMhz * (UINT32)1000000) / (moduleDivisor * (psc+1));
121 tmp = trueModFreqHz / (clkFreqKhz * 1000);
122 if (tmp > 12)
123 clkx = (tmp - 12) >> 1;
124 else
125 clkx = 0;
127 /* Store the core frequency for use in generating delay */
128 i2cCoreFreqMhz = coreFreqMhz;
130 /* Calculate the number of micro seconds for each bit. */
131 trueModFreqkHz = trueModFreqHz / 1000; /* Prevent 32 bit integer overlflow */
132 i2cBitPeriodCycles = (UINT32)coreFreqMhz * 1000 * (2 * clkx + 12) / trueModFreqkHz;
134 /* Initialize the registers */
135 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_PSC, (UINT32)psc);
136 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_OAR, (UINT32)ownAddr);
137 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_IER, (UINT32)0);
138 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_STR, I2C_VAL_REG_STR_RESET);
139 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_CLKL, clkx);
140 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_CLKH, clkx);
141 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_CNT, (UINT32)0);
142 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_SAR, (UINT32)0x3ff);
143 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_DXR, (UINT32)0);
144 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_PFUNC, (UINT32)0);
146 /* Take the I2C out of reset in the slave receiver mode */
147 DEVICE_REG32_W(DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_SLVRCV);
149 /* Read the receive register to clear it */
150 tmp = DEVICE_REG32_R(DEVICE_I2C_BASE + I2C_REG_DRR);
153 } /* hwI2Cinit */
156 /****************************************************************************
157 * FUNCTION PURPOSE: Perform a master write
158 ****************************************************************************
159 * DESCRIPTION: Enters master transmitter mode, writes a specified number
160 * of bytes. The byte stream arrives packed in the 16 bit
161 * data stream, and are sent most significant byte first.
162 ****************************************************************************/
163 I2C_RET hwI2cMasterWrite (UINT32 eeprom_i2c_id, UINT8 *eData, UINT32 nbytes, UINT32 endBusState, BOOL busIsMine)
164 {
165 UINT32 timeoutCount;
166 UINT32 polling;
167 UINT32 value;
168 UINT32 str;
169 UINT16 i;
171 /* If the byte length is 0 there is nothing to do */
172 if (nbytes == 0)
173 return (I2C_RET_OK);
175 /* Check for the bus busy signal */
176 if (busIsMine == FALSE) {
177 timeoutCount = 0;
178 do {
179 polling = I2C_REG_STR_FIELD_BB(DEVICE_REG32_R (DEVICE_I2C_BASE + I2C_REG_STR));
181 if (polling != 0) {
182 hw_i2c_delay_usec (I2C_MASTER_TRANSMITTER_BUS_ACCESS_DELAY_US);
184 timeoutCount += 1;
185 if (timeoutCount >= I2C_MAX_MASTER_TRANSMITTER_BUS_ACCESS_TIMEOUT) {
187 /* Return to slave receiver, clear nack and bus busy */
188 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_SLVRCV);
189 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_STR, I2C_VAL_REG_STR_ON_FAIL);
190 return (I2C_RET_IDLE_TIMEOUT);
191 }
192 } else { /* The bus is free */
193 timeoutCount = 0;
194 }
195 }
196 while (timeoutCount != 0);
198 }
200 /* Enter master transmitter mode, set the slave address register */
201 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_MSTXMT);
202 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_SAR, (UINT32)eeprom_i2c_id);
204 /* Put the first byte into the transmit register, set the start bit */
205 value = *eData & 0x00ff;
206 eData = eData + 1;
207 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_DXR, value);
210 /* Some delay required */
211 chipDelay32 (i2cBitPeriodCycles);
213 /* Set the start bit */
214 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_MSTXMTSTRT);
216 for (i = 1; i < nbytes; i++) {
217 timeoutCount = 0;
219 do {
220 /* Read status */
221 str = DEVICE_REG32_R (DEVICE_I2C_BASE + I2C_REG_STR);
223 /* On Nack return failure */
224 if (I2C_REG_STR_FIELD_NACK(str) != 0) {
226 /* Return to slave receiver, clear nack and bus busy */
227 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_SLVRCV);
228 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_STR, I2C_VAL_REG_STR_ON_FAIL);
229 return (I2C_RET_NO_ACK);
230 }
232 /* Check for transmit ready */
233 if (I2C_REG_STR_FIELD_XRDY(str) != 0) {
234 timeoutCount = 0;
236 value = *eData & 0x00ff;
237 eData = eData + 1;
239 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_DXR, value);
242 } else { /* XRDY bit not set */
243 chipDelay32 (i2cBitPeriodCycles);
244 timeoutCount += 1;
245 if (timeoutCount >= I2C_MAX_MASTER_TRANSMITTER_TIMEOUT) {
246 /* Return to slave receiver, clear nack and bus busy */
247 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_SLVRCV);
248 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_STR, I2C_VAL_REG_STR_ON_FAIL);
249 return (I2C_RET_IDLE_TIMEOUT);
250 }
251 }
253 } while (timeoutCount != 0);
255 } /* end for loop */
258 /* If releasing the bus, send a stop bit */
259 if (endBusState == I2C_RELEASE_BUS) {
261 /* Wait for the ardy bit to go high */
262 timeoutCount = 0;
263 do {
264 str = DEVICE_REG32_R (DEVICE_I2C_BASE + I2C_REG_STR);
265 if (I2C_REG_STR_FIELD_ARDY(str) != 0) {
266 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_MSTXMTSTOP);
267 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_STR, I2C_VAL_REG_STR_CLR_BUSY);
268 hw_i2c_delay_usec (10000);
269 timeoutCount = 0;
271 } else { /* Registers not ready for access */
272 timeoutCount += 1;
274 if (timeoutCount >= I2C_MAX_MASTER_TRANSMITTER_ARDY_TIMEOUT) {
275 /* On timeout put the peripheral into reset, wait, then
276 * take it out of reset */
277 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_RESET);
278 hw_i2c_delay_usec (10000);
279 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_SLVRCV);
280 return (I2C_RET_IDLE_TIMEOUT);
281 }
282 chipDelay32 (i2cBitPeriodCycles);
283 }
284 } while (timeoutCount != 0);
286 } /* end bus release */
288 return (I2C_RET_OK);
290 } /* hwI2cMasterWrite */
294 /**************************************************************************
295 * FUNCTION PURPOSE: Perform a master read from an I2C prom
296 **************************************************************************
297 * DESCRIPTION: Reads a fixed number of bytes from an I2C prom. The read
298 * consists of a master write of 2 bytes (forming a 16 bit address,
299 * msb transmitted first), followed by a master read of the
300 * input number of bytes. The bytes that are read are placed
301 * in p_packed_bytes in big endian format.
302 **************************************************************************/
303 I2C_RET hwI2cMasterRead (
304 UINT32 byte_addr,
305 UINT32 byte_len,
306 UINT8 *p_packed_bytes,
307 UINT32 eeprom_i2c_id,
308 UINT32 address_delay)
309 {
311 UINT32 str;
312 UINT32 timeoutCount;
313 UINT32 i;
314 UINT8 eAddr[2];
315 I2C_RET ret;
317 /* If the byte length is 0, there is nothing to do */
318 if (byte_len == 0)
319 return (I2C_RET_OK);
321 /* Write the byte address to the eeprom. Do not send a stop */
322 eAddr[0] = (byte_addr >> 8) & 0xff;
323 eAddr[1] = byte_addr & 0xff;
325 ret = hwI2cMasterWrite (eeprom_i2c_id, eAddr, 2, I2C_DO_NOT_RELEASE_BUS, FALSE);
326 if (ret != I2C_RET_OK)
327 return (ret);
329 /* Give the I2C prom some time to process the read command */
330 chipDelay32 (((UINT32)address_delay)<<8);
332 /* Set the start bit, begin the master read */
333 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_MSTRCV);
335 /* Read the requested number of bytes */
336 for (i = 0; i < byte_len; i++) {
337 timeoutCount = 0;
339 do {
340 /* Read status */
341 str = DEVICE_REG32_R (DEVICE_I2C_BASE + I2C_REG_STR);
343 /* On Nack return failure */
344 if (I2C_REG_STR_FIELD_NACK(str) != 0) {
346 /* Return to slave receiver, clear nack and bus busy */
347 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_SLVRCV);
348 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_STR, I2C_VAL_REG_STR_ON_FAIL);
349 return (I2C_RET_NO_ACK);
350 }
352 /* Check for receive byte ready */
353 if (I2C_REG_STR_FIELD_RRDY(str) != 0) {
354 *p_packed_bytes = (UINT16) (DEVICE_REG32_R (DEVICE_I2C_BASE + I2C_REG_DRR) & 0x00ff);
355 timeoutCount = 0;
356 p_packed_bytes = p_packed_bytes + 1;
359 } else { /* RRDY bit not set */
360 chipDelay32 (i2cBitPeriodCycles);
361 timeoutCount += 1;
362 if (timeoutCount >= I2C_MAX_MASTER_RECEIVE_TIMEOUT) {
363 /* Return to slave receiver, clear nack and bus busy */
364 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_SLVRCV);
365 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_STR, I2C_VAL_REG_STR_ON_FAIL);
366 return (I2C_RET_IDLE_TIMEOUT);
367 }
368 }
370 } while (timeoutCount != 0);
372 } /* end for loop */
374 /* The data block has been read. Send the stop bit */
375 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_MSTRCVSTOP);
378 /* Wait for the rrdy and read the dummy byte */
379 timeoutCount = 0;
380 do {
382 str = DEVICE_REG32_R (DEVICE_I2C_BASE + I2C_REG_STR);
384 /* Check for receive byte ready */
385 if (I2C_REG_STR_FIELD_RRDY(str) != 0) {
386 eAddr[0] = (UINT16) (DEVICE_REG32_R (DEVICE_I2C_BASE + I2C_REG_DRR) & 0x00ff);
387 timeoutCount = 0;
389 } else { /* rrdy not set */
391 chipDelay32 (i2cBitPeriodCycles);
392 timeoutCount += 1;
393 if (timeoutCount >= I2C_MAX_MASTER_RECEIVE_TIMEOUT) {
394 /* Return to slave receiver, clear nack and bus busy */
395 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_MDR, I2C_VAL_REG_MDR_SLVRCV);
396 DEVICE_REG32_W (DEVICE_I2C_BASE + I2C_REG_STR, I2C_VAL_REG_STR_ON_FAIL);
397 return (I2C_RET_IDLE_TIMEOUT);
398 }
399 }
401 } while (timeoutCount != 0);
403 return (I2C_RET_OK);
405 } /* hwI2cMasterRead */