1/* pmc93x6_eeprom.c - PMC's 93LC46 EEPROM Device 2 * 3 * The 93LC46 is a low-power, serial Electrically Erasable and 4 * Programmable Read Only Memory organized as 128 8-bit bytes. 5 * 6 * Accesses to the 93LC46 are done in a bit serial stream, organized 7 * in a 3 wire format. Writes are internally timed by the device 8 * (the In data bit is pulled low until the write is complete and 9 * then is pulled high) and take about 6 milliseconds. 10 * 11 * Copyright (C) 2003-2005 SBE, Inc. 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or 16 * (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 */ 23 24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 25 26#include <linux/types.h> 27#include "pmcc4_sysdep.h" 28#include "sbecom_inline_linux.h" 29#include "pmcc4.h" 30#include "sbe_promformat.h" 31 32#ifndef TRUE 33#define TRUE 1 34#define FALSE 0 35#endif 36 37/*------------------------------------------------------------------------ 38 * EEPROM address definitions 39 *------------------------------------------------------------------------ 40 * 41 * The offset in the definitions below allows the test to skip over 42 * areas of the EEPROM that other programs (such a VxWorks) are 43 * using. 44 */ 45 46#define EE_MFG (long)0 /* Index to manufacturing record */ 47#define EE_FIRST 0x28 /* Index to start testing at */ 48#define EE_LIMIT 128 /* Index to end testing at */ 49 50 51/* Bit Ordering for Instructions 52** 53** A0, A1, A2, A3, A4, A5, A6, OP0, OP1, SB (lsb, or 1st bit out) 54** 55*/ 56 57#define EPROM_EWEN 0x0019 /* Erase/Write enable (reversed) */ 58#define EPROM_EWDS 0x0001 /* Erase/Write disable (reversed) */ 59#define EPROM_READ 0x0003 /* Read (reversed) */ 60#define EPROM_WRITE 0x0005 /* Write (reversed) */ 61#define EPROM_ERASE 0x0007 /* Erase (reversed) */ 62#define EPROM_ERAL 0x0009 /* Erase All (reversed) */ 63#define EPROM_WRAL 0x0011 /* Write All (reversed) */ 64 65#define EPROM_ADR_SZ 7 /* Number of bits in offset address */ 66#define EPROM_OP_SZ 3 /* Number of bits in command */ 67#define SIZE_ADDR_OP (EPROM_ADR_SZ + EPROM_OP_SZ) 68#define LC46A_MAX_OPS 10 /* Number of bits in Instruction */ 69#define NUM_OF_BITS 8 /* Number of bits in data */ 70 71 72/* EEPROM signal bits */ 73#define EPROM_ACTIVE_OUT_BIT 0x0001 /* Out data bit */ 74#define EPROM_ACTIVE_IN_BIT 0x0002 /* In data bit */ 75#define ACTIVE_IN_BIT_SHIFT 0x0001 /* Shift In data bit to LSB */ 76#define EPROM_ENCS 0x0004 /* Set EEPROM CS during operation */ 77 78 79/*------------------------------------------------------------------------ 80 * The ByteReverse table is used to reverses the 8 bits within a byte 81 *------------------------------------------------------------------------ 82 */ 83 84static unsigned char ByteReverse[256]; 85static int ByteReverseBuilt = FALSE; 86 87 88/*------------------------------------------------------------------------ 89 * mfg_template - initial serial EEPROM data structure 90 *------------------------------------------------------------------------ 91 */ 92 93short mfg_template[sizeof (FLD_TYPE2)] = 94{ 95 PROM_FORMAT_TYPE2, /* type; */ 96 0x00, 0x1A, /* length[2]; */ 97 0x00, 0x00, 0x00, 0x00, /* Crc32[4]; */ 98 0x11, 0x76, /* Id[2]; */ 99 0x07, 0x05, /* SubId[2] E1; */ 100 0x00, 0xA0, 0xD6, 0x00, 0x00, 0x00, /* Serial[6]; */ 101 0x00, 0x00, 0x00, 0x00, /* CreateTime[4]; */ 102 0x00, 0x00, 0x00, 0x00, /* HeatRunTime[4]; */ 103 0x00, 0x00, 0x00, 0x00, /* HeatRunIterations[4]; */ 104 0x00, 0x00, 0x00, 0x00, /* HeatRunErrors[4]; */ 105}; 106 107 108/*------------------------------------------------------------------------ 109 * BuildByteReverse - build the 8-bit reverse table 110 *------------------------------------------------------------------------ 111 * 112 * The 'ByteReverse' table reverses the 8 bits within a byte 113 * (the MSB becomes the LSB etc.). 114 */ 115 116static void 117BuildByteReverse (void) 118{ 119 long half; /* Used to build by powers to 2 */ 120 int i; 121 122 ByteReverse[0] = 0; 123 124 for (half = 1; half < sizeof (ByteReverse); half <<= 1) 125 for (i = 0; i < half; i++) 126 ByteReverse[half + i] = (char) (ByteReverse[i] | (0x80 / half)); 127 128 ByteReverseBuilt = TRUE; 129} 130 131 132/*------------------------------------------------------------------------ 133 * eeprom_delay - small delay for EEPROM timing 134 *------------------------------------------------------------------------ 135 */ 136 137static void 138eeprom_delay (void) 139{ 140 int timeout; 141 142 for (timeout = 20; timeout; --timeout) 143 { 144 OS_uwait_dummy (); 145 } 146} 147 148 149/*------------------------------------------------------------------------ 150 * eeprom_put_byte - Send a byte to the EEPROM serially 151 *------------------------------------------------------------------------ 152 * 153 * Given the PCI address and the data, this routine serially sends 154 * the data to the EEPROM. 155 */ 156 157void 158eeprom_put_byte (long addr, long data, int count) 159{ 160 u_int32_t output; 161 162 while (--count >= 0) 163 { 164 output = (data & EPROM_ACTIVE_OUT_BIT) ? 1 : 0; /* Get next data bit */ 165 output |= EPROM_ENCS; /* Add Chip Select */ 166 data >>= 1; 167 168 eeprom_delay (); 169 pci_write_32 ((u_int32_t *) addr, output); /* Output it */ 170 } 171} 172 173 174/*------------------------------------------------------------------------ 175 * eeprom_get_byte - Receive a byte from the EEPROM serially 176 *------------------------------------------------------------------------ 177 * 178 * Given the PCI address, this routine serially fetches the data 179 * from the EEPROM. 180 */ 181 182u_int32_t 183eeprom_get_byte (long addr) 184{ 185 u_int32_t input; 186 u_int32_t data; 187 int count; 188 189/* Start the Reading of DATA 190** 191** The first read is a dummy as the data is latched in the 192** EPLD and read on the next read access to the EEPROM. 193*/ 194 195 input = pci_read_32 ((u_int32_t *) addr); 196 197 data = 0; 198 count = NUM_OF_BITS; 199 while (--count >= 0) 200 { 201 eeprom_delay (); 202 input = pci_read_32 ((u_int32_t *) addr); 203 204 data <<= 1; /* Shift data over */ 205 data |= (input & EPROM_ACTIVE_IN_BIT) ? 1 : 0; 206 207 } 208 209 return data; 210} 211 212 213/*------------------------------------------------------------------------ 214 * disable_pmc_eeprom - Disable writes to the EEPROM 215 *------------------------------------------------------------------------ 216 * 217 * Issue the EEPROM command to disable writes. 218 */ 219 220static void 221disable_pmc_eeprom (long addr) 222{ 223 eeprom_put_byte (addr, EPROM_EWDS, SIZE_ADDR_OP); 224 225 pci_write_32 ((u_int32_t *) addr, 0); /* this removes Chip Select 226 * from EEPROM */ 227} 228 229 230/*------------------------------------------------------------------------ 231 * enable_pmc_eeprom - Enable writes to the EEPROM 232 *------------------------------------------------------------------------ 233 * 234 * Issue the EEPROM command to enable writes. 235 */ 236 237static void 238enable_pmc_eeprom (long addr) 239{ 240 eeprom_put_byte (addr, EPROM_EWEN, SIZE_ADDR_OP); 241 242 pci_write_32 ((u_int32_t *) addr, 0); /* this removes Chip Select 243 * from EEPROM */ 244} 245 246 247/*------------------------------------------------------------------------ 248 * pmc_eeprom_read - EEPROM location read 249 *------------------------------------------------------------------------ 250 * 251 * Given a EEPROM PCI address and location offset, this routine returns 252 * the contents of the specified location to the calling routine. 253 */ 254 255u_int32_t 256pmc_eeprom_read (long addr, long mem_offset) 257{ 258 u_int32_t data; /* Data from chip */ 259 260 if (!ByteReverseBuilt) 261 BuildByteReverse (); 262 263 mem_offset = ByteReverse[0x7F & mem_offset]; /* Reverse address */ 264 /* 265 * NOTE: The max offset address is 128 or half the reversal table. So the 266 * LSB is always zero and counts as a built in shift of one bit. So even 267 * though we need to shift 3 bits to make room for the command, we only 268 * need to shift twice more because of the built in shift. 269 */ 270 mem_offset <<= 2; /* Shift for command */ 271 mem_offset |= EPROM_READ; /* Add command */ 272 273 eeprom_put_byte (addr, mem_offset, SIZE_ADDR_OP); /* Output chip address */ 274 275 data = eeprom_get_byte (addr); /* Read chip data */ 276 277 pci_write_32 ((u_int32_t *) addr, 0); /* Remove Chip Select from 278 * EEPROM */ 279 280 return (data & 0x000000FF); 281} 282 283 284/*------------------------------------------------------------------------ 285 * pmc_eeprom_write - EEPROM location write 286 *------------------------------------------------------------------------ 287 * 288 * Given a EEPROM PCI address, location offset and value, this 289 * routine writes the value to the specified location. 290 * 291 * Note: it is up to the caller to determine if the write 292 * operation succeeded. 293 */ 294 295int 296pmc_eeprom_write (long addr, long mem_offset, u_int32_t data) 297{ 298 volatile u_int32_t temp; 299 int count; 300 301 if (!ByteReverseBuilt) 302 BuildByteReverse (); 303 304 mem_offset = ByteReverse[0x7F & mem_offset]; /* Reverse address */ 305 /* 306 * NOTE: The max offset address is 128 or half the reversal table. So the 307 * LSB is always zero and counts as a built in shift of one bit. So even 308 * though we need to shift 3 bits to make room for the command, we only 309 * need to shift twice more because of the built in shift. 310 */ 311 mem_offset <<= 2; /* Shift for command */ 312 mem_offset |= EPROM_WRITE; /* Add command */ 313 314 eeprom_put_byte (addr, mem_offset, SIZE_ADDR_OP); /* Output chip address */ 315 316 data = ByteReverse[0xFF & data];/* Reverse data */ 317 eeprom_put_byte (addr, data, NUM_OF_BITS); /* Output chip data */ 318 319 pci_write_32 ((u_int32_t *) addr, 0); /* Remove Chip Select from 320 * EEPROM */ 321 322/* 323** Must see Data In at a low state before completing this transaction. 324** 325** Afterwards, the data bit will return to a high state, ~6 ms, terminating 326** the operation. 327*/ 328 pci_write_32 ((u_int32_t *) addr, EPROM_ENCS); /* Re-enable Chip Select */ 329 temp = pci_read_32 ((u_int32_t *) addr); /* discard first read */ 330 temp = pci_read_32 ((u_int32_t *) addr); 331 if (temp & EPROM_ACTIVE_IN_BIT) 332 { 333 temp = pci_read_32 ((u_int32_t *) addr); 334 if (temp & EPROM_ACTIVE_IN_BIT) 335 { 336 pci_write_32 ((u_int32_t *) addr, 0); /* Remove Chip Select 337 * from EEPROM */ 338 return (1); 339 } 340 } 341 count = 1000; 342 while (count--) 343 { 344 for (temp = 0; temp < 0x10; temp++) 345 OS_uwait_dummy (); 346 347 if (pci_read_32 ((u_int32_t *) addr) & EPROM_ACTIVE_IN_BIT) 348 break; 349 } 350 351 if (count == -1) 352 return (2); 353 354 return (0); 355} 356 357 358/*------------------------------------------------------------------------ 359 * pmcGetBuffValue - read the specified value from buffer 360 *------------------------------------------------------------------------ 361 */ 362 363long 364pmcGetBuffValue (char *ptr, int size) 365{ 366 long value = 0; 367 int index; 368 369 for (index = 0; index < size; ++index) 370 { 371 value <<= 8; 372 value |= ptr[index] & 0xFF; 373 } 374 375 return value; 376} 377 378 379/*------------------------------------------------------------------------ 380 * pmcSetBuffValue - save the specified value to buffer 381 *------------------------------------------------------------------------ 382 */ 383 384void 385pmcSetBuffValue (char *ptr, long value, int size) 386{ 387 int index = size; 388 389 while (--index >= 0) 390 { 391 ptr[index] = (char) (value & 0xFF); 392 value >>= 8; 393 } 394} 395 396 397/*------------------------------------------------------------------------ 398 * pmc_eeprom_read_buffer - read EEPROM data into specified buffer 399 *------------------------------------------------------------------------ 400 */ 401 402void 403pmc_eeprom_read_buffer (long addr, long mem_offset, char *dest_ptr, int size) 404{ 405 while (--size >= 0) 406 *dest_ptr++ = (char) pmc_eeprom_read (addr, mem_offset++); 407} 408 409 410/*------------------------------------------------------------------------ 411 * pmc_eeprom_write_buffer - write EEPROM data from specified buffer 412 *------------------------------------------------------------------------ 413 */ 414 415void 416pmc_eeprom_write_buffer (long addr, long mem_offset, char *dest_ptr, int size) 417{ 418 enable_pmc_eeprom (addr); 419 420 while (--size >= 0) 421 pmc_eeprom_write (addr, mem_offset++, *dest_ptr++); 422 423 disable_pmc_eeprom (addr); 424} 425 426 427/*------------------------------------------------------------------------ 428 * pmcCalcCrc - calculate the CRC for the serial EEPROM structure 429 *------------------------------------------------------------------------ 430 */ 431 432u_int32_t 433pmcCalcCrc_T01 (void *bufp) 434{ 435 FLD_TYPE2 *buf = bufp; 436 u_int32_t crc; /* CRC of the structure */ 437 438 /* Calc CRC for type and length fields */ 439 sbeCrc ( 440 (u_int8_t *) &buf->type, 441 (u_int32_t) STRUCT_OFFSET (FLD_TYPE1, Crc32), 442 (u_int32_t) 0, 443 (u_int32_t *) &crc); 444 445#ifdef EEPROM_TYPE_DEBUG 446 pr_info("sbeCrc: crc 1 calculated as %08x\n", crc); /* RLD DEBUG */ 447#endif 448 return ~crc; 449} 450 451u_int32_t 452pmcCalcCrc_T02 (void *bufp) 453{ 454 FLD_TYPE2 *buf = bufp; 455 u_int32_t crc; /* CRC of the structure */ 456 457 /* Calc CRC for type and length fields */ 458 sbeCrc ( 459 (u_int8_t *) &buf->type, 460 (u_int32_t) STRUCT_OFFSET (FLD_TYPE2, Crc32), 461 (u_int32_t) 0, 462 (u_int32_t *) &crc); 463 464 /* Calc CRC for remaining fields */ 465 sbeCrc ( 466 (u_int8_t *) &buf->Id[0], 467 (u_int32_t) (sizeof (FLD_TYPE2) - STRUCT_OFFSET (FLD_TYPE2, Id)), 468 (u_int32_t) crc, 469 (u_int32_t *) &crc); 470 471#ifdef EEPROM_TYPE_DEBUG 472 pr_info("sbeCrc: crc 2 calculated as %08x\n", crc); /* RLD DEBUG */ 473#endif 474 return crc; 475} 476 477 478/*------------------------------------------------------------------------ 479 * pmc_init_seeprom - initialize the serial EEPROM structure 480 *------------------------------------------------------------------------ 481 * 482 * At the front of the serial EEPROM there is a record that contains 483 * manufacturing information. If the info does not already exist, it 484 * is created. The only field modifiable by the operator is the 485 * serial number field. 486 */ 487 488void 489pmc_init_seeprom (u_int32_t addr, u_int32_t serialNum) 490{ 491 PROMFORMAT buffer; /* Memory image of structure */ 492 u_int32_t crc; /* CRC of structure */ 493 time_t createTime; 494 int i; 495 496 createTime = get_seconds (); 497 498 /* use template data */ 499 for (i = 0; i < sizeof (FLD_TYPE2); ++i) 500 buffer.bytes[i] = mfg_template[i]; 501 502 /* Update serial number field in buffer */ 503 pmcSetBuffValue (&buffer.fldType2.Serial[3], serialNum, 3); 504 505 /* Update create time field in buffer */ 506 pmcSetBuffValue (&buffer.fldType2.CreateTime[0], createTime, 4); 507 508 /* Update CRC field in buffer */ 509 crc = pmcCalcCrc_T02 (&buffer); 510 pmcSetBuffValue (&buffer.fldType2.Crc32[0], crc, 4); 511 512#ifdef DEBUG 513 for (i = 0; i < sizeof (FLD_TYPE2); ++i) 514 pr_info("[%02X] = %02X\n", i, buffer.bytes[i] & 0xFF); 515#endif 516 517 /* Write structure to serial EEPROM */ 518 pmc_eeprom_write_buffer (addr, EE_MFG, (char *) &buffer, sizeof (FLD_TYPE2)); 519} 520 521 522char 523pmc_verify_cksum (void *bufp) 524{ 525 FLD_TYPE1 *buf1 = bufp; 526 FLD_TYPE2 *buf2 = bufp; 527 u_int32_t crc1, crc2; /* CRC read from EEPROM */ 528 529 /* Retrieve contents of CRC field */ 530 crc1 = pmcGetBuffValue (&buf1->Crc32[0], sizeof (buf1->Crc32)); 531#ifdef EEPROM_TYPE_DEBUG 532 pr_info("EEPROM: chksum 1 reads as %08x\n", crc1); /* RLD DEBUG */ 533#endif 534 if ((buf1->type == PROM_FORMAT_TYPE1) && 535 (pmcCalcCrc_T01 ((void *) buf1) == crc1)) 536 return PROM_FORMAT_TYPE1; /* checksum type 1 verified */ 537 538 crc2 = pmcGetBuffValue (&buf2->Crc32[0], sizeof (buf2->Crc32)); 539#ifdef EEPROM_TYPE_DEBUG 540 pr_info("EEPROM: chksum 2 reads as %08x\n", crc2); /* RLD DEBUG */ 541#endif 542 if ((buf2->type == PROM_FORMAT_TYPE2) && 543 (pmcCalcCrc_T02 ((void *) buf2) == crc2)) 544 return PROM_FORMAT_TYPE2; /* checksum type 2 verified */ 545 546 return PROM_FORMAT_Unk; /* failed to validate */ 547} 548 549 550/*** End-of-File ***/ 551