www.pudn.com > PlxSdk.rar > Eep_8000.c


/*******************************************************************************
 * Copyright (c) 2007 PLX Technology, Inc.
 *
 * PLX Technology Inc. licenses this software under specific terms and
 * conditions.  Use of any of the software or derviatives thereof in any
 * product without a PLX Technology chip is strictly prohibited.
 *
 * PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY,
 * EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  PLX makes no guarantee
 * or representations regarding the use of, or the results of the use of,
 * the software and documentation in terms of correctness, accuracy,
 * reliability, currentness, or otherwise; and you rely on the software,
 * documentation and results solely at your own risk.
 *
 * IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS,
 * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES
 * OF ANY KIND.  IN NO EVENT SHALL PLX'S TOTAL LIABILITY EXCEED THE SUM
 * PAID TO PLX FOR THE PRODUCT LICENSED HEREUNDER.
 *
 ******************************************************************************/

/******************************************************************************
 *
 * File Name:
 *
 *      Eep_8000.c
 *
 * Description:
 *
 *      This file contains 8000-series EEPROM support functions
 *
 * Revision History:
 *
 *      06-01-07 : PLX SDK v5.10
 *
 ******************************************************************************/


#include "Eep_8000.h"




/******************************************************************************
 *
 * Function   :  Plx8000_EepromPresent
 *
 * Description:  Returns the state of the EEPROM as reported by the PLX device
 *
 ******************************************************************************/
RETURN_CODE
Plx8000_EepromPresent(
    DEVICE_EXTENSION  *pdx,
    PLX_EEPROM_STATUS *pStatus
    )
{
    U32 RegValue;


    // Get EEPROM Control/Status
    RegValue =
        PLX_8000_REG_READ(
            pdx,
            0x260
            );

    // Check if an EEPROM is present (bit 16)
    if (RegValue & (1 << 16))
    {
        // Check if there is a CRC error or EEPROM is blank
        if (RegValue & (1 << 17))
        {
            *pStatus = PLX_EEPROM_STATUS_CRC_ERROR;
        }
        else
        {
            *pStatus = PLX_EEPROM_STATUS_VALID;
        }
    }
    else
    {
        *pStatus = PLX_EEPROM_STATUS_NONE;
    }

    return ApiSuccess;
}




/*******************************************************************************
 *
 * Function   :  Plx8000_EepromSetAddressWidth
 *
 * Description:  Sets a new EEPROM address width
 *
 ******************************************************************************/
RETURN_CODE
Plx8000_EepromSetAddressWidth(
    DEVICE_EXTENSION *pdx,
    U8                width
    )
{
    U32 RegValue;


    // Get EEPROM Control/Status
    RegValue =
        PLX_8000_REG_READ(
            pdx,
            0x260
            );

    // Clear command field [15:13] to avoid EEPROM cycle
    RegValue &= ~(7 << 13);

    // Set address width override enable
    RegValue |= (1 << 21);

    // Enable override
    PLX_8000_REG_WRITE(
        pdx,
        0x260,
        RegValue
        );

    // Verify width is overridable
    RegValue =
        PLX_8000_REG_READ(
            pdx,
            0x260
            );

    if ((RegValue & (1 << 21)) == 0)
        return ApiUnsupportedFunction;

    // Set address width [23:22]
    RegValue |= ((width & 0x3) << 22);

    // Set new address width
    PLX_8000_REG_WRITE(
        pdx,
        0x260,
        RegValue
        );

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  Plx8000_EepromCrcGet
 *
 * Description:  Returns the current value of the CRC and its status
 *
 ******************************************************************************/
RETURN_CODE
Plx8000_EepromCrcGet(
    DEVICE_EXTENSION *pdx,
    U32              *pCrc,
    U8               *pCrcStatus
    )
{
    U16 OffsetCrc;
    U32 RegValue;


    // Determine the CRC EEPROM offset
    switch (pdx->PlxChipType)
    {
        case 0x8114:
            if (pdx->PlxRevision >= 0xBA)
                OffsetCrc = 0x3EC;
            else
                OffsetCrc = 0x378;
            break;

        case 0x8508:
        case 0x8512:
        case 0x8517:
        case 0x8518:
            OffsetCrc = 0x78F * sizeof(U32);
            break;

        case 0x8516:
        case 0x8524:
        case 0x8532:
            OffsetCrc = 0xBE4 * sizeof(U32);
            break;

        default:
            return ApiUnsupportedFunction;
    }

    // Read CRC from EEPROM
    Plx8000_EepromReadByOffset(
        pdx,
        OffsetCrc,
        pCrc
        );

    DebugPrintf((
        "CRC = %08x (offset=%02x)\n",
        *pCrc, OffsetCrc
        ));

    // Get EEPROM and CRC status
    RegValue =
        PLX_8000_REG_READ(
            pdx,
            0x260
            );

    // Get EEPROM status bits [17:16]
    RegValue = (RegValue >> 16) & 0x3;

    if (RegValue == 1)
        *pCrcStatus = PLX_CRC_VALID;
    else
        *pCrcStatus = PLX_CRC_INVALID;

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  Plx8000_EepromCrcUpdate
 *
 * Description:  Calculates and updates the CRC value in the EEPROM
 *
 ******************************************************************************/
RETURN_CODE
Plx8000_EepromCrcUpdate(
    DEVICE_EXTENSION *pdx,
    U32              *pCrc,
    BOOLEAN           bUpdateEeprom
    )
{
    U16 offset;
    U16 OffsetCrc;
    U32 Crc;
    U32 EepromValue;


    // Determine the CRC EEPROM offset
    switch (pdx->PlxChipType)
    {
        case 0x8114:
            if (pdx->PlxRevision >= 0xBA)
                OffsetCrc = 0x3EC;
            else
                OffsetCrc = 0x378;
            break;

        case 0x8508:
        case 0x8512:
        case 0x8517:
        case 0x8518:
            OffsetCrc = 0x78F * sizeof(U32);
            break;

        case 0x8516:
        case 0x8524:
        case 0x8532:
            OffsetCrc = 0xBE4 * sizeof(U32);
            break;

        default:
            return ApiUnsupportedFunction;
    }

    // Initialize CRC
    Crc = (U32)-1;

    // Calculate CRC by reading all values in EEPROM
    for (offset=0; offset < OffsetCrc; offset += sizeof(U32))
    {
        // Read next EEPROM value
        Plx8000_EepromReadByOffset(
            pdx,
            offset,
            &EepromValue
            );

        // Update the CRC
        Plx8000_EepromComputeNextCrc(
            &Crc,
            EepromValue
            );
    }

    DebugPrintf((
        "Calculated CRC = 0x%08x\n",
        Crc
        ));

    // Write new value to EEPROM if requested
    if (bUpdateEeprom)
    {
        DebugPrintf(("Writing new CRC to EEPROM...\n"));

        // Update CRC in EEPROM
        Plx8000_EepromWriteByOffset(
            pdx,
            OffsetCrc,
            Crc
            );
    }
    else
    {
        DebugPrintf(("Skipping CRC update in EEPROM\n"));
    }


    // Return the new CRC
    *pCrc = Crc;

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  Plx8000_EepromReadByOffset
 *
 * Description:  Read a 32-bit value from the EEPROM at a specified offset
 *
 ******************************************************************************/
RETURN_CODE
Plx8000_EepromReadByOffset(
    DEVICE_EXTENSION *pdx,
    U16               offset,
    U32              *pValue
    )
{
    U32 RegValue;


    // Verify offset (14 bits max [13:0])
    if (offset >= (1 << 14))
        return ApiInvalidOffset;

    // Wait until EEPROM is ready
    if (Plx8000_EepromWaitIdle(
            pdx
            ) == FALSE)
    {
        return ApiWaitTimeout;
    }

    // Clear return data
    *pValue = 0;

    // Convert offset to an index
    offset = (offset / sizeof(U32));

    // Get EEPROM control register
    RegValue =
        PLX_8000_REG_READ(
            pdx,
            0x260
            );

    // Clear command field [15:13]
    RegValue &= ~(7 << 13);

    // Clear offset field [20,12:0]
    RegValue &= ~((1 << 20) | (0x1FFF << 0));

    // Prepare EEPROM read command
    RegValue |=
        ((offset & 0x1FFF)    <<  0) |     // Bits [12:0] of offset
        (((offset >> 13) & 1) << 20) |     // Bit 13 of offset
        (PLX8000_EE_CMD_READ  << 13);      // EEPROM command

    // Send EEPROM command
    Plx8000_EepromSendCommand(
        pdx,
        RegValue
        );

    // Return EEPROM data
    *pValue =
        PLX_8000_REG_READ(
            pdx,
            0x264
            );

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  Plx8000_EepromWriteByOffset
 *
 * Description:  Write a 32-bit value to the EEPROM at a specified offset
 *
 ******************************************************************************/
RETURN_CODE
Plx8000_EepromWriteByOffset(
    DEVICE_EXTENSION *pdx,
    U16               offset,
    U32               value
    )
{
    U32 RegValue;


    // Verify offset (14 bits max [13:0])
    if (offset >= (1 << 14))
        return ApiInvalidOffset;

    // Wait until EEPROM is ready
    if (Plx8000_EepromWaitIdle(
            pdx
            ) == FALSE)
    {
        return ApiWaitTimeout;
    }

    // Convert offset to an index
    offset = (offset / sizeof(U32));

    // Get EEPROM control register
    RegValue =
        PLX_8000_REG_READ(
            pdx,
            0x260
            );

    // Clear command field [15:13]
    RegValue &= ~(7 << 13);

    // Clear offset field [20,12:0]
    RegValue &= ~((1 << 20) | (0x1FFF << 0));

    // Send EEPROM write enable command
    Plx8000_EepromSendCommand(
        pdx,
        RegValue | (PLX8000_EE_CMD_WRITE_ENABLE << 13)
        );

    // Prepare EEPROM data
    PLX_8000_REG_WRITE(
        pdx,
        0x264,
        value
        );

    // Prepare EEPROM write command
    RegValue |=
        ((offset & 0x1FFF)    <<  0) |     // Bits [12:0] of offset
        (((offset >> 13) & 1) << 20) |     // Bit 13 of offset
        (PLX8000_EE_CMD_WRITE << 13);      // EEPROM command

    // Send EEPROM write command
    Plx8000_EepromSendCommand(
        pdx,
        RegValue
        );

    return ApiSuccess;
}




/******************************************************************************
 *
 * Function   :  Plx8000_EepromWaitIdle
 *
 * Description:  Wait until the EEPROM access is idle
 *
 ******************************************************************************/
BOOLEAN
Plx8000_EepromWaitIdle(
    DEVICE_EXTENSION *pdx
    )
{
    U32 Timeout;
    U32 RegValue;
    U32 RegCmd;


    // Set timeout
    Timeout = 10000;

    // Get EEPROM control register
    RegCmd =
        PLX_8000_REG_READ(
            pdx,
            0x260
            );
	
    // Clear command field [15:13]
    RegCmd &= ~(7 << 13);

    // Clear the EepRdy bit [24]
    RegCmd &= ~(1 << 24);

    // Clear the EepWrStatus bits[30:28]
    RegCmd &= ~(7 << 28);
	
    // Prepare EEPROM write command
    RegCmd |= (PLX8000_EE_CMD_READ_STATUS << 13);

    // Query EEPROM status until it's ready
    do
    {
        // Send command to get EEPROM status in bits [31:24]
        Plx8000_EepromSendCommand(
            pdx,
            RegCmd
            );

        // Get EEPROM control register
        RegValue =
            PLX_8000_REG_READ(
                pdx,
                0x260
                );

        // Check EEPROM read (bit 24) & write ([30:28]) status bits
        if ( ((RegValue & (1 << 24)) == 0) &&
             ((RegValue & (7 << 28)) == 0))
        {
            return TRUE;
        }

        // Decrement timeout
        Timeout--;
    }
    while (Timeout);

    return FALSE;
}




/******************************************************************************
 *
 * Function   :  Plx8000_EepromSendCommand
 *
 * Description:  Send a command to the EEPROM and wait until it has completed
 *
 ******************************************************************************/
BOOLEAN
Plx8000_EepromSendCommand(
    DEVICE_EXTENSION *pdx,
    U32               command
    )
{
    U32 Timeout;
    U32 RegValue;


    // Send EEPROM command
    PLX_8000_REG_WRITE(
        pdx,
        0x260,
        command
        );

    // Setup timeout counter
    Timeout = 100000;

    // Wait for command to complete
    do
    {
        // Get EEPROM control register
        RegValue =
            PLX_8000_REG_READ(
                pdx,
                0x260
                );

        // EEPROM command is complete if status [19:18] is 0 or 2 (with CRC error)
        if ((RegValue & (1 << 18)) == 0)
            return TRUE;

        // Decrement timeout
        Timeout--;
    }
    while (Timeout);

    return FALSE;
}




/******************************************************************************
 *
 * Function   :  Plx8000_EepromComputeNextCrc
 *
 * Description:  Updates the CRC based on the next EEPROM value
 *
 ******************************************************************************/
VOID
Plx8000_EepromComputeNextCrc(
    U32 *pCrc,
    U32  NextEepromValue
    )
{
    U16 i;
    U32 XorValue;


    // Step through each bit of the CRC
    for( i=0; i<32; ++i )
    {
        // Shift the CRC, XOR'ing in the constant as required
        XorValue = ((*pCrc ^ (NextEepromValue << i)) & (1 << 31));

        if (XorValue)
            XorValue = CONST_CRC_XOR_VALUE;
        else
            XorValue = 0;

        // XOR to update the CRC
        *pCrc = (*pCrc << 1) ^ XorValue;
    }
}