linux/drivers/staging/cxt1e1/pmc93x6_eeprom.c
<<
>>
Prefs
   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