1/******************************************************************************* 2Copyright (C) Marvell International Ltd. and its affiliates 3 4This software file (the "File") is owned and distributed by Marvell 5International Ltd. and/or its affiliates ("Marvell") under the following 6alternative licensing terms. Once you have made an election to distribute the 7File under one of the following license alternatives, please (i) delete this 8introductory statement regarding license alternatives, (ii) delete the two 9license alternatives that you have not elected to use and (iii) preserve the 10Marvell copyright notice above. 11 12******************************************************************************** 13Marvell Commercial License Option 14 15If you received this File from Marvell and you have entered into a commercial 16license agreement (a "Commercial License") with Marvell, the File is licensed 17to you under the terms of the applicable Commercial License. 18 19******************************************************************************** 20Marvell GPL License Option 21 22If you received this File from Marvell, you may opt to use, redistribute and/or 23modify this File in accordance with the terms and conditions of the General 24Public License Version 2, June 1991 (the "GPL License"), a copy of which is 25available along with the File in the license.txt file or by writing to the Free 26Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or 27on the worldwide web at http://www.gnu.org/licenses/gpl.txt. 28 29THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED 30WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY 31DISCLAIMED. The GPL License provides additional details about this warranty 32disclaimer. 33******************************************************************************** 34Marvell BSD License Option 35 36If you received this File from Marvell, you may opt to use, redistribute and/or 37modify this File under the following licensing terms. 38Redistribution and use in source and binary forms, with or without modification, 39are permitted provided that the following conditions are met: 40 41 * Redistributions of source code must retain the above copyright notice, 42 this list of conditions and the following disclaimer. 43 44 * Redistributions in binary form must reproduce the above copyright 45 notice, this list of conditions and the following disclaimer in the 46 documentation and/or other materials provided with the distribution. 47 48 * Neither the name of Marvell nor the names of its contributors may be 49 used to endorse or promote products derived from this software without 50 specific prior written permission. 51 52THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 53ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 54WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 55DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 56ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 57(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 58LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 59ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 60(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 61SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 63*******************************************************************************/ 64 65 66/* includes */ 67#define MV_ASMLANGUAGE 68#include "ctrlEnv/mvCtrlEnvSpec.h" 69#include "boardEnv/mvBoardEnvSpec.h" 70#include "mvOsAsm.h" 71#include "mvTwsiSpec.h" 72#include "mvSysHwConfig.h" 73#include "ctrlEnv/sys/mvCpuIfRegs.h" 74#include "mvCommon.h" 75 76#define I2C_CH MV_BOARD_DIMM_I2C_CHANNEL 77 78/* defines */ 79/* defines */ 80 81 82 .data 83 .global _i2cInit 84 .global _i2cRead 85 86 .text 87 88/******************************************************************************* 89* _i2cInit - Initialize TWSI interface 90* 91* DESCRIPTION: 92* The function performs TWSI interface initialization. It resets the 93* TWSI state machine and initialize its clock to 100KHz assuming Tclock 94* of 133MHz. 95* 96* INPUT: 97* None. 98* 99* OUTPUT: 100* None. 101* 102* RETURN: 103* None. 104* 105*******************************************************************************/ 106_i2cInit: 107 mov r9, LR /* Save link register */ 108 mov r0, #0 /* Make sure r0 is zero */ 109 110 /* Reset the i2c Mechanism first */ 111 MV_REG_WRITE_ASM (r0, r1, TWSI_SOFT_RESET_REG(I2C_CH)) 112 113 bl _twsiDelay 114 bl _twsiDelay 115 116 /* Initializing the I2C mechanism. Assuming Tclock frequency */ 117 /* of 166MHz. The I2C frequency in that case will be 100KHz. */ 118 /* For this settings, M = 9 and N = 3. Set the baud-rate with the */ 119 /* value of 0x2b (freq of ==> 100KHz */ 120 /* see spec for more details about the calculation of this value) */ 121 mov r6, #(9 << 3 | 3) 122 MV_REG_WRITE_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) 123 124 /* Enable the I2C master */ 125 /* Enable TWSI interrupt in main mask reg */ 126 mov r6, #0xC4 127 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 128 129 /* Let the slow TWSI machine get used to the idea that it is enabled */ 130 bl _twsiDelay 131 132 133 mov PC, r9 /* r9 is saved link register */ 134 135/******************************************************************************* 136* _twsiDelay - Perform delay. 137* 138* DESCRIPTION: 139* The function performs a delay to enable TWSI logic to stable. 140* 141* INPUT: 142* None. 143* 144* OUTPUT: 145* None. 146* 147* RETURN: 148* None. 149* 150*******************************************************************************/ 151_twsiDelay: 152 mov r10, #0x100000 /*was 0x400*/ 153 154_twsiDelayLoop: 155 subs r10, r10, #1 156 bne _twsiDelayLoop 157 158 mov PC, LR 159 160/******************************************************************************* 161* _i2cRead - Read byte from I2C EEPROM device. 162* 163* DESCRIPTION: 164* The function returns a byte from I2C EEPROM device. 165* The EEPROM device is 7-bit address type. 166* 167* INPUT: 168* r4 has the DIMM0 base address with shift 1 bit to the left 169* r7 has the EEPROM offset 170* 171* OUTPUT: 172* None. 173* 174* RETURN: 175* r4 returns '0' if address can not be read. 176* r7 has byte value in case read is successful. 177* 178*******************************************************************************/ 179_i2cRead: 180 mov r9, LR /* Save link register */ 181 182 /* Transmit the device address and desired offset within the EEPROM. */ 183 184 /* Generate Start Bit */ 185 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 186 orr r6, r6, #TWSI_CONTROL_START_BIT 187 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 188 189 /* Wait for the interrupt flag (bit3) to be set */ 190 mov r10, #0x50000 191loop_1: 192 subs r10, r10, #1 193 beq loop_1_timeout 194#ifdef MV78XX0 195 MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) 196 tst r6, #BIT2 197#else 198 MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) 199 tst r6, #BIT5 200#endif 201 beq loop_1 202 203loop_1_timeout: 204 205 /* Wait for the start bit to be reset by HW */ 206 mov r10, #0x50000 207loop_2: 208 subs r10, r10, #1 209 beq loop_2_timeout 210 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 211 tst r6, #TWSI_CONTROL_START_BIT 212 bne loop_2 213 214loop_2_timeout: 215 216 /* Wait for the status TWSI_START_CONDITION_TRA = 0x8 */ 217 mov r10, #0x50000 218loop_3: 219 subs r10, r10, #1 220 beq loop_3_timeout 221 MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) 222 cmp r6, #0x08 223 bne loop_3 224 225loop_3_timeout: 226 227 /* writing the address of (DIMM0/1 << 1) with write indication */ 228 mov r6, r4, LSL #1 /* Write operation address bit 0 must be 0 */ 229 MV_REG_WRITE_ASM (r6, r1, TWSI_DATA_REG(I2C_CH)) 230 231 bl _twsiDelay 232 /* Clear the interrupt flag */ 233 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 234 bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET 235 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 236 bl _twsiDelay 237 238 /* Waiting for the interrupt flag to be set which means that the 239 address has been transmitted */ 240loop_4: 241#ifdef MV78XX0 242 MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) 243 tst r6, #BIT2 244#else 245 MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) 246 tst r6, #BIT5 247#endif 248 beq loop_4 /* if tst = 0, then the bit is not set yet */ 249 250 /* Wait for status TWSI_ADDR_PLUS_WRITE_BIT_TRA_ACK_REC = 0x18 */ 251 mov r10, #0x50000 /* Set r10 to 0x50000 =~ 328,000 */ 252 253loop_5: 254 subs r10, r10, #1 /* timeout count down */ 255 bne testStatus 256 mov r4, #0 /* r4 = 0 -> operation failed */ 257 b exit_i2cRead /* Exit if timeout (No DIMM) */ 258 259testStatus: 260 MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) 261 cmp r6, #0x18 262 bne loop_5 263 264 265 /* check if the offset is bigger than 256 byte*/ 266 tst r7, #0x80000000 267 bne great_than_256 268 269 /* Write the offset to be read from the DIMM EEPROM */ 270 MV_REG_WRITE_ASM (r7, r1, TWSI_DATA_REG(I2C_CH)) 271 272 b after_offset 273 274great_than_256: 275 mov r10, r7, LSR #8 276 and r10, r10, #0xff 277 /* Write the offset0 to be read from the EEPROM */ 278 MV_REG_WRITE_ASM (r10, r1, TWSI_DATA_REG(I2C_CH)) 279 280 /* Clear the interrupt flag ==> signaling that the address can now 281 be transmited */ 282 283 bl _twsiDelay 284 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 285 bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET 286 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 287 bl _twsiDelay 288 289 /* Wait for the interrupt to be set again ==> address has transmited */ 290loop_6_1: 291#ifdef MV78XX0 292 MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) 293 tst r6, #BIT2 294#else 295 MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) 296 tst r6, #BIT5 297#endif 298 beq loop_6_1 299 300 /* Wait for status TWSI_MAS_TRAN_DATA_BYTE_ACK_REC = 0x28 */ 301loop_7_1: 302 MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) 303 cmp r6, #0x28 304 bne loop_7_1 305 306 307 mov r10, r7 308 and r10, r10, #0xff 309 /* Write the offset1 to be read from the EEPROM */ 310 MV_REG_WRITE_ASM (r10, r1, TWSI_DATA_REG(I2C_CH)) 311 312 313 314after_offset: 315 316 /* Clear the interrupt flag ==> signaling that the address can now 317 be transmited */ 318 319 bl _twsiDelay 320 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 321 bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET 322 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 323 bl _twsiDelay 324 325 /* Wait for the interrupt to be set again ==> address has transmited */ 326loop_6: 327#ifdef MV78XX0 328 MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) 329 tst r6, #BIT2 330#else 331 MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) 332 tst r6, #BIT5 333#endif 334 beq loop_6 335 336 /* Wait for status TWSI_MAS_TRAN_DATA_BYTE_ACK_REC = 0x28 */ 337loop_7: 338 MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) 339 cmp r6, #0x28 340 bne loop_7 341 342 /* Retransmit the device address with read indication to get the data */ 343 344 /* generate a repeated start bit */ 345 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 346 orr r6, r6, #TWSI_CONTROL_START_BIT 347 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 348 349 350 /* Clear the interrupt flag ==> the start bit will be transmitted. */ 351 bl _twsiDelay 352 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 353 bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET 354 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 355 bl _twsiDelay 356 357 /* Wait for the interrupt flag (bit3) to be set */ 358loop_9: 359#ifdef MV78XX0 360 MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) 361 tst r6, #BIT2 362#else 363 MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) 364 tst r6, #BIT5 365#endif 366 beq loop_9 367 368 /* Wait for the start bit to be reset by HW */ 369loop_8: 370 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 371 tst r6, #TWSI_CONTROL_START_BIT 372 bne loop_8 373 374 /* Wait for status TWSI_REPEATED_START_CONDITION_TRA = 0x10 */ 375loop_10: 376 MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) 377 cmp r6, #0x10 378 bne loop_10 379 380 /* Writing the address of (DIMM0<<1) with read indication (bit0 is 1) */ 381 mov r6, r4, LSL #1 382 orr r6, r6, #1 /* Read operation address bit 0 must be 1 */ 383 MV_REG_WRITE_ASM (r6, r1, TWSI_DATA_REG(I2C_CH)) 384 385 /* Clear the interrupt flag ==> the address will be transmitted */ 386 bl _twsiDelay 387 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 388 bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET 389 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 390 bl _twsiDelay 391 392 /* Wait for the interrupt flag (bit3) to be set as a result of 393 transmitting the address. */ 394loop_11: 395#ifdef MV78XX0 396 MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) 397 tst r6, #BIT2 398#else 399 MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) 400 tst r6, #BIT5 401#endif 402 beq loop_11 403 404 /* Wait for status TWSI_ADDR_PLUS_READ_BIT_TRA_ACK_REC = 0x40 */ 405loop_12: 406 MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) 407 cmp r6, #0x40 408 bne loop_12 409 410 /* Clear the interrupt flag and the Acknoledge bit */ 411 bl _twsiDelay 412 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 413 bic r6, r6, #(TWSI_CONTROL_INT_FLAG_SET | TWSI_CONTROL_ACK) 414 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 415 bl _twsiDelay 416 417 /* Wait for the interrupt flag (bit3) to be set */ 418loop_14: 419#ifdef MV78XX0 420 MV_REG_READ_ASM (r6, r1, CPU_INT_LOW_REG(I2C_CH)) 421 tst r6, #BIT2 422#else 423 MV_REG_READ_ASM (r6, r1, CPU_MAIN_INT_CAUSE_REG) 424 tst r6, #BIT5 425#endif 426 beq loop_14 427 428 /* Wait for status TWSI_MAS_REC_READ_DATA_ACK_NOT_TRA = 0x58 */ 429loop_15: 430 MV_REG_READ_ASM (r6, r1, TWSI_STATUS_BAUDE_RATE_REG(I2C_CH)) 431 cmp r6, #0x58 432 bne loop_15 433 434 /* Store the data in r7. */ 435 MV_REG_READ_ASM (r7, r1, TWSI_DATA_REG(I2C_CH)) 436 437 /* Generate stop bit */ 438 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 439 orr r6, r6, #TWSI_CONTROL_STOP_BIT 440 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 441 442 443 /* Clear the interrupt flag */ 444 bl _twsiDelay 445 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 446 bic r6, r6, #TWSI_CONTROL_INT_FLAG_SET 447 MV_REG_WRITE_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 448 bl _twsiDelay 449 450 /* Wait for the stop bit to be reset by HW */ 451loop_16: 452 MV_REG_READ_ASM (r6, r1, TWSI_CONTROL_REG(I2C_CH)) 453 tst r6, #TWSI_CONTROL_INT_FLAG_SET 454 bne loop_16 455 456exit_i2cRead: 457 mov PC, r9 /* r9 is saved link register */ 458