24c64.c (31039B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * BCM56xx I2C Device Driver for ATMEL 24LC64 EEPROM 8 * 9 * The AT24C32/64 provides for 32,768 or 65,536 bits of electrically 10 * eraseable programmable read only memory (EEPROM) organized as 11 * 4096/8192 bytes. The AT24C32/64 chips are internally organized 12 * as 128/256 pages of 32 bytes each, hence a page addressing mode 13 * is available. 14 * The top quadrant (1024/2048 bytes) can be write protected. This is 15 * where the Board Information Structure (BIS) is stored; it is not 16 * subject to any destructive memory integrity tests. 17 * 18 * See also: AT24C64 Data Sheet 19 */ 20 #include <sal/types.h> 21 #include <soc/drv.h> 22 #include <soc/error.h> 23 #include <soc/debug.h> 24 #include <soc/i2c.h> 25 #include <soc/iproc.h> 26 #include <soc/cm.h> 27 #include <shared/bsl.h> 28 #define LC2464_WRITE_CYCLE_DELAY (10*MILLISECOND_USEC) /* 10 ms MAX */ 29 #define LC2464_PAGE_SIZE 32 /* Bytes per page */ 30 #define LC2464_DEVICE_SIZE (8192) /* AT24C64 */ 31 #define LC2464_DEVICE_RW_SIZE (((LC2464_DEVICE_SIZE)*3)/4) 32 #define LC2464_ACK_RETRY_COUNT 1000 /* Number of retry polls */ 33 #define LC2464_NAME_LEN 6 34 35 36 37 38 39 typedef struct eep24c64_s{ 40 uint16 size; /* Number of Bytes */ 41 uint16 type; /* Reserved */ 42 char name[LC2464_NAME_LEN]; /* Device name */ 43 uint16 chksum; /* 16 bit checksum of size, type, and name */ 44 } eep24c64_t; 45 46 /* 47 * Store EEPROM data at start of prom, make all 48 * drivers read/write beyond that. This basically 49 * serves as a way of signing the EEPROM with data 50 * so that we know the device is good and has been 51 * validated. 52 */ 53 #define LC24C64_PARAMS_SIZE (sizeof(eep24c64_t)) 54 #define LC24C64_DATA_START LC24C64_PARAMS_SIZE 55 56 /* 57 * Function: eep24c64_ack_poll 58 * 59 * Purpose: Poll the device to determine if it is ready for IO. 60 * When the chip writes data, it will become unresponsive 61 * for a period of Time Tw (Internal Write Delay). We could 62 * either wait the maximum amount of time for the device to 63 * finish it's write-cycle (10ms), or we can poll the device 64 * for a specified operation (r/w) until it responds with an 65 * ACK. This routine polls the device until it is responsive. 66 * 67 * Parameters: 68 * unit - StrataSwitch device number or I2C bus number 69 * bus_addr - chip IO (I2C) slave bus address byte(s) 70 * 71 * Returns: 72 * Number of Poll operations required to contact device, or 73 * LC24C64_ACK_RETRY_COUNT if the device is not online or responding. 74 * 75 * 76 * Notes: 77 * See also: soc_i2c_ack_poll 78 */ 79 STATIC INLINE int 80 eep24c64_ack_poll(int unit, i2c_bus_addr_t bus_addr) 81 { 82 return soc_i2c_ack_poll(unit, bus_addr, LC2464_ACK_RETRY_COUNT); 83 } 84 85 /* 86 * Function: eep24c64_read 87 * 88 * Purpose: Read len bytes of data into buffer, update len with total 89 * amount read. 90 * 91 * Parameters: 92 * unit - StrataSwitch device number or I2C bus number 93 * devno - chip device id 94 * addr - NVRAM memory address to read from 95 * data - address of data buffer to read into 96 * len - address containing number of bytes read into data buffer (updated 97 * with number of bytes read on completion). 98 * 99 * Returns: data bufffer filled in with data from address, number of 100 * bytes read is updated in len field. Status code: 101 * 102 * SOC_E_NONE -- no error encounter 103 * SOC_E_TIMEOUT - chip timeout or data error 104 * 105 * Notes: 106 * Currently uses random address byte read to initiate the read; if 107 * more than one byte of data is requested at the current address, a 108 * sequential read operation is performed. 109 */ 110 STATIC int 111 eep24c64_read(int unit, int devno, 112 uint16 addr, uint8* data, uint32 *len) 113 { 114 int rv = SOC_E_NONE; 115 uint8 saddr_r, saddr_w, a0, a1; 116 uint32 nbytes = 0; 117 #ifdef BCM_CMICM_SUPPORT 118 uint8 rx; 119 uint32 nread; 120 soc_timeout_t to; 121 #endif 122 #ifdef BCM_IPROC_SUPPORT 123 uint32 rval; 124 uint32 i; 125 #endif 126 127 /* Valid address, memory and size must be provided */ 128 if ( ! len || ! data ) 129 return SOC_E_PARAM; 130 131 I2C_LOCK(unit); 132 133 saddr_r = SOC_I2C_RX_ADDR(soc_i2c_addr(unit, devno)); 134 saddr_w = SOC_I2C_TX_ADDR(soc_i2c_addr(unit, devno)); 135 136 a0 = (uint8) (addr & 0x00ff); 137 a1 = (uint8) ((addr & 0xff00) >> 8); 138 139 LOG_INFO(BSL_LS_SOC_I2C, 140 (BSL_META_U(unit, 141 "eep24c64_read: addr=0x%x (a0=0x%x,a1=0x%x) len=%d\n"), 142 addr, a0, a1, (int)*len)); 143 144 #ifdef BCM_IPROC_SUPPORT 145 if (soc_feature(unit, soc_feature_eeprom_iproc)) { 146 rval = (uint32)saddr_w; 147 WRITE_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_WRITEr(unit, rval); 148 rval = (uint32)a1; 149 WRITE_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_WRITEr(unit, rval); 150 rval = (uint32)a0; 151 WRITE_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_WRITEr(unit, rval); 152 153 nbytes = *len; 154 *len = 0; 155 for (i = 0; i < nbytes; i++) { 156 rval = (uint32)saddr_r; 157 soc_reg_field_set(unit, CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_WRITEr, &rval, 158 MASTER_WR_STATUSf, 1); 159 WRITE_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_WRITEr(unit, rval); 160 rval = 0; 161 soc_reg_field_set(unit, CHIPCOMMONG_SMBUS0_SMBUS_MASTER_COMMANDr, &rval, 162 SMBUS_PROTOCOLf, SMBUS_BLOCK_PROCESS_CALL); 163 soc_reg_field_set(unit, CHIPCOMMONG_SMBUS0_SMBUS_MASTER_COMMANDr, &rval, 164 RD_BYTE_COUNTf, 1); 165 WRITE_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_COMMANDr(unit, rval); 166 167 rv = iproc_smbus_start_wait(unit); 168 if (rv == SOC_E_NONE) { 169 READ_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_READr(unit, &rval); 170 data[i] = (uint8)(rval & 0xFF); 171 *len = *len + 1; 172 } else { 173 LOG_INFO(BSL_LS_SOC_I2C, 174 (BSL_META_U(unit, 175 "eep24c64_read(%d,%d,%x,%p,%d): " 176 "failed to read.\n"), 177 unit, devno, addr, (void *)data, *len)); 178 I2C_UNLOCK(unit); 179 return rv; 180 } 181 } 182 } else 183 #endif /* BCM_IPROC_SUPPORT */ 184 #ifdef BCM_CMICM_SUPPORT 185 if(soc_feature(unit, soc_feature_cmicm) && !SOC_IS_SAND(unit)) { 186 rv = soc_i2c_write_word(unit, soc_i2c_addr(unit, devno), addr); 187 nbytes = *len; 188 *len = 0; 189 if (rv == SOC_E_NONE) { 190 for (nread = 0; nread < nbytes; nread++) { 191 rv = soc_i2c_read_byte(unit, soc_i2c_addr(unit, devno), &rx); 192 if(rv != SOC_E_NONE) { 193 if (nread == 0) { 194 /* Might be the situation that the previous write is 195 * under it's internal write-cycle. The max write-cycle 196 * time could reach to 5ms. 197 */ 198 soc_timeout_init(&to, 5000, 3); 199 do { 200 /* coverity[callee_ptr_arith: FALSE] */ 201 rv = soc_i2c_read_byte(unit, soc_i2c_addr(unit, devno), &rx); 202 if (rv == SOC_E_NONE) { 203 break; 204 } 205 } while(!(soc_timeout_check(&to))); 206 } 207 if (rv != SOC_E_NONE) { 208 I2C_UNLOCK(unit); 209 return rv; 210 } 211 } 212 *len = *len + 1; 213 data[nread] = rx; 214 } 215 } 216 } else 217 #endif /* BCM_CMICM_SUPPORT */ 218 { 219 /* First, we put out the address which we would like to 220 * read at using the SOC_I2C_TX_ADDR (saddr_w) 221 */ 222 if ( (rv = soc_i2c_start(unit, saddr_w)) < 0) { 223 LOG_INFO(BSL_LS_SOC_I2C, 224 (BSL_META_U(unit, 225 "eep24c64_read(%d,%d,%x,%p,%d): " 226 "failed to generate start.\n"), 227 unit, devno, addr, (void *)data, *len)); 228 I2C_UNLOCK(unit); 229 return rv; 230 } 231 /* Word Protocol: Address MSB */ 232 if ( (rv = soc_i2c_write_one_byte(unit, a1)) < 0) { 233 LOG_INFO(BSL_LS_SOC_I2C, 234 (BSL_META_U(unit, 235 "eep24c64_read(%d,%d,%x,%p,%d): " 236 "failed to send a1 byte.\n"), 237 unit, devno, addr, (void *)data, *len)); 238 239 goto error; 240 } 241 /* Address LSB */ 242 if( (rv = soc_i2c_write_one_byte(unit, a0)) < 0) { 243 LOG_INFO(BSL_LS_SOC_I2C, 244 (BSL_META_U(unit, 245 "eep24c64_read(%d,%d,%x,%p,%d): " 246 "failed to send a0 byte.\n"), 247 unit, devno, addr, (void *)data, *len)); 248 249 goto error; 250 } 251 /* Now, we have sent the first and second word addresses, 252 * we then issue a repeated start condition, followed by 253 * the device's read address (note: saddr_r) 254 */ 255 if( (rv = soc_i2c_rep_start(unit, saddr_r)) < 0) { 256 LOG_INFO(BSL_LS_SOC_I2C, 257 (BSL_META_U(unit, 258 "eep24c64_read(%d,%d,%x,%p,%d): " 259 "failed to generate rep start.\n"), 260 unit, devno, addr, (void *)data, *len)); 261 goto error; 262 } 263 nbytes = *len; 264 if ( (rv = soc_i2c_read_bytes(unit, data, (int *)&nbytes, 0) ) < 0 ) { 265 goto error; 266 } 267 *len = nbytes; 268 269 error: 270 271 soc_i2c_stop(unit); 272 } 273 274 I2C_UNLOCK(unit); 275 return rv ; 276 } 277 278 /* 279 * Function: eep24c64_write 280 * Purpose: Write len bytes of data, return the number of bytes written. 281 * Uses PAGE mode to write up to 32 bytes at a time between address 282 * stages for maximum performance. See AT24C64 data sheet for more info. 283 * 284 * Parameters: 285 * unit - StrataSwitch device number or I2C bus number 286 * devno - chip device id 287 * addr - NVRAM memory address to write to 288 * data - address of data buffer to write from 289 * len - number of bytes to write 290 * 291 * Returns: 292 * SOC_E_NONE -- no error encountered 293 * SOC_E_TIMEOUT - chip timeout or data error 294 * 295 * 296 * Notes: 297 * Uses page mode to write in 32-byte chunks, when an address 298 * which does not begin on a page boundary is provided, the write 299 * operation handles unaligned accesses by breaking up the write 300 * into one write which is not page aligned, and the remainder as 301 * page aligned accesses. 302 */ 303 STATIC int 304 eep24c64_write(int unit, int devno, 305 uint16 addr, uint8* data, uint32 len) 306 { 307 int rv = SOC_E_NONE; 308 uint8 *ptr, a0, a1; 309 uint32 b, numpages, cpage, nbytes, tbytes, caddr; 310 i2c_bus_addr_t bus_addr; 311 #if defined(BCM_CMICM_SUPPORT) || defined(BCM_IPROC_SUPPORT) 312 uint32 rval; 313 #endif 314 315 /* User must have data to write */ 316 if ( ! data || len <= 0 ) { 317 return SOC_E_PARAM; 318 } 319 320 I2C_LOCK(unit); 321 322 /* Use PAGE mode */ 323 caddr = addr; 324 numpages = 1 + (((caddr%LC2464_PAGE_SIZE)+len-1)/LC2464_PAGE_SIZE); 325 ptr = data; 326 327 328 tbytes = soc_i2c_device(unit, devno)->tbyte++; 329 330 bus_addr = SOC_I2C_TX_ADDR(soc_i2c_addr(unit, devno)); 331 332 LOG_INFO(BSL_LS_SOC_I2C, 333 (BSL_META_U(unit, 334 "eep24c64_write: addr=0x%x data=%p len=%d npages=%d\n"), 335 caddr, (void *)data, (int)len, numpages)); 336 337 /* Loop over every page in buffer .. */ 338 for(cpage = 0; cpage < numpages; cpage++) { 339 if( (caddr % LC2464_PAGE_SIZE) != 0){ 340 /* Address not page aligned, D'Oh, can't write a full page. */ 341 nbytes = LC2464_PAGE_SIZE - (caddr % LC2464_PAGE_SIZE); 342 nbytes = (len > nbytes) ? nbytes : len; 343 len -= nbytes; 344 } else { 345 /* Address is page aligned, calculate bytes to write */ 346 if ( len <= LC2464_PAGE_SIZE ) { 347 /* Less than a page to write */ 348 nbytes = len; 349 } else { 350 /* Wammo, full page write */ 351 nbytes = LC2464_PAGE_SIZE; 352 len -= nbytes; 353 } 354 } 355 356 /* Construct device address bytes */ 357 a1 = (uint8) ((caddr & 0xff00) >> 8); 358 a0 = (uint8) (caddr & 0x00ff); 359 360 LOG_INFO(BSL_LS_SOC_I2C, 361 (BSL_META_U(unit, 362 "eep24c64_write: unit=%d cpage=%d START on page_addr=0x%x" 363 " nbytes=%d\n"), unit, cpage, caddr, nbytes)); 364 365 #ifdef BCM_IPROC_SUPPORT 366 if(soc_feature(unit, soc_feature_eeprom_iproc)) { 367 /* Write Word is achieved with SMBUS_WRITE_BYTE, with LSB of data instead of the command */ 368 rval = SOC_I2C_TX_ADDR(soc_i2c_addr(unit, devno)); 369 WRITE_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_WRITEr(unit, rval); 370 rval = a1; 371 WRITE_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_WRITEr(unit, rval); 372 rval = a0; 373 WRITE_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_WRITEr(unit, rval); 374 375 for ( b = 0; b < nbytes; b++, ptr++, caddr++ ) { 376 rval = *ptr; 377 if(b == (nbytes - 1)) { 378 soc_reg_field_set(unit, CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_WRITEr, 379 &rval, MASTER_WR_STATUSf, 1); /* Last Byte */ 380 } 381 WRITE_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_DATA_WRITEr(unit, rval); 382 soc_i2c_device(unit, devno)->tbyte++; 383 } 384 385 rval = 0; 386 soc_reg_field_set(unit, CHIPCOMMONG_SMBUS0_SMBUS_MASTER_COMMANDr, &rval, SMBUS_PROTOCOLf, SMBUS_BLOCK_WRITE); 387 WRITE_CHIPCOMMONG_SMBUS0_SMBUS_MASTER_COMMANDr(unit, rval); 388 rv = iproc_smbus_start_wait(unit); 389 390 if (rv < 0) { 391 I2C_UNLOCK(unit); 392 return (rv); 393 } 394 395 /* EEPROM after write operation requested need a period of time 396 * (in term of WriteCycle) to finish the programming process 397 * into EEPROM. This driver implement a usleep to wait WriteCycle. 398 */ 399 sal_usleep(5000); 400 } else 401 #endif /* BCM_IPROC_SUPPORT */ 402 #ifdef BCM_CMICM_SUPPORT 403 if(soc_feature(unit, soc_feature_cmicm) && !SOC_IS_SAND(unit)) { 404 /* Write Word is achieved with SMBUS_WRITE_BYTE, with LSB of data instead of the command */ 405 rval = SOC_I2C_TX_ADDR(soc_i2c_addr(unit, devno)); 406 WRITE_CMIC_I2CM_SMBUS_MASTER_DATA_WRITEr(unit, rval); 407 408 rval = a1; 409 WRITE_CMIC_I2CM_SMBUS_MASTER_DATA_WRITEr(unit, rval); 410 rval = a0; 411 WRITE_CMIC_I2CM_SMBUS_MASTER_DATA_WRITEr(unit, rval); 412 413 for ( b = 0; b < nbytes; b++, ptr++, caddr++ ) { 414 rval = *ptr; 415 if(b == (nbytes-1)) { 416 soc_reg_field_set(unit, CMIC_I2CM_SMBUS_MASTER_DATA_WRITEr, &rval, MASTER_WR_STATUSf, 1); /* Last Byte */ 417 } 418 WRITE_CMIC_I2CM_SMBUS_MASTER_DATA_WRITEr(unit, rval); 419 soc_i2c_device(unit, devno)->tbyte++; 420 } 421 422 rval = 0; 423 soc_reg_field_set(unit, CMIC_I2CM_SMBUS_MASTER_COMMANDr, &rval, SMBUS_PROTOCOLf, SMBUS_BLOCK_WRITE); 424 WRITE_CMIC_I2CM_SMBUS_MASTER_COMMANDr(unit,rval); 425 rv = smbus_start_wait(unit); 426 427 if (rv < 0) { 428 I2C_UNLOCK(unit); 429 return (rv); 430 } 431 432 /* EEPROM after write operation requested need a period of time 433 * (in term of WriteCycle) to finish the programming process 434 * into EEPROM. This driver implement a usleep to wait WriteCycle. 435 */ 436 sal_usleep(5000); 437 } else 438 #endif /* BCM_CMICM_SUPPORT */ 439 { 440 /* Generate Start, for Write address */ 441 if( (rv = soc_i2c_start(unit, bus_addr)) < 0){ 442 LOG_INFO(BSL_LS_SOC_I2C, 443 (BSL_META_U(unit, 444 "eep24c64_write(%d,%d,%x,%d,%d): " 445 "failed to gen start\n"), 446 unit, devno, caddr, *data, len)); 447 I2C_UNLOCK(unit); 448 return rv; 449 } 450 /* Send MSB (a1), wait for ACK */ 451 if( (rv = soc_i2c_write_one_byte(unit, a1)) < 0){ 452 LOG_INFO(BSL_LS_SOC_I2C, 453 (BSL_META_U(unit, 454 "eep24c64_write(%d,%d,%x,%d,%d): " 455 "failed to send a1 byte\n"), 456 unit, devno, caddr, *data, len)); 457 goto error; 458 } 459 /* Send LSB (a0), wait for ACK */ 460 if( (rv = soc_i2c_write_one_byte(unit, a0)) < 0){ 461 LOG_INFO(BSL_LS_SOC_I2C, 462 (BSL_META_U(unit, 463 "eep24c64_write(%d,%d,%x,%d,%d): " 464 "failed to send a0 byte\n"), 465 unit, devno, caddr, *data, len)); 466 goto error; 467 } 468 /* Send up to PAGE_SIZE data bytes, wait for ACK */ 469 for ( b = 0; b < nbytes; b++, ptr++, caddr++ ) { 470 if ( (rv = soc_i2c_write_one_byte(unit, *ptr)) < 0){ 471 LOG_INFO(BSL_LS_SOC_I2C, 472 (BSL_META_U(unit, 473 "eep24c64_write(%d,%d,%d,%d,%d): " 474 "tx data byte error\n"), 475 unit, devno, caddr, (uint32)*ptr, b)); 476 goto error; 477 } 478 LOG_VERBOSE(BSL_LS_SOC_I2C, 479 (BSL_META_U(unit, 480 "eep24c64_write(u=%d,id=%d,page=%d " 481 "caddr=%d,data=0x%x,idx=%d)\n"), 482 unit, devno, cpage, caddr, (uint8)*ptr, b)); 483 484 soc_i2c_device(unit, devno)->tbyte++; 485 } 486 487 /* Send STOP, also what we do on an error to free bus.. */ 488 error: 489 490 soc_i2c_stop(unit); 491 492 /* Acknowledge polling: When the chip enters it's 493 * own internal write-cycle, it falls off the I2C bus 494 * and does not ACK a start/address phase; hence, we 495 * attempt addressing the chip until it responds, at 496 * which point the internal write cycle has finished. 497 */ 498 rv = eep24c64_ack_poll(unit, bus_addr); 499 LOG_INFO(BSL_LS_SOC_I2C, 500 (BSL_META_U(unit, 501 "eep24c64_ack_poll: " 502 "%d address cycles for wr latency.\n"), rv)); 503 rv = (rv > 0 ? SOC_E_NONE: SOC_E_TIMEOUT); 504 } 505 } 506 507 I2C_UNLOCK(unit); 508 509 if (rv >= 0) { 510 return soc_i2c_device(unit, devno)->tbyte - tbytes - 1 ; 511 } else { 512 return (rv); 513 } 514 } 515 516 /* 517 * Function: eep24c64_checksum 518 * 519 * Purpose: 16 bit incremental checksum; used for checking data 520 * validity of the configuration parameter block. 521 * Parameters: 522 * partial - partial checksum, or zero if initial checksum, 523 * updated on each call. 524 * data - data buffer to checksum 525 * len - size of data buffer to checksum 526 * 527 * Returns: updated checksum value 528 * 529 * Notes: 530 * This routine is called incrementally, one or more times, 531 * and each time, the new checksum value is returned. The first 532 * time this routine is called, pass 0 as the initial checksum 533 * value. On succesive calls, pass the last computed checksum 534 * value. 535 */ 536 STATIC uint16 537 eep24c64_chksum(uint16 partial, uint8* data, int len) 538 { 539 uint8* dp; 540 uint8 c0, c1; 541 int i; 542 543 partial = soc_ntohs(partial); 544 545 c0 = (uint8) partial; 546 c1 = (uint8) (partial >> 8); 547 548 for ( i=0, dp = (uint8*)data; i < len; i++, dp++) { 549 c0 += *dp; 550 c1 += c0; 551 } 552 partial = (c1 << 8) + c0; 553 return soc_htons(partial); 554 } 555 556 /* 557 * Function: eep24c64_get_params 558 * 559 * Purpose: Get EEPROM configuration block from I2C NVRAM. 560 * Used internally by driver, demonstrates how to reliably 561 * store configuration parameters with a checksum. 562 * 563 * Parameters: 564 * u - StrataSwitch device number or I2C bus number 565 * d - chip device id 566 * c - NVRAM configuration block. 567 * 568 * Returns: 569 * SOC_E_INTERNAL - checksum bad, contents invalid. 570 * SOC_E_NONE - checksum read and contents valid. 571 */ 572 STATIC int 573 eep24c64_get_params(uint32 u, uint32 d, eep24c64_t* c) 574 { 575 int r = SOC_E_NONE; 576 int l = sizeof(eep24c64_t); 577 uint16 savesum, sum; 578 579 if ( !c ) 580 return SOC_E_PARAM; 581 582 if ( (r = eep24c64_read(u, d, 0, (uint8*)c, (uint32 *)&l)) < 0 ) { 583 LOG_INFO(BSL_LS_SOC_I2C, 584 (BSL_META_U(u, 585 "eep24c64_get_params: %s\n"), soc_errmsg(r))); 586 return r; 587 } 588 /* Checksum config block */ 589 savesum = c->chksum; 590 sum = eep24c64_chksum(0, (uint8 *)&c->size, sizeof(uint16) ); 591 sum = eep24c64_chksum(sum,(uint8 *)&c->type, sizeof(uint16) ); 592 sum = eep24c64_chksum(sum,(uint8 *)&c->name, LC2464_NAME_LEN); 593 594 if ( sum != savesum ) { 595 LOG_VERBOSE(BSL_LS_SOC_COMMON, 596 (BSL_META_U(u, 597 "%s: NOTICE: EEPROM contents invalid or bad checksum\n"), 598 soc_i2c_devname(u, d))); 599 return SOC_E_INTERNAL; 600 } 601 602 return r ; 603 } 604 605 /* 606 * Function: eep24c64_set_params 607 * 608 * Purpose: Set EEPROM configuration block into NVRAM. 609 * 610 * Parameters: 611 * u - StrataSwitch device number or I2C bus number 612 * d - chip device id 613 * c - NVRAM configuration block. 614 * 615 * Returns: 616 * SOC_E_TIMEOUT - write error or chip timeout 617 * SOC_E_NONE - configuration block and checksum updated, written to NVRAM. 618 */ 619 STATIC int 620 eep24c64_set_params(uint32 u, uint32 d, eep24c64_t* c) 621 { 622 int rv = SOC_E_NONE; 623 int l = sizeof(eep24c64_t); 624 uint16 sum = 0; 625 626 if ( !c ) 627 return SOC_E_PARAM; 628 629 /* Checksum config block (over length and checksum) */ 630 sum = eep24c64_chksum(0, (uint8 *)&c->size, sizeof(uint16) ); 631 sum = eep24c64_chksum(sum,(uint8 *)&c->type, sizeof(uint16) ); 632 sum = eep24c64_chksum(sum,(uint8 *)&c->name, LC2464_NAME_LEN); 633 c->chksum = sum; 634 return (rv = eep24c64_write(u, d, 0, (uint8*)c, l)) == l ? SOC_E_NONE : rv; 635 } 636 637 /* 638 * Macro: GET_IO_STAT 639 * Purpose: Used to measure I/O performance of NVRAM reads and writes. 640 * Parameters: 641 * rtn - C function to call 642 * name - string to display 643 * sz - number of bytes I/O 644 */ 645 646 #ifdef COMPILER_HAS_DOUBLE 647 #define GET_IO_STAT(rtn, sz, name, op) { \ 648 COMPILER_DOUBLE stime, etime; \ 649 stime = sal_time_double(); \ 650 (rtn); \ 651 etime = sal_time_double(); \ 652 LOG_VERBOSE(BSL_LS_SOC_COMMON, \ 653 (BSL_META("%s: %s took %.2f sec %.2fKB/sec\n"), \ 654 name, op, etime - stime, \ 655 sz / (etime - stime) / 1024)); \ 656 } 657 #else 658 #define GET_IO_STAT(rtn, sz, name, op) { \ 659 COMPILER_DOUBLE stime, etime; \ 660 stime = sal_time_usecs(); \ 661 (rtn); \ 662 etime = sal_time_usecs(); \ 663 LOG_VERBOSE(BSL_LS_SOC_COMMON, \ 664 (BSL_META("%s: %s took %u usec %dKB/sec\n"), \ 665 name, op, etime - stime, \ 666 sz * (SECOND_USEC / 1024) / (etime - stime))); \ 667 } 668 #endif /* COMPILER_HAS_DOUBLE */ 669 670 /* 671 * Function: eep24c64_init 672 * 673 * Purpose: initialize the ATMEL 24C64 NVRAM chip. Attempt to read 674 * checksum, if checksum is invalid, attempt to write a pattern 675 * to the first three quadrants of the 64K chip, and then read 676 * it all back, checking each byte to verify data integrity. When 677 * finished, write the new configuration block to the start 678 * of the chip. 679 * 680 * The last quadrant of the NVRAM is write protectable and 681 * stores read-only static information about the platform. 682 * 683 * If the checksum is valid, simply display the checksum and 684 * number of bytes tested initially when the chip was probed. 685 * 686 * Parameters: 687 * unit - StrataSwitch device number or I2C bus number 688 * devno - chip device id 689 * data - address of test data 690 * len - size of test data 691 * 692 * 693 * Notes: When the initial NVRAM is configured, this test destructively 694 * modifies the NVRAM contents. If the NVRAM ever becomes 695 * corrupt, this driver will clear the NVRAM with a new data 696 * pattern. All reads and writes should be performed past the 697 * NVRAM configuration block (LC24C64_DATA_START). 698 */ 699 STATIC int 700 eep24c64_init(int unit, int devno, void* data, int len) 701 { 702 eep24c64_t config; 703 uint8 pattern; 704 const char *devname; 705 706 #ifdef CLEAR_NVRAM_BLOCK 707 eep24c64_write(unit, devno, 0, "nvm", 3); 708 #endif 709 710 devname = soc_i2c_devname(unit, devno); 711 soc_i2c_devdesc_set(unit, devno, "Atmel 24C64 Serial EEPROM"); 712 713 sal_memset(&config, 0 , sizeof(eep24c64_t)); 714 715 716 if ( eep24c64_get_params( unit, devno, &config) < 0 ) { 717 int i, j, rlen = len; 718 uint8* outbuf = (uint8*)data; 719 uint8* inbuf = NULL; 720 721 #ifdef RANDOM_PAGE_TEST 722 inbuf = (uint8*)sal_alloc(len, "i2c"); 723 /* Fragmented (page and then some) write .. */ 724 for(i = 0; i <= LC2464_DEVICE_RW_SIZE/8; i+= len){ 725 LOG_INFO(BSL_LS_SOC_I2C, 726 (BSL_META_U(unit, 727 "eep24c64_init: unit=%d bytes=%d\n"), unit, i)); 728 /* Write buffer to EEPROM */ 729 eep24c64_write(unit, devno, i, outbuf, len); 730 /* Read back data just written */ 731 eep24c64_read(unit, devno, i, inbuf, &rlen); 732 733 /* Verify each byte */ 734 for( j = 0; j < len; j++){ 735 if ( inbuf[j] != outbuf[j]){ 736 LOG_VERBOSE(BSL_LS_SOC_COMMON, 737 (BSL_META_U(unit, 738 "%s: ERROR: EEPROM miscompare " 739 "off=%d expected=0x%x " 740 "got 0x%x (addr=%d in page)\n"), 741 devname, 742 i+j, outbuf[j], inbuf[j], j)); 743 } 744 } 745 } 746 sal_free(inbuf); 747 #endif 748 749 LOG_VERBOSE(BSL_LS_SOC_COMMON, 750 (BSL_META_U(unit, 751 "%s: testing data integrity, %d bytes\n"), 752 devname, LC2464_DEVICE_RW_SIZE)); 753 754 /* Full buffer write in one shot ...*/ 755 len = LC2464_DEVICE_RW_SIZE; 756 outbuf = (uint8*)sal_alloc(len, "i2c"); 757 if (outbuf == NULL) { 758 return SOC_E_MEMORY; 759 } 760 inbuf = (uint8*)sal_alloc(len, "i2c"); 761 if (inbuf == NULL) { 762 sal_free(outbuf); 763 return SOC_E_MEMORY; 764 } 765 766 /* Write known pattern, clobber the parameter block */ 767 sal_memset(inbuf, 0x0, len); 768 pattern = (uint8) sal_time_usecs(); 769 sal_memset(outbuf,pattern, len); 770 LOG_VERBOSE(BSL_LS_SOC_COMMON, 771 (BSL_META_U(unit, 772 "%s: writing %d bytes pattern=0x%x\n"), 773 devname, len, pattern)); 774 775 GET_IO_STAT(rlen = eep24c64_write(unit, devno, 0, outbuf, len), 776 LC2464_DEVICE_RW_SIZE, devname, "write"); 777 778 if (rlen == LC2464_DEVICE_RW_SIZE ) 779 ; /* write was ok */ 780 else if (rlen > 0) 781 LOG_VERBOSE(BSL_LS_SOC_COMMON, 782 (BSL_META_U(unit, 783 "%s: ERROR: only %d out of %d bytes written!\n"), 784 devname, rlen, len)); 785 else 786 LOG_VERBOSE(BSL_LS_SOC_COMMON, 787 (BSL_META_U(unit, 788 "%s: ERROR: write failed: %s\n"), 789 devname, soc_errmsg(rlen))); 790 791 /* Clear receive buffer */ 792 sal_memset(inbuf, 0x0, len); 793 rlen = len; 794 795 LOG_VERBOSE(BSL_LS_SOC_COMMON, 796 (BSL_META_U(unit, 797 "%s: reading %d bytes\n"), devname, rlen)); 798 799 GET_IO_STAT(eep24c64_read(unit, devno, 0, inbuf, (uint32 *)&rlen), 800 rlen, devname, "read"); 801 802 if (rlen == LC2464_DEVICE_RW_SIZE) 803 ; /* read was ok */ 804 else if (rlen > 0) 805 LOG_VERBOSE(BSL_LS_SOC_COMMON, 806 (BSL_META_U(unit, 807 "%s: ERROR: only %d out of %d bytes read!\n"), 808 devname, rlen, len)); 809 else 810 LOG_VERBOSE(BSL_LS_SOC_COMMON, 811 (BSL_META_U(unit, 812 "%s: ERROR: read failed: %s\n"), 813 devname, soc_errmsg(rlen))); 814 815 i = 0; 816 for( j = 0; j < LC2464_DEVICE_RW_SIZE; j++){ 817 if ( inbuf[j] != outbuf[j]){ 818 LOG_VERBOSE(BSL_LS_SOC_COMMON, 819 (BSL_META_U(unit, 820 "%s: ERROR: miscompare at offset=%d " 821 "expected=0x%x got 0x%x (addr=%d in page)\n"), 822 devname, i+j, outbuf[j], inbuf[j], j)); 823 i = -1; 824 break; 825 } 826 } 827 828 if(i == 0) 829 LOG_VERBOSE(BSL_LS_SOC_COMMON, 830 (BSL_META_U(unit, 831 "%s: test passed (%d bytes verified)\n"), 832 devname, len)); 833 834 sal_free(inbuf); 835 sal_free(outbuf); 836 837 /* Write configuration block to NVRAM */ 838 config.size = (uint16)rlen - LC24C64_DATA_START; 839 config.type = 0x70; 840 sal_memset(config.name, 0x0,LC2464_NAME_LEN); 841 842 if(sal_strlen(soc_i2c_devname(unit,devno)) > LC2464_NAME_LEN ) { 843 LOG_WARN(BSL_LS_SOC_I2C, 844 (BSL_META_U(unit, 845 "Device name %s too long, trimming it .... \n"), 846 soc_i2c_devname(unit , devno))); 847 sal_memcpy(config.name , soc_i2c_devname(unit, devno), LC2464_NAME_LEN - 1); 848 config.name[LC2464_NAME_LEN - 1] = '\0'; 849 } else { 850 sal_strncpy(config.name, soc_i2c_devname(unit,devno), LC2464_NAME_LEN - 1); 851 config.name[LC2464_NAME_LEN - 1] = '\0'; 852 } 853 return eep24c64_set_params(unit, devno, &config); 854 855 } 856 857 return SOC_E_NONE; 858 } 859 860 /* 861 * Function: eep24c64_ioctl: does miscellaenous tasks. 862 * Purpose: Support miscellaneous chip options. 863 * 864 * Parameters: 865 * unit - StrataSwitch device number or I2C bus number 866 * devno - chip device id 867 * command - IO control operation 868 * data - address of user data 869 * len - size of test data 870 * 871 * Notes: 872 * Placeholder for write Protect, EEPROM Chip reset - NYI 873 */ 874 STATIC int 875 eep24c64_ioctl(int unit, int devno, 876 int command, void* data, int len) 877 { 878 switch ( command ) { 879 880 default: 881 break; 882 } 883 return SOC_E_NONE; 884 } 885 886 887 /* AT24C64 64K Serial EEPROM Driver callout */ 888 i2c_driver_t _soc_i2c_eep24c64_driver = { 889 0x0,0x0, /* System assigned bytes */ 890 LC24C64_DEVICE_TYPE, 891 eep24c64_read, 892 eep24c64_write, 893 eep24c64_ioctl, 894 eep24c64_init, 895 NULL, 896 }; 897 898 899 900 901 902 903 904 905