1 /* pmc93x6_eeprom.c - PMC's 93LC46 EEPROM Device
3 * The 93LC46 is a low-power, serial Electrically Erasable and
4 * Programmable Read Only Memory organized as 128 8-bit bytes.
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.
11 * Copyright (C) 2003-2005 SBE, Inc.
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.
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.
24 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26 #include <linux/types.h>
27 #include "pmcc4_sysdep.h"
28 #include "sbecom_inline_linux.h"
30 #include "sbe_promformat.h"
37 #ifdef SBE_INCLUDE_SYMBOLS
44 /*------------------------------------------------------------------------
45 * EEPROM address definitions
46 *------------------------------------------------------------------------
48 * The offset in the definitions below allows the test to skip over
49 * areas of the EEPROM that other programs (such a VxWorks) are
53 #define EE_MFG (long)0 /* Index to manufacturing record */
54 #define EE_FIRST 0x28 /* Index to start testing at */
55 #define EE_LIMIT 128 /* Index to end testing at */
58 /* Bit Ordering for Instructions
60 ** A0, A1, A2, A3, A4, A5, A6, OP0, OP1, SB (lsb, or 1st bit out)
64 #define EPROM_EWEN 0x0019 /* Erase/Write enable (reversed) */
65 #define EPROM_EWDS 0x0001 /* Erase/Write disable (reversed) */
66 #define EPROM_READ 0x0003 /* Read (reversed) */
67 #define EPROM_WRITE 0x0005 /* Write (reversed) */
68 #define EPROM_ERASE 0x0007 /* Erase (reversed) */
69 #define EPROM_ERAL 0x0009 /* Erase All (reversed) */
70 #define EPROM_WRAL 0x0011 /* Write All (reversed) */
72 #define EPROM_ADR_SZ 7 /* Number of bits in offset address */
73 #define EPROM_OP_SZ 3 /* Number of bits in command */
74 #define SIZE_ADDR_OP (EPROM_ADR_SZ + EPROM_OP_SZ)
75 #define LC46A_MAX_OPS 10 /* Number of bits in Instruction */
76 #define NUM_OF_BITS 8 /* Number of bits in data */
79 /* EEPROM signal bits */
80 #define EPROM_ACTIVE_OUT_BIT 0x0001 /* Out data bit */
81 #define EPROM_ACTIVE_IN_BIT 0x0002 /* In data bit */
82 #define ACTIVE_IN_BIT_SHIFT 0x0001 /* Shift In data bit to LSB */
83 #define EPROM_ENCS 0x0004 /* Set EEPROM CS during operation */
86 /*------------------------------------------------------------------------
87 * The ByteReverse table is used to reverses the 8 bits within a byte
88 *------------------------------------------------------------------------
91 static unsigned char ByteReverse
[256];
92 static int ByteReverseBuilt
= FALSE
;
95 /*------------------------------------------------------------------------
96 * mfg_template - initial serial EEPROM data structure
97 *------------------------------------------------------------------------
100 short mfg_template
[sizeof (FLD_TYPE2
)] =
102 PROM_FORMAT_TYPE2
, /* type; */
103 0x00, 0x1A, /* length[2]; */
104 0x00, 0x00, 0x00, 0x00, /* Crc32[4]; */
105 0x11, 0x76, /* Id[2]; */
106 0x07, 0x05, /* SubId[2] E1; */
107 0x00, 0xA0, 0xD6, 0x00, 0x00, 0x00, /* Serial[6]; */
108 0x00, 0x00, 0x00, 0x00, /* CreateTime[4]; */
109 0x00, 0x00, 0x00, 0x00, /* HeatRunTime[4]; */
110 0x00, 0x00, 0x00, 0x00, /* HeatRunIterations[4]; */
111 0x00, 0x00, 0x00, 0x00, /* HeatRunErrors[4]; */
115 /*------------------------------------------------------------------------
116 * BuildByteReverse - build the 8-bit reverse table
117 *------------------------------------------------------------------------
119 * The 'ByteReverse' table reverses the 8 bits within a byte
120 * (the MSB becomes the LSB etc.).
124 BuildByteReverse (void)
126 long half
; /* Used to build by powers to 2 */
131 for (half
= 1; half
< sizeof (ByteReverse
); half
<<= 1)
132 for (i
= 0; i
< half
; i
++)
133 ByteReverse
[half
+ i
] = (char) (ByteReverse
[i
] | (0x80 / half
));
135 ByteReverseBuilt
= TRUE
;
139 /*------------------------------------------------------------------------
140 * eeprom_delay - small delay for EEPROM timing
141 *------------------------------------------------------------------------
149 for (timeout
= 20; timeout
; --timeout
)
156 /*------------------------------------------------------------------------
157 * eeprom_put_byte - Send a byte to the EEPROM serially
158 *------------------------------------------------------------------------
160 * Given the PCI address and the data, this routine serially sends
161 * the data to the EEPROM.
165 eeprom_put_byte (long addr
, long data
, int count
)
171 output
= (data
& EPROM_ACTIVE_OUT_BIT
) ? 1 : 0; /* Get next data bit */
172 output
|= EPROM_ENCS
; /* Add Chip Select */
176 pci_write_32 ((u_int32_t
*) addr
, output
); /* Output it */
181 /*------------------------------------------------------------------------
182 * eeprom_get_byte - Receive a byte from the EEPROM serially
183 *------------------------------------------------------------------------
185 * Given the PCI address, this routine serially fetches the data
190 eeprom_get_byte (long addr
)
196 /* Start the Reading of DATA
198 ** The first read is a dummy as the data is latched in the
199 ** EPLD and read on the next read access to the EEPROM.
202 input
= pci_read_32 ((u_int32_t
*) addr
);
209 input
= pci_read_32 ((u_int32_t
*) addr
);
211 data
<<= 1; /* Shift data over */
212 data
|= (input
& EPROM_ACTIVE_IN_BIT
) ? 1 : 0;
220 /*------------------------------------------------------------------------
221 * disable_pmc_eeprom - Disable writes to the EEPROM
222 *------------------------------------------------------------------------
224 * Issue the EEPROM command to disable writes.
228 disable_pmc_eeprom (long addr
)
230 eeprom_put_byte (addr
, EPROM_EWDS
, SIZE_ADDR_OP
);
232 pci_write_32 ((u_int32_t
*) addr
, 0); /* this removes Chip Select
237 /*------------------------------------------------------------------------
238 * enable_pmc_eeprom - Enable writes to the EEPROM
239 *------------------------------------------------------------------------
241 * Issue the EEPROM command to enable writes.
245 enable_pmc_eeprom (long addr
)
247 eeprom_put_byte (addr
, EPROM_EWEN
, SIZE_ADDR_OP
);
249 pci_write_32 ((u_int32_t
*) addr
, 0); /* this removes Chip Select
254 /*------------------------------------------------------------------------
255 * pmc_eeprom_read - EEPROM location read
256 *------------------------------------------------------------------------
258 * Given a EEPROM PCI address and location offset, this routine returns
259 * the contents of the specified location to the calling routine.
263 pmc_eeprom_read (long addr
, long mem_offset
)
265 u_int32_t data
; /* Data from chip */
267 if (!ByteReverseBuilt
)
270 mem_offset
= ByteReverse
[0x7F & mem_offset
]; /* Reverse address */
272 * NOTE: The max offset address is 128 or half the reversal table. So the
273 * LSB is always zero and counts as a built in shift of one bit. So even
274 * though we need to shift 3 bits to make room for the command, we only
275 * need to shift twice more because of the built in shift.
277 mem_offset
<<= 2; /* Shift for command */
278 mem_offset
|= EPROM_READ
; /* Add command */
280 eeprom_put_byte (addr
, mem_offset
, SIZE_ADDR_OP
); /* Output chip address */
282 data
= eeprom_get_byte (addr
); /* Read chip data */
284 pci_write_32 ((u_int32_t
*) addr
, 0); /* Remove Chip Select from
287 return (data
& 0x000000FF);
291 /*------------------------------------------------------------------------
292 * pmc_eeprom_write - EEPROM location write
293 *------------------------------------------------------------------------
295 * Given a EEPROM PCI address, location offset and value, this
296 * routine writes the value to the specified location.
298 * Note: it is up to the caller to determine if the write
299 * operation succeeded.
303 pmc_eeprom_write (long addr
, long mem_offset
, u_int32_t data
)
305 volatile u_int32_t temp
;
308 if (!ByteReverseBuilt
)
311 mem_offset
= ByteReverse
[0x7F & mem_offset
]; /* Reverse address */
313 * NOTE: The max offset address is 128 or half the reversal table. So the
314 * LSB is always zero and counts as a built in shift of one bit. So even
315 * though we need to shift 3 bits to make room for the command, we only
316 * need to shift twice more because of the built in shift.
318 mem_offset
<<= 2; /* Shift for command */
319 mem_offset
|= EPROM_WRITE
; /* Add command */
321 eeprom_put_byte (addr
, mem_offset
, SIZE_ADDR_OP
); /* Output chip address */
323 data
= ByteReverse
[0xFF & data
];/* Reverse data */
324 eeprom_put_byte (addr
, data
, NUM_OF_BITS
); /* Output chip data */
326 pci_write_32 ((u_int32_t
*) addr
, 0); /* Remove Chip Select from
330 ** Must see Data In at a low state before completing this transaction.
332 ** Afterwards, the data bit will return to a high state, ~6 ms, terminating
335 pci_write_32 ((u_int32_t
*) addr
, EPROM_ENCS
); /* Re-enable Chip Select */
336 temp
= pci_read_32 ((u_int32_t
*) addr
); /* discard first read */
337 temp
= pci_read_32 ((u_int32_t
*) addr
);
338 if (temp
& EPROM_ACTIVE_IN_BIT
)
340 temp
= pci_read_32 ((u_int32_t
*) addr
);
341 if (temp
& EPROM_ACTIVE_IN_BIT
)
343 pci_write_32 ((u_int32_t
*) addr
, 0); /* Remove Chip Select
351 for (temp
= 0; temp
< 0x10; temp
++)
354 if (pci_read_32 ((u_int32_t
*) addr
) & EPROM_ACTIVE_IN_BIT
)
365 /*------------------------------------------------------------------------
366 * pmcGetBuffValue - read the specified value from buffer
367 *------------------------------------------------------------------------
371 pmcGetBuffValue (char *ptr
, int size
)
376 for (index
= 0; index
< size
; ++index
)
379 value
|= ptr
[index
] & 0xFF;
386 /*------------------------------------------------------------------------
387 * pmcSetBuffValue - save the specified value to buffer
388 *------------------------------------------------------------------------
392 pmcSetBuffValue (char *ptr
, long value
, int size
)
398 ptr
[index
] = (char) (value
& 0xFF);
404 /*------------------------------------------------------------------------
405 * pmc_eeprom_read_buffer - read EEPROM data into specified buffer
406 *------------------------------------------------------------------------
410 pmc_eeprom_read_buffer (long addr
, long mem_offset
, char *dest_ptr
, int size
)
413 *dest_ptr
++ = (char) pmc_eeprom_read (addr
, mem_offset
++);
417 /*------------------------------------------------------------------------
418 * pmc_eeprom_write_buffer - write EEPROM data from specified buffer
419 *------------------------------------------------------------------------
423 pmc_eeprom_write_buffer (long addr
, long mem_offset
, char *dest_ptr
, int size
)
425 enable_pmc_eeprom (addr
);
428 pmc_eeprom_write (addr
, mem_offset
++, *dest_ptr
++);
430 disable_pmc_eeprom (addr
);
434 /*------------------------------------------------------------------------
435 * pmcCalcCrc - calculate the CRC for the serial EEPROM structure
436 *------------------------------------------------------------------------
440 pmcCalcCrc_T01 (void *bufp
)
442 FLD_TYPE2
*buf
= bufp
;
443 u_int32_t crc
; /* CRC of the structure */
445 /* Calc CRC for type and length fields */
447 (u_int8_t
*) &buf
->type
,
448 (u_int32_t
) STRUCT_OFFSET (FLD_TYPE1
, Crc32
),
452 #ifdef EEPROM_TYPE_DEBUG
453 pr_info("sbeCrc: crc 1 calculated as %08x\n", crc
); /* RLD DEBUG */
459 pmcCalcCrc_T02 (void *bufp
)
461 FLD_TYPE2
*buf
= bufp
;
462 u_int32_t crc
; /* CRC of the structure */
464 /* Calc CRC for type and length fields */
466 (u_int8_t
*) &buf
->type
,
467 (u_int32_t
) STRUCT_OFFSET (FLD_TYPE2
, Crc32
),
471 /* Calc CRC for remaining fields */
473 (u_int8_t
*) &buf
->Id
[0],
474 (u_int32_t
) (sizeof (FLD_TYPE2
) - STRUCT_OFFSET (FLD_TYPE2
, Id
)),
478 #ifdef EEPROM_TYPE_DEBUG
479 pr_info("sbeCrc: crc 2 calculated as %08x\n", crc
); /* RLD DEBUG */
485 /*------------------------------------------------------------------------
486 * pmc_init_seeprom - initialize the serial EEPROM structure
487 *------------------------------------------------------------------------
489 * At the front of the serial EEPROM there is a record that contains
490 * manufacturing information. If the info does not already exist, it
491 * is created. The only field modifiable by the operator is the
492 * serial number field.
496 pmc_init_seeprom (u_int32_t addr
, u_int32_t serialNum
)
498 PROMFORMAT buffer
; /* Memory image of structure */
499 u_int32_t crc
; /* CRC of structure */
503 createTime
= get_seconds ();
505 /* use template data */
506 for (i
= 0; i
< sizeof (FLD_TYPE2
); ++i
)
507 buffer
.bytes
[i
] = mfg_template
[i
];
509 /* Update serial number field in buffer */
510 pmcSetBuffValue (&buffer
.fldType2
.Serial
[3], serialNum
, 3);
512 /* Update create time field in buffer */
513 pmcSetBuffValue (&buffer
.fldType2
.CreateTime
[0], createTime
, 4);
515 /* Update CRC field in buffer */
516 crc
= pmcCalcCrc_T02 (&buffer
);
517 pmcSetBuffValue (&buffer
.fldType2
.Crc32
[0], crc
, 4);
520 for (i
= 0; i
< sizeof (FLD_TYPE2
); ++i
)
521 pr_info("[%02X] = %02X\n", i
, buffer
.bytes
[i
] & 0xFF);
524 /* Write structure to serial EEPROM */
525 pmc_eeprom_write_buffer (addr
, EE_MFG
, (char *) &buffer
, sizeof (FLD_TYPE2
));
530 pmc_verify_cksum (void *bufp
)
532 FLD_TYPE1
*buf1
= bufp
;
533 FLD_TYPE2
*buf2
= bufp
;
534 u_int32_t crc1
, crc2
; /* CRC read from EEPROM */
536 /* Retrieve contents of CRC field */
537 crc1
= pmcGetBuffValue (&buf1
->Crc32
[0], sizeof (buf1
->Crc32
));
538 #ifdef EEPROM_TYPE_DEBUG
539 pr_info("EEPROM: chksum 1 reads as %08x\n", crc1
); /* RLD DEBUG */
541 if ((buf1
->type
== PROM_FORMAT_TYPE1
) &&
542 (pmcCalcCrc_T01 ((void *) buf1
) == crc1
))
543 return PROM_FORMAT_TYPE1
; /* checksum type 1 verified */
545 crc2
= pmcGetBuffValue (&buf2
->Crc32
[0], sizeof (buf2
->Crc32
));
546 #ifdef EEPROM_TYPE_DEBUG
547 pr_info("EEPROM: chksum 2 reads as %08x\n", crc2
); /* RLD DEBUG */
549 if ((buf2
->type
== PROM_FORMAT_TYPE2
) &&
550 (pmcCalcCrc_T02 ((void *) buf2
) == crc2
))
551 return PROM_FORMAT_TYPE2
; /* checksum type 2 verified */
553 return PROM_FORMAT_Unk
; /* failed to validate */
557 /*** End-of-File ***/