/*
Copyright (C) 2008, 2009  GE Intelligent Platforms, Inc
 
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

#include <common.h>
#include <command.h>
#include <asm/au1x00.h>
#include <asm/mipsregs.h>
#include "octeon_boot.h"
#include <pci.h>
#include <lib_octeon_shared.h>
#include <lib_octeon.h>
#include <net.h>

#include "rhOsif.h"
#include "rhRegif.h"
#include "rhAsicReg.h"
#include "rhAsicLib.h"

#include "prestReg.h"
#include "eagleReg.h"
#include "npaEagle.h"

#if defined(CONFIG_PCI)
extern void init_octeon_pci (void);
extern int npaPresteraInit (void);
extern int npaPresteraVlanCfg (void);

void pci_init_board (void)
{
	init_octeon_pci();
}
#endif

extern int eeprom_diags(void);
extern void uboot_version_num_store(void);
extern int npaPresteraConfigPort (int, int);
extern int npaEagleInit (void);
extern int npaEgEnablePort( struct npaEagleObj_t *, int );

extern struct eth_device *eth_devices;
extern struct npaEagleObj_t gEagleObj;

extern void rhReset (reginfo_t *);
extern int configMACAfterAutoneg ( struct npaEagleObj_t *, int );
extern int npaEgAsicAutoNegCompleteFiberStatus ( struct npaEagleObj_t *, int );

int checkboard (void)
{
    DECLARE_GLOBAL_DATA_PTR;

#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
    /* Enable MDIO */
    cvmx_write_csr(CVMX_SMI_EN, 1);
#endif
    if (octeon_show_info() && octeon_ebt3000_get_board_major_rev() != 1)
    {

        int pal_rev_maj = 0;
        int pal_rev_min = 0;
        int voltage_100ths = 0;
        int voltage_1s = 0;
        int mcu_rev_maj = 0;
        int mcu_rev_min = 0;

        if (octeon_read64_byte(OCTEON_PAL_BASE_ADDR)==0xa5 && octeon_read64_byte(OCTEON_PAL_BASE_ADDR+1)==0x5a)
        {
            pal_rev_maj = octeon_read64_byte(OCTEON_PAL_BASE_ADDR+2);
            pal_rev_min = octeon_read64_byte(OCTEON_PAL_BASE_ADDR+3);
            if ((octeon_read64_byte(OCTEON_PAL_BASE_ADDR+4))>0xf)
            {
                voltage_1s = 0;
                voltage_100ths = (600+(31-octeon_read64_byte(OCTEON_PAL_BASE_ADDR+4))*25);
            }
            else
            {
                voltage_1s = 1;
                voltage_100ths = ((15-octeon_read64_byte(OCTEON_PAL_BASE_ADDR+4))*5);
            }
        }

        if (twsii_mcu_read(0x00)==0xa5 && twsii_mcu_read(0x01)==0x5a)
        {
            gd->mcu_rev_maj = mcu_rev_maj = twsii_mcu_read(2);
            gd->mcu_rev_min = mcu_rev_min = twsii_mcu_read(3);
        }

        printf("PAL rev: %d.%02d, MCU rev: %d.%02d, CPU voltage: %d.%02d\n",
               pal_rev_maj, pal_rev_min, mcu_rev_maj, mcu_rev_min, voltage_1s, voltage_100ths);

    }

    if (octeon_show_info())
    {
        /* Display CPU speed on display */

        if (octeon_ebt3000_get_board_major_rev() != 1)
        {
            if ((octeon_read64_byte(OCTEON_PAL_BASE_ADDR+4))>0xf)
            {
                char tmp[10];
                sprintf(tmp,"%d 0.%.2d ",gd->cpu_clock_mhz,(600+(31-octeon_read64_byte(OCTEON_PAL_BASE_ADDR+4))*25)/10);
                octeon_led_str_write(tmp);
            }
            else
            {
                char tmp[10];
                sprintf(tmp,"%d 1.%.2d ",gd->cpu_clock_mhz,(15-octeon_read64_byte(OCTEON_PAL_BASE_ADDR+4))*5);
                octeon_led_str_write(tmp);
            }
        }
        else
        {
            char tmp[10];
            sprintf(tmp, "%dMHz    ", gd->cpu_clock_mhz);
            octeon_led_str_write(tmp);
        }
    }
    else
    {
        octeon_led_str_write("Boot    ");
    }
    return 0;
}



int early_board_init(void)
{
    int cpu_ref;

    DECLARE_GLOBAL_DATA_PTR;

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_EARLY_BOARD_INIT);
#endif

    memset((void *)&(gd->mac_desc), 0x0, sizeof(octeon_eeprom_mac_addr_t));
    memset((void *)&(gd->clock_desc), 0x0, sizeof(octeon_eeprom_clock_desc_t));
    memset((void *)&(gd->board_desc), 0x0, sizeof(octeon_eeprom_board_desc_t));

    /* NOTE: this is early in the init process, so the serial port is not yet configured */

    /* Populate global data from eeprom */
    uint8_t ee_buf[OCTEON_EEPROM_MAX_TUPLE_LENGTH];
    int addr;

    addr = octeon_tlv_get_tuple_addr(CFG_DEF_EEPROM_ADDR, EEPROM_CLOCK_DESC_TYPE, 0, ee_buf, OCTEON_EEPROM_MAX_TUPLE_LENGTH);
    if (addr >= 0)
    {
        memcpy((void *)&(gd->clock_desc), ee_buf, sizeof(octeon_eeprom_clock_desc_t));
    }

    /* Determine board type/rev */
    strncpy((char *)(gd->board_desc.serial_str), "unknown", SERIAL_LEN);
    addr = octeon_tlv_get_tuple_addr(CFG_DEF_EEPROM_ADDR, EEPROM_BOARD_DESC_TYPE, 0, ee_buf, OCTEON_EEPROM_MAX_TUPLE_LENGTH);
    if (addr >= 0)
    {
        memcpy((void *)&(gd->board_desc), ee_buf, sizeof(octeon_eeprom_board_desc_t));
    }
    else
    {
        gd->flags |= GD_FLG_BOARD_DESC_MISSING;
        gd->board_desc.rev_minor = 0;
        gd->board_desc.board_type = CVMX_BOARD_TYPE_AT5810;

#ifdef OBSOLETE
        /* Try to determine board rev by looking at PAL */
        if (octeon_ebt3000_rev1())
        {
            gd->board_desc.rev_major = 1;
        }
        else
        {
            gd->board_desc.rev_major = 2;
        }
#endif

        gd->board_desc.rev_major = 1;
    }

    cpu_ref = 50;
    gd->ddr_clock_mhz = 333; /* 333 must multiply by 2 for 667 MHz (was 266 multiplied by 2 for 533 MHz) */

    addr = octeon_tlv_get_tuple_addr(CFG_DEF_EEPROM_ADDR, EEPROM_MAC_ADDR_TYPE, 0, ee_buf, OCTEON_EEPROM_MAX_TUPLE_LENGTH);
    if (addr >= 0)
    {
        memcpy((void *)&(gd->mac_desc), ee_buf, sizeof(octeon_eeprom_mac_addr_t));
    }
    else
    {
        /* Make up some MAC addresses */
        gd->mac_desc.count = 2;
        gd->mac_desc.mac_addr_base[0] = 0x00;
        if (cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000)
        {
            /* cavium B */
            gd->mac_desc.mac_addr_base[1] = 0xDE;
            gd->mac_desc.mac_addr_base[2] = 0xAD;
        }
        else
        {
            /* cavium A */
            gd->mac_desc.mac_addr_base[1] = 0xBE;
            gd->mac_desc.mac_addr_base[2] = 0xEF;
        }
        gd->mac_desc.mac_addr_base[3] = (gd->board_desc.rev_major<<4) | gd->board_desc.rev_minor;
        gd->mac_desc.mac_addr_base[4] = gd->board_desc.serial_str[0];
        gd->mac_desc.mac_addr_base[5] = 0x00;
    }

    /* Read CPU clock multiplier */
    uint64_t data = cvmx_read_csr((uint64_t)0x80011F00000001E8ull);
    data = data >> 18;
    data &= 0x1f;

    gd->cpu_clock_mhz = data * cpu_ref;

    /* adjust for 33.33 Mhz clock */
    if (cpu_ref == 33)
        gd->cpu_clock_mhz += (data)/4 + data/8;

    if (gd->cpu_clock_mhz < 100 || gd->cpu_clock_mhz > 1100)
    {
        gd->cpu_clock_mhz = DEFAULT_ECLK_FREQ_MHZ;
    }

    /* Take everything out of reset */
    *BOARD_RESET_REG = 0x003D;
    /* Enable the SFPs */
    *BOARD_FP_SFP_CONTROL_STATUS_REG = 0x0808;

    return 0;
}
void octeon_led_str_write(const char *str)
{
    octeon_led_str_write_std(str);
}

#define MAX_NUM_SFP                                     4

#define ID                                              0
#define EXT_ID                                          1
#define CONNECTOR                                       2
#define TRANSCEIVER_3                                   3
#define TRANSCEIVER_4                                   4
#define TRANSCEIVER_5                                   5
#define TRANSCEIVER_6                                   6
#define TRANSCEIVER_7                                   7
#define TRANSCEIVER_8                                   8
#define TRANSCEIVER_9                                   9
#define TRANSCEIVER_10                                  10
#define FIBER_9_125MM_UNITS_KM                          14
#define FIBER_9_125MM_UNITS_100M                        15
#define FIBER_50_125MM_UNITS_10M                        16
#define FIBER_62P5_125MM_UNITS_10M                      17
#define COPPER_UNITS_M                                  18

#define SFP_VS_BASE                                     0x600

#define CONTROL_REG                                     0
#define STATUS_REG                                      1
#define AUTONEG_ADVERTISEMENT                           4
#define CONTROL_REG_1000BASE_T                          9
#define EXTENDED_PHY_SPECIFIC_CONTROL_REG               20
#define EXTENDED_ADDRESS_REG                            22
#define LED_CONTROL_REG                                 24
#define EXTENDED_PHY_SPECIFIC_CONTROL_2_REG             26
#define EXTENDED_PHY_SPECIFIC_STATUS_REG                27

extern int octeon_twsi_write8_addr16(uint8_t dev_addr, uint16_t addr, uint8_t data);
extern int miiphy_write(unsigned char, unsigned char, unsigned short);
extern int miiphy_read(unsigned char, unsigned char, unsigned short *);

unsigned char connector_type[MAX_NUM_SFP] = {SFP_VACANT, SFP_VACANT, SFP_VACANT, SFP_VACANT};

void phyRegWrite (int interface, int reg, int mask, int newVal, int wait)
{
    unsigned short data;

    miiphy_read (interface, reg, &data);
    data = (data & mask) | newVal;
    miiphy_write (interface, reg, data);
    if (wait)
    {
        do
        {
            miiphy_read (interface, reg, &data);
        }
        while ((data & 0x8000) != 0) ; /* wait till finished */
    }
}

void phyRegRead (int interface, int reg, unsigned short *val)
{
    miiphy_read (interface, reg, val);
}

void sfpVSRegWrite (int dev, int reg, int mask, int newVal, int reset_wait)
{
    int data;

    data = octeon_twsi_read8(dev, SFP_VS_BASE + reg);
    data = octeon_twsi_read8(dev, SFP_VS_BASE + reg) | (data << 8);
    data = (data & mask) | newVal;
    if (reset_wait)
    {
        octeon_twsi_write8 (dev, SFP_VS_BASE + reg, (data & 0x7FFF) >> 8);
        octeon_twsi_write8 (dev, SFP_VS_BASE + reg, data & 0x00FF);
        octeon_twsi_write8 (dev, SFP_VS_BASE + reg, data >> 8);
        octeon_twsi_write8 (dev, SFP_VS_BASE + reg, data & 0x00FF);
        do
        {
            data = octeon_twsi_read8(dev, SFP_VS_BASE + reg);
            data = octeon_twsi_read8(dev, SFP_VS_BASE + reg) | (data << 8);
        }
        while ((data & 0x8000) != 0);
	}
	else
    {
        octeon_twsi_write8 (dev, SFP_VS_BASE + reg, data >> 8);
        octeon_twsi_write8 (dev, SFP_VS_BASE + reg, data & 0x00FF);
	}
}

void sfpVSRegRead (int dev, int reg, int *val)
{
    int data;

    data = octeon_twsi_read8(dev, SFP_VS_BASE + reg);
    data = octeon_twsi_read8(dev, SFP_VS_BASE + reg) | ((data) << 8);
    *val = data;
}

extern struct npaEagleObj_t gEagleObj;

void sfpInit (int interface, int display_output)
{
    switch (interface)
    {
        case PRES_FP_CP_0:
        case PRES_FP_CP_1:
            if (((*BOARD_MASTER_CONTROL_REG & SFP_OWNED_MASK) == SFP_OCT_A_OWNED) &&
                 ((cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000) != 0))
            {
                /* we're Octeon B but Octeon A owns the RTM so just return */
                return;
			}
            if (((*BOARD_MASTER_CONTROL_REG & SFP_OWNED_MASK) == SFP_OCT_B_OWNED) &&
                 ((cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000) == 0))
            {
                /* we're Octeon A but Octeon B owns the RTM so just return */
                return;
			}
            connector_type[interface] = octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, CONNECTOR);
            break;
        case PRES_RTM_CP_0:
        case PRES_RTM_CP_1:
            if (((*BOARD_MASTER_CONTROL_REG & RTM_OWNED_MASK) == RTM_OCT_A_OWNED) &&
                 ((cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000) != 0))
            {
                /* we're Octeon B but Octeon A owns the RTM so just return */
                return;
			}
            if (((*BOARD_MASTER_CONTROL_REG & RTM_OWNED_MASK) == RTM_OCT_B_OWNED) &&
                 ((cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000) == 0))
            {
                /* we're Octeon A but Octeon B owns the RTM so just return */
                return;
			}
            if (*BOARD_RTM_GE_CARDID != GE_RTM_CARDID)
            {
                /* not a GE RTM so just return */
                return;
            }
            if (interface == PRES_RTM_CP_0)
            {
                connector_type[interface] = gEagleObj.sfpType[EAGLE_DATA_PORTS + 0];
            }
            else
            {
                connector_type[interface] = gEagleObj.sfpType[EAGLE_DATA_PORTS + 1];
            }
            break;
        default:
            printf("sfpInit(): Error - Unsupported SFP Interface!\n");
            return;
            break;
    }
    if (connector_type[interface] == SFP_VACANT)
    {
        if (display_output)
        {
            printf ("V ");
        }
    }
    else if (connector_type[interface] == SFP_COPPER)
    {
        if (display_output)
        {
            printf ("C ");
        }
        if ((interface == PRES_FP_CP_0) || (interface == PRES_FP_CP_1))
        {
            /* command SFPs/M88E1111 into SGMII mode */
            sfpVSRegWrite (BOARD_SFP0_TWSI_ADDR + interface, EXTENDED_PHY_SPECIFIC_STATUS_REG, 0x0000, 0x9084, 0);
            /* command SFPs/M88E1111 to advertise 1000BASE-T Full/Half-Duplex */
            sfpVSRegWrite (BOARD_SFP0_TWSI_ADDR + interface, CONTROL_REG_1000BASE_T, 0x0000, 0x0F00, 0);
            /* command SFPs/M88E1111 to advertise 100/10BASE-T Full/Half-Duplex */
            sfpVSRegWrite (BOARD_SFP0_TWSI_ADDR + interface, AUTONEG_ADVERTISEMENT, 0x0000, 0x0DE1, 0);
            /* command SFPs into reset */
            sfpVSRegWrite (BOARD_SFP0_TWSI_ADDR + interface, CONTROL_REG, 0x0000, 0x9140, 1);
            /* command SFPs/M88E1111 to advertise 100/10BASE-T Full/Half-Duplex */
            sfpVSRegWrite (BOARD_SFP0_TWSI_ADDR + interface, AUTONEG_ADVERTISEMENT, 0x0000, 0x0DE1, 0);
        }
        else if ((interface == PRES_RTM_CP_0) || (interface == PRES_RTM_CP_1))
        {
            /* command SFPs/M88E1111 into SGMII mode */
            npaEgSfpVsRegWrite( &gEagleObj, EAGLE_DATA_PORTS + (interface - PRES_RTM_CP_0),
                                                               EXTENDED_PHY_SPECIFIC_STATUS_REG, 0x0000, 0x9084 );
            /* command SFPs/M88E1111 to advertise 1000BASE-T Full/Half-Duplex */
            npaEgSfpVsRegWrite( &gEagleObj, EAGLE_DATA_PORTS + (interface - PRES_RTM_CP_0),
                                                                         CONTROL_REG_1000BASE_T, 0x0000, 0x0F00 );
            /* command SFPs/M88E1111 to advertise 100/10BASE-T Full/Half-Duplex */
            npaEgSfpVsRegWrite( &gEagleObj, EAGLE_DATA_PORTS + (interface - PRES_RTM_CP_0),
                                                                          AUTONEG_ADVERTISEMENT, 0x0000, 0x0DE1 );
            /* command SFPs into reset */
            npaEgSfpVsRegWrite( &gEagleObj, EAGLE_DATA_PORTS + (interface - PRES_RTM_CP_0),
                                                                                    CONTROL_REG, 0x0000, 0x9140 );
            /* command SFPs/M88E1111 to advertise 100/10BASE-T Full/Half-Duplex */
            npaEgSfpVsRegWrite( &gEagleObj, EAGLE_DATA_PORTS + (interface - PRES_RTM_CP_0),
                                                                          AUTONEG_ADVERTISEMENT, 0x0000, 0x0DE1 );
        }
        /* configure the Prestera */
        npaPresteraConfigPort (interface, PRESTERA_SGMII);
    }
    else
    {
        if (display_output)
        {
            printf ("F ");
        }
        /* configure the Prestera */
        npaPresteraConfigPort (interface, PRESTERA_SERDES);
    }
}

void phyLinkSetup(int display_output)
{
    /* initialize SFPs */
    if (display_output)
    {
        printf ("CP SFP Type: ");
    }
    sfpInit (PRES_FP_CP_0, display_output);  /* Front Panel SFP Control Port 0 */
    sfpInit (PRES_FP_CP_1, display_output);  /* Front Panel SFP Control Port 1 */
    sfpInit (PRES_RTM_CP_0, display_output); /* RTM SFP Control Port 0 */
    sfpInit (PRES_RTM_CP_1, display_output); /* RTM SFP Control Port 1 */
    if (display_output)
    {
        printf ("\n");
    }
    npaPresteraConfigPort (PRES_BI_CP_0, PRESTERA_SGMII);  /* Base Interface Control Port 0 */
    npaPresteraConfigPort (PRES_BI_CP_1, PRESTERA_SGMII);  /* Base Interface Control Port 1 */
    npaPresteraConfigPort (PRES_OB_CP_0, PRESTERA_SERDES); /* Octeon B 82546 Control Port 0 */
    npaPresteraConfigPort (PRES_OB_CP_1, PRESTERA_SERDES); /* Octeon B 82546 Control Port 1 */
    npaPresteraConfigPort (PRES_OA_CP_0, PRESTERA_SERDES); /* Octeon A 82546 Control Port 0 */
    npaPresteraConfigPort (PRES_OA_CP_1, PRESTERA_SERDES); /* Octeon A 82546 Control Port 1 */
}

int prInit (void)
{
    int retCode;

    retCode = npaPresteraInit();
    if (retCode == 0)
    {
        npaPresteraVlanCfg();
    }
    return (retCode);
}

int rhInit (void)
{
    unsigned int memoryBase = (unsigned int)BOARD_REDHAWK_BASE_REG;
    char *s;

    /* Reset the Redhawk */
    rhReset(redHawkRegs);

    /* Setup RedHawk Register Database */
    if (regdbInit(redHawkRegs, memoryBase) == ERROR)
    {
        return -1;
    }

#ifdef NOTNOW
    /* Run diagnostic tests - Register default test */
    if (rhAsicTestDefault() == ERROR)
    {
        printf("FAIL !!! RedHawk register default test\n");
    }
    else
    {
        printf("RedHawk default register test: PASS\n");
    }
#endif

    if ((s = getenv("xaui0")) != NULL)
    {
        if (strcmp(s, "yes") == 0)
        {
           /* XAUI0 - SPI */
           rhAsicXauiSpiConfig (0);
        }
    }
    if ((s = getenv("xaui1")) != NULL)
    {
        if (strcmp(s, "yes") == 0)
        {
           /* XAUI1 - SPI */
           rhAsicXauiSpiConfig (1);
        }
    }
    return (0);
}

int dpSfpEagleAutonegCompleteCheck(void)
{
    int portNum, retry;
    uint32_t intrRegVal;

    /* process for all the ports in data path */
    for (portNum = 0; portNum < EAGLE_DATA_PORTS; portNum++)
    {
        retry = 0;
        do
        {
            npaEgRegGet(&gEagleObj, AD_StsMdioRxInterrupt + (portNum * 0x200), 0, &intrRegVal);
            if (intrRegVal & (1 << 8))
            {
                if (gEagleObj.sfpType[portNum] == SFP_COPPER)
                {
                    configMACAfterAutoneg (&gEagleObj, portNum);
                }
                else if (gEagleObj.sfpType[portNum] == SFP_FIBER)
                {
                    npaEgAsicAutoNegCompleteFiberStatus(&gEagleObj, portNum);
                }
                break;
            }
        }
        while (++retry < EAGLE_LINK_RETRY_LIMIT);
    }
    return (0);
}

int egInit (int mode_type)
{
    int portNum;

    if (npaEagleInit() != 0)
    {
        return (1);
	}
    for (portNum = 0; portNum < EAGLE_DATA_PORTS; portNum++)
    {
        npaEgEnablePort(&gEagleObj, portNum);
    }
    return (0);
}

#define  CVMX_STXX_STAT_BYTES_HI(block_id)                   (CVMX_ADD_IO_SEG(0x0001180090000648ull+((block_id)*0x8000000ull)))
#define  CVMX_STXX_STAT_BYTES_LO(block_id)                   (CVMX_ADD_IO_SEG(0x0001180090000680ull+((block_id)*0x8000000ull)))
#define  CVMX_STXX_STAT_PKT_XMT(block_id)                    (CVMX_ADD_IO_SEG(0x0001180090000640ull+((block_id)*0x8000000ull)))
#define  CVMX_STXX_INT_REG(block_id)                         (CVMX_ADD_IO_SEG(0x0001180090000698ull+((block_id)*0x8000000ull)))

uint32_t ptFirstEaglePtiMACTime = 1;
/* MAC rx stats */
uint32_t fMACRxOK[EAGLE_DATA_PORTS];
uint32_t fMACRxBcast[EAGLE_DATA_PORTS];
uint32_t fMACRxMcast[EAGLE_DATA_PORTS];
uint32_t fMACRxCRCE[EAGLE_DATA_PORTS];
uint32_t fMACRxTLong[EAGLE_DATA_PORTS];
uint32_t fMACRxBad[EAGLE_DATA_PORTS];
uint32_t oMACRxOKMSB[EAGLE_DATA_PORTS];
uint32_t oMACRxOKLSB[EAGLE_DATA_PORTS];
/* MAC tx stats */
uint32_t fMACTxOK[EAGLE_DATA_PORTS];
uint32_t fMACTxBcast[EAGLE_DATA_PORTS];
uint32_t fMACTxMcast[EAGLE_DATA_PORTS];
uint32_t fMACTxError[EAGLE_DATA_PORTS];
uint32_t fMACTxTLong[EAGLE_DATA_PORTS];
uint32_t fMACTxFDrop[EAGLE_DATA_PORTS];
uint32_t oMACTxOKMSB[EAGLE_DATA_PORTS];
uint32_t oMACTxOKLSB[EAGLE_DATA_PORTS];
/* SPI/Eagle rx stats */
uint32_t SPIERSOP = 0;
uint32_t SPIEREOP1 = 0;
uint32_t SPIEREOP2 = 0;
uint32_t SPIEREOPA = 0;
uint32_t SPIERTrain = 0;
uint32_t SPIEROFU = 0;
uint32_t SPIERLOS = 0;
uint32_t SPIERCal = 0;
uint32_t SPIERAUPE = 0;
uint32_t SPIERBFU = 0;
uint32_t SPIERAUSOP = 0;
uint32_t SPIERD2ERR = 0;
/* SPI/Eagle tx stats */
uint32_t SPIETSOP = 0;
uint32_t SPIETEOP = 0;
uint32_t SPIETDPVEOP = 0;
uint32_t SPIETDPGEOP = 0;
uint32_t SPIETTrain = 0;
uint32_t SPIETFIFOO = 0;
uint32_t SPIETEAEOP = 0;
uint32_t SPIETIAEOP = 0;
uint32_t SPIETDIP4 = 0;
uint32_t SPIETPVIOL = 0;

uint32_t ptgetreg(int portNum, int reg)
{
    uint32_t regVal;

    npaEgRegGet( &gEagleObj, reg, 0, &regVal );
    return(regVal);
}

void ptcleareagleptiMACstats(int portNum)
{
    /* MAC rx stats */
    fMACRxOK[portNum] = 0;
    fMACRxBcast[portNum] = 0;
    fMACRxMcast[portNum] = 0;
    fMACRxCRCE[portNum] = 0;
    fMACRxTLong[portNum] = 0;
    fMACRxBad[portNum] = 0;
    oMACRxOKMSB[portNum] = 0;
    oMACRxOKLSB[portNum] = 0;
    /* MAC tx stats */
    fMACTxOK[portNum] = 0;
    fMACTxBcast[portNum] = 0;
    fMACTxMcast[portNum] = 0;
    fMACTxError[portNum] = 0;
    fMACTxTLong[portNum] = 0;
    fMACTxFDrop[portNum] = 0;
    oMACTxOKMSB[portNum] = 0;
    oMACTxOKLSB[portNum] = 0;
}

void ptdumpeagleptiMACinfo(int portNum)
{
    int i;

    if (ptFirstEaglePtiMACTime)
    {
        for (i = 0; i < EAGLE_DATA_PORTS; i++)
        {
            ptcleareagleptiMACstats(i);
        }
        ptFirstEaglePtiMACTime = 0;
    }
    /* collect MAC rx stats */
    fMACRxOK[portNum] += ptgetreg(portNum, AD_StsRxMacFRcvdOK + (portNum * 0x200));
    fMACRxBcast[portNum] += ptgetreg(portNum, AD_StsRxMacNumOfBcastFrms + (portNum * 0x200));
    fMACRxMcast[portNum] += ptgetreg(portNum, AD_StsRxMacNumOfMcastFrms + (portNum * 0x200));
    fMACRxCRCE[portNum] += ptgetreg(portNum, AD_StsRxMacNumOfCRCErrors + (portNum * 0x200));
    fMACRxTLong[portNum] += ptgetreg(portNum, AD_StsRxMacNumOfLongErrors + (portNum * 0x200));
    fMACRxBad[portNum] += ptgetreg(portNum, AD_StsRxMacNumOfBadFrms + (portNum * 0x200));
    oMACRxOKMSB[portNum] += ptgetreg(portNum, AD_StsRxMacOctetsRcvdOKMSB + (portNum * 0x200));
    oMACRxOKLSB[portNum] += ptgetreg(portNum, AD_StsRxMacOctetsRcvdOKLSB + (portNum * 0x200));
    /* collect MAC tx stats */
    fMACTxOK[portNum] += ptgetreg(portNum, AD_StsTxMacGoodFrames + (portNum * 0x200));
    fMACTxBcast[portNum] += ptgetreg(portNum, AD_StsTxMacBCASTFrames + (portNum * 0x200));
    fMACTxMcast[portNum] += ptgetreg(portNum, AD_StsTxMacMCASTFrames + (portNum * 0x200));
    fMACTxError[portNum] += ptgetreg(portNum, AD_StsTxMacErroredFrames + (portNum * 0x200));
    fMACTxTLong[portNum] += ptgetreg(portNum, AD_StsTxMacTooLongFrames + (portNum * 0x200));
    fMACTxFDrop[portNum] += ptgetreg(portNum, AD_StsTxMacFilterDropFrames + (portNum * 0x200));
    oMACTxOKMSB[portNum] += ptgetreg(portNum, AD_StsTxMacGoodByteCountMSB + (portNum * 0x200));
    oMACTxOKLSB[portNum] += ptgetreg(portNum, AD_StsTxMacGoodByteCountLSB + (portNum * 0x200));
    /* display MAC rx stats */
    printf("  fMACRxOK   : 0x%08x", fMACRxOK[portNum]);
    printf("  fMACRxBcast: 0x%08x", fMACRxBcast[portNum]);
    printf("  fMACRxMcast: 0x%08x", fMACRxMcast[portNum]);
    printf("  fMACRxCRCE : 0x%08x", fMACRxCRCE[portNum]);
    printf("\n");
    /* display MAC rx stats */
    printf("  fMACRxTLong: 0x%08x", fMACRxTLong[portNum]);
    printf("  fMACRxBad  : 0x%08x", fMACRxBad[portNum]);
    printf("  oMACRxOKMSB: 0x%08x", oMACRxOKMSB[portNum]);
    printf("  oMACRxOKLSB: 0x%08x", oMACRxOKLSB[portNum]);
    printf("\n");
    /* display MAC tx stats */
    printf("  fMACTxOK   : 0x%08x", fMACTxOK[portNum]);
    printf("  fMACTxBcast: 0x%08x", fMACTxBcast[portNum]);
    printf("  fMACTxMcast: 0x%08x", fMACTxMcast[portNum]);
    printf("  fMACTxError: 0x%08x", fMACTxError[portNum]);
    printf("\n");
    /* display MAC tx stats */
    printf("  fMACTxTLong: 0x%08x", fMACTxTLong[portNum]);
    printf("  fMACTxFDrop: 0x%08x", fMACTxFDrop[portNum]);
    printf("  oMACTxOKMSB: 0x%08x", oMACTxOKMSB[portNum]);
    printf("  oMACTxOKLSB: 0x%08x", oMACTxOKLSB[portNum]);
    printf("\n");
}

void ptdumpeagleptiSPIinfo(void)
{
    /* SPI/Eagle rx stats */
    SPIERSOP += ptgetreg(0, AD_StsRxSpiSopCount);
    SPIEREOP1 += ptgetreg(0, AD_StsRxSpiEop1Count);
    SPIEREOP2 += ptgetreg(0, AD_StsRxSpiEop2Count);
    SPIEREOPA += ptgetreg(0, AD_StsRxSpiEopACount);
    SPIERTrain += ptgetreg(0, AD_StsRxSpiTrainingCount);
    SPIEROFU += ptgetreg(0, AD_StsRxSpiOutputFifoUFlow);
    SPIERLOS += ptgetreg(0, AD_StsRxSpiLosStatus);
    SPIERCal += ptgetreg(0, AD_StsRxSpiShdwCalendarAct);
    SPIERAUPE += ptgetreg(0, AD_StsRxSpiAmpleUsePipeEmpty);
    SPIERBFU += ptgetreg(0, AD_StsRxSpiBurstFifoUFlow);
    SPIERAUSOP += ptgetreg(0, AD_StsRxSpiAmpleUseSopCnt);
    SPIERD2ERR += ptgetreg(0, AD_StsRxSpiDip2ErrCount);
    /* SPI/Eagle tx stats */
    SPIETSOP += ptgetreg(0, AD_StsTxSpiSopCount);
    SPIETEOP += ptgetreg(0, AD_StsTxSpiEopCount);
    SPIETDPVEOP += ptgetreg(0, AD_StsTxSpiDPVEopCnt);
    SPIETDPGEOP += ptgetreg(0, AD_StsTxSpiDPGEopCnt);
    SPIETTrain += ptgetreg(0, AD_StsTxSpiTrainingCount);
    SPIETFIFOO += ptgetreg(0, AD_StsTxSpiFifoOverFlow);
    SPIETEAEOP += ptgetreg(0, AD_StsTxSpiExtAbortEopCount);
    SPIETIAEOP += ptgetreg(0, AD_StsTxSpiIntAbortEopCount);
    SPIETDIP4 += ptgetreg(0, AD_StsTxSpiDip4ErrCount);
    SPIETPVIOL += ptgetreg(0, AD_StsTxSpiProtViolCount);
    printf("RTM SPI:\n");
    /* SPI/Eagle rx stats */
    printf("  SPIERSOP   : 0x%08x", SPIERSOP);
    printf("  SPIEREOP1  : 0x%08x", SPIEREOP1);
    printf("  SPIEREOP2  : 0x%08x", SPIEREOP2);
    printf("  SPIEREOPA  : 0x%08x", SPIEREOPA);
    printf("\n");
    /* SPI/Eagle rx stats */
    printf("  SPIERTrain : 0x%08x", SPIERTrain);
    printf("  SPIEROFU   : 0x%08x", SPIEROFU);
    printf("  SPIERLOS   : 0x%08x", SPIERLOS);
    printf("  SPIERCal   : 0x%08x", SPIERCal);
    printf("\n");
    /* SPI/Eagle rx stats */
    printf("  SPIERAUPE  : 0x%08x", SPIERAUPE);
    printf("  SPIERBFU   : 0x%08x", SPIERBFU);
    printf("  SPIERAUSOP : 0x%08x", SPIERAUSOP);
    printf("  SPIERD2ERR : 0x%08x", SPIERD2ERR);
    printf("\n");
    /* SPI/Eagle tx stats */
    printf("  SPIETSOP   : 0x%08x", SPIETSOP);
    printf("  SPIETEOP   : 0x%08x", SPIETEOP);
    printf("  SPIETDPVEOP: 0x%08x", SPIETDPVEOP);
    printf("  SPIETDPGEOP: 0x%08x", SPIETDPGEOP);
    printf("\n");
    /* SPI/Eagle tx stats */
    printf("  SPIETTrain : 0x%08x", SPIETTrain);
    printf("  SPIETFIFOO : 0x%08x", SPIETFIFOO);
    printf("  SPIETEAEOP : 0x%08x", SPIETEAEOP);
    printf("  SPIETIAEOP : 0x%08x", SPIETIAEOP);
    printf("\n");
    printf("  SPIETDIP4  : 0x%08x", SPIETDIP4);
    printf("  SPIETPVIOL : 0x%08x", SPIETPVIOL);
    printf("\n");
}

/* SPI/Cavium error stats */
uint32_t SPI0CAVCPA0 = 0;
uint32_t SPI0CAVCPA1 = 0;
uint32_t SPI0CAVBRTE = 0;
uint32_t SPI0CAVDOVR = 0;
uint32_t SPI0CAVDIPE = 0;
uint32_t SPI0CAVNSYN = 0;
uint32_t SPI0CAVUXFR = 0;
uint32_t SPI0CAVFRME = 0;
uint32_t SPI0CAVSYNE = 0;
uint32_t SPI1CAVCPA0 = 0;
uint32_t SPI1CAVCPA1 = 0;
uint32_t SPI1CAVBRTE = 0;
uint32_t SPI1CAVDOVR = 0;
uint32_t SPI1CAVDIPE = 0;
uint32_t SPI1CAVNSYN = 0;
uint32_t SPI1CAVUXFR = 0;
uint32_t SPI1CAVFRME = 0;
uint32_t SPI1CAVSYNE = 0;

void ptdumpcaviumptiinfo(void)
{
    uint32_t regVal;
    uint32_t writeBack;
    /* SPI/Cavium error stats */
    writeBack = 0;
    regVal = cvmx_read_csr(CVMX_STXX_INT_REG(0));
    if (regVal & 0x01)
    {
        ++SPI0CAVCPA0;
        writeBack = 1;
    }
    if (regVal & 0x02)
    {
        ++SPI0CAVCPA1;
        writeBack = 1;
    }
    if (regVal & 0x04)
    {
        ++SPI0CAVBRTE;
        writeBack = 1;
    }
    if (regVal & 0x08)
    {
        ++SPI0CAVDOVR;
        writeBack = 1;
    }
    if (regVal & 0x10)
    {
        ++SPI0CAVDIPE;
        writeBack = 1;
    }
    if (regVal & 0x20)
    {
        ++SPI0CAVNSYN;
        writeBack = 1;
    }
    if (regVal & 0x40)
    {
        ++SPI0CAVUXFR;
        writeBack = 1;
    }
    if (regVal & 0x80)
    {
        ++SPI0CAVFRME;
        writeBack = 1;
    }
    if (regVal & 0x08)
    {
        ++SPI0CAVSYNE;
        writeBack = 1;
    }
    if (writeBack)
    {
        cvmx_write_csr(CVMX_STXX_INT_REG(0), regVal);
    }

    writeBack = 0;
    regVal = cvmx_read_csr(CVMX_STXX_INT_REG(1));
    if (regVal & 0x01)
    {
        ++SPI1CAVCPA0;
        writeBack = 1;
    }
    if (regVal & 0x02)
    {
        ++SPI1CAVCPA1;
        writeBack = 1;
    }
    if (regVal & 0x04)
    {
        ++SPI1CAVBRTE;
        writeBack = 1;
    }
    if (regVal & 0x08)
    {
        ++SPI1CAVDOVR;
        writeBack = 1;
    }
    if (regVal & 0x10)
    {
        ++SPI1CAVDIPE;
        writeBack = 1;
    }
    if (regVal & 0x20)
    {
        ++SPI1CAVNSYN;
        writeBack = 1;
    }
    if (regVal & 0x40)
    {
        ++SPI1CAVUXFR;
        writeBack = 1;
    }
    if (regVal & 0x80)
    {
        ++SPI1CAVFRME;
        writeBack = 1;
    }
    if (regVal & 0x08)
    {
        ++SPI1CAVSYNE;
        writeBack = 1;
    }
    if (writeBack)
    {
        cvmx_write_csr(CVMX_STXX_INT_REG(1), regVal);
    }

    if (cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000)
    {
        printf("Cavium B SPI Dataplane:\n");
    }
    else
    {
        printf("Cavium A SPI Dataplane:\n");
    }
    /* SPI0/Cavium tx stats */
    printf("  SPI0CAVFTx : 0x%08x", cvmx_read_csr(CVMX_STXX_STAT_PKT_XMT(0)));
    printf("  SPI0CAVOTxH: 0x%08x", cvmx_read_csr(CVMX_STXX_STAT_BYTES_HI(0)));
    printf("  SPI0CAVOTxL: 0x%08x", cvmx_read_csr(CVMX_STXX_STAT_BYTES_LO(0)));
    printf("\n");
    /* SPI1/Cavium tx stats */
    printf("  SPI1CAVFTx : 0x%08x", cvmx_read_csr(CVMX_STXX_STAT_PKT_XMT(1)));
    printf("  SPI1CAVOTxH: 0x%08x", cvmx_read_csr(CVMX_STXX_STAT_BYTES_HI(1)));
    printf("  SPI1CAVOTxL: 0x%08x", cvmx_read_csr(CVMX_STXX_STAT_BYTES_LO(1)));
    printf("\n");
    /* SPI0/Cavium error stats */
    printf("  SPI0CAVCPA0: 0x%08x", SPI0CAVCPA0);
    printf("  SPI0CAVCPA1: 0x%08x", SPI0CAVCPA1);
    printf("  SPI0CAVBRTE: 0x%08x", SPI0CAVBRTE);
    printf("  SPI0CAVDOVR: 0x%08x", SPI0CAVDOVR);
    printf("\n");
    printf("  SPI0CAVDIPE: 0x%08x", SPI0CAVDIPE);
    printf("  SPI0CAVNSYN: 0x%08x", SPI0CAVNSYN);
    printf("  SPI0CAVUXFR: 0x%08x", SPI0CAVUXFR);
    printf("  SPI0CAVFRME: 0x%08x", SPI0CAVFRME);
    printf("\n");
    printf("  SPI0CAVSYNE: 0x%08x", SPI0CAVSYNE);
    printf("\n");
    /* SPI1/Cavium error stats */
    printf("  SPI1CAVCPA0: 0x%08x", SPI1CAVCPA0);
    printf("  SPI1CAVCPA1: 0x%08x", SPI1CAVCPA1);
    printf("  SPI1CAVBRTE: 0x%08x", SPI1CAVBRTE);
    printf("  SPI1CAVDOVR: 0x%08x", SPI1CAVDOVR);
    printf("\n");
    printf("  SPI1CAVDIPE: 0x%08x", SPI1CAVDIPE);
    printf("  SPI1CAVNSYN: 0x%08x", SPI1CAVNSYN);
    printf("  SPI1CAVUXFR: 0x%08x", SPI1CAVUXFR);
    printf("  SPI1CAVFRME: 0x%08x", SPI1CAVFRME);
    printf("\n");
    printf("  SPI1CAVSYNE: 0x%08x", SPI1CAVSYNE);
    printf("\n");
}

/* SPI/Redhawk tx stats */
uint32_t SPIRTSOP = 0;
uint32_t SPIRTEOP = 0;
uint32_t SPIRTEEOP = 0;
uint32_t SPIRTIEOP = 0;
uint32_t SPIRTTrain = 0;
uint32_t SPIRTDIP4 = 0;
uint32_t SPIRTPVIOL = 0;
uint32_t SPIRTSYNCL = 0;
uint32_t SPIRTFIFOO = 0;
/* SPI/Redhawk rx stats */
uint32_t SPIRRSOP = 0;
uint32_t SPIRREOP1 = 0;
uint32_t SPIRREOP2 = 0;
uint32_t SPIRREOPA = 0;
/* SPI/Redhawk tx stats */
void ptdumpredhawkptiinfo(void)
{
	uint32_t regVal;

    /* SPI/Redhawk tx stats */
    regGet( redHawkRegs, StsRegTSpiSopCount, 0, &regVal );
    SPIRTSOP += regVal;
    regGet( redHawkRegs, StsRegTSpiEopCount, 0, &regVal );
    SPIRTEOP += regVal;
    regGet( redHawkRegs, StsRegTSpiExtEopACount, 0, &regVal );
    SPIRTEEOP += regVal;
    regGet( redHawkRegs, StsRegTSpiIntEopACount, 0, &regVal );
    SPIRTIEOP += regVal;
    regGet( redHawkRegs, StsRegTSpiTrainingCount, 0, &regVal );
    SPIRTTrain += regVal;
    regGet( redHawkRegs, StsRegTSpiDip4ErrCount, 0, &regVal );
    SPIRTDIP4 += regVal;
    regGet( redHawkRegs, StsRegTSpiProtViolCount, 0, &regVal );
    SPIRTPVIOL += regVal;
    regGet( redHawkRegs, StsRegTSpiLossOfSync, 0, &regVal );
    SPIRTSYNCL += regVal;
    regGet( redHawkRegs, StsRegTSpiFifoOverFlow, 0, &regVal );
    SPIRTFIFOO += regVal;
    /* SPI/Redhawk rx stats */
    regGet( redHawkRegs, StsRegRxpSpiSopCount, 0, &regVal );
    SPIRRSOP += regVal;
    regGet( redHawkRegs, StsRegRxpSpiEop1Count, 0, &regVal );
    SPIRREOP1 += regVal;
    regGet( redHawkRegs, StsRegRxpSpiEop2Count, 0, &regVal );
    SPIRREOP2 += regVal;
    regGet( redHawkRegs, StsRegRxpSpiEopACount, 0, &regVal );
    SPIRREOPA += regVal;
    printf("Redhawk SPI:\n");
    /* SPI/Redhawk rx stats */
    printf("  SPIRTSOP   : 0x%08x", SPIRTSOP);
    printf("  SPIRTEOP   : 0x%08x", SPIRTEOP);
    printf("  SPIRTEEOP  : 0x%08x", SPIRTEEOP);
    printf("  SPIRTIEOP  : 0x%08x", SPIRTIEOP);
    printf("\n");
    printf("  SPIRTTrain : 0x%08x", SPIRTTrain);
    printf("  SPIRTDIP4  : 0x%08x", SPIRTDIP4);
    printf("  SPIRTPVIOL : 0x%08x", SPIRTPVIOL);
    printf("  SPIRTSYNCL : 0x%08x", SPIRTSYNCL);
    printf("\n");
    printf("  SPIRTFIFOO : 0x%08x", SPIRTFIFOO);
    printf("\n");
    /* SPI/Redhawk rx stats */
    printf("  SPIRRSOP   : 0x%08x", SPIRRSOP);
    printf("  SPIRREOP1  : 0x%08x", SPIRREOP1);
    printf("  SPIRREOP2  : 0x%08x", SPIRREOP2);
    printf("  SPIRREOPA  : 0x%08x", SPIRREOPA);
    printf("\n");
}

extern int write_tlv_tuple(octeon_eeprom_header_t *);
extern int do_inite1000eeprom (cmd_tbl_t *, int, int, char *);

void uboot_mac_addr_update(void)
{
    DECLARE_GLOBAL_DATA_PTR;
    int addr, ind, bladeMacFromMMC[BOARD_MMC_BLADE_MAC_SIZE], rtmMacFromMMC[BOARD_MMC_RTM_MAC_SIZE];
    int bladeMacChanged, rtmMacChanged, mmcMacPres;
    uint16_t eeprom_buf16[OCTEON_EEPROM_MAX_TUPLE_LENGTH/2 + 1];
    uint8_t *eeprom_buf = (void *)eeprom_buf16;
    octeon_eeprom_mac_addr_t *bladeMac = (void *)eeprom_buf;
    octeon_eeprom_mac_addr_t *rtmMac = (void *)eeprom_buf;
    char *s;

	s = getenv("blademacoverride");
	if (strcmp(s, "yes") != 0)
	{
        bladeMacChanged = 0;
        /* get Blade MAC from MMC space EEPROM if it exists */
        for (ind = 0, addr = BOARD_MMC_BLADE_MAC_START, mmcMacPres = 0; ind < BOARD_MMC_BLADE_MAC_SIZE; ind++, addr++)
        {
            bladeMacFromMMC[ind] = octeon_twsi_read8(BOARD_EEPROM_TWSI_ADDR, addr);
            if (bladeMacFromMMC[ind] != 0xFF)
            {
                mmcMacPres = 1;
            }
        }
        if (mmcMacPres)
        {
            /* compare MMC MAC with Blade MAC */
            addr = octeon_tlv_get_tuple_addr(CFG_DEF_EEPROM_ADDR, EEPROM_MAC_ADDR_TYPE, 1, (uint8_t *)bladeMac, OCTEON_EEPROM_MAX_TUPLE_LENGTH);
            if (addr >= 0)
            {
                for (ind = 0; ind < BOARD_MMC_BLADE_MAC_SIZE; ind++)
                {
                    if (bladeMacFromMMC[ind] != bladeMac->mac_addr_base[ind])
                    {
                        bladeMacChanged = 1;
                        break;
                    }
                }
            }
            else
            {
                bladeMacChanged = 1;
            }
            /* update Blade MAC if necessary */
            if (bladeMacChanged)
            {
                bladeMac->header.type = EEPROM_MAC_ADDR_TYPE;
                bladeMac->header.major_version = OCTEON_EEPROM_MAC_ADDR_MAJOR_VER;
                bladeMac->header.minor_version = OCTEON_EEPROM_MAC_ADDR_MINOR_VER;
                bladeMac->header.length = sizeof(octeon_eeprom_mac_addr_t);
                bladeMac->count = 16;
                for (ind = 0; ind < BOARD_MMC_BLADE_MAC_SIZE; ind++)
                {
                    bladeMac->mac_addr_base[ind] = bladeMacFromMMC[ind];
                }
                printf("Blade MAC Address Update... ");
                write_tlv_tuple((octeon_eeprom_header_t *)bladeMac);
                /* update global data */
                for (ind = 0; ind < BOARD_MMC_BLADE_MAC_SIZE; ind++)
                {
                    gd->mac_desc.mac_addr_base[ind] = bladeMac->mac_addr_base[ind];
                }
                /* update 82546 eeprom */
                do_inite1000eeprom ((cmd_tbl_t *)NULL, (int)NULL, (int)NULL, (char *)NULL);
                printf("Blade MAC Address Change!... (RESET SYSTEM TO TAKE EFFECT)\n");
            }
        }
    }

	s = getenv("rtmmacoverride");
	if (strcmp(s, "yes") != 0)
	{
        rtmMacChanged = 0;
        /* get RTM MAC from MMC space EEPROM if it exists */
        for (ind = 0, addr = BOARD_MMC_RTM_MAC_START, mmcMacPres = 0; ind < BOARD_MMC_RTM_MAC_SIZE; ind++, addr++)
        {
            rtmMacFromMMC[ind] = octeon_twsi_read8(BOARD_EEPROM_TWSI_ADDR, addr);
            if (rtmMacFromMMC[ind] != 0xFF)
            {
                mmcMacPres = 1;
            }
        }
        if (mmcMacPres)
        {
            /* compare MMC MAC with RTM MAC */
            addr = octeon_tlv_get_tuple_addr(CFG_DEF_EEPROM_ADDR, EEPROM_RTM_MAC_ADDR_TYPE, 1, (uint8_t *)rtmMac, OCTEON_EEPROM_MAX_TUPLE_LENGTH);
            if (addr >= 0)
            {
                for (ind = 0; ind < BOARD_MMC_RTM_MAC_SIZE; ind++)
                {
                    if (rtmMacFromMMC[ind] != rtmMac->mac_addr_base[ind])
                    {
                        rtmMacChanged = 1;
                        break;
                    }
                }
            }
            else
            {
                rtmMacChanged = 1;
            }
            /* update Blade MAC if necessary */
            if (rtmMacChanged)
            {
                rtmMac->header.type = EEPROM_RTM_MAC_ADDR_TYPE;
                rtmMac->header.major_version = OCTEON_EEPROM_MAC_ADDR_MAJOR_VER;
                rtmMac->header.minor_version = OCTEON_EEPROM_MAC_ADDR_MINOR_VER;
                rtmMac->header.length = sizeof(octeon_eeprom_mac_addr_t);
                rtmMac->count = 16;
                for (ind = 0; ind < BOARD_MMC_RTM_MAC_SIZE; ind++)
                {
                    rtmMac->mac_addr_base[ind] = rtmMacFromMMC[ind];
                }
                printf("RTM MAC Address Update... ");
                write_tlv_tuple((octeon_eeprom_header_t *)rtmMac);
            }
        }
    }
}

void late_board_init(void)
{
    DECLARE_GLOBAL_DATA_PTR;
    uint16_t fpga_mcr;
    struct eth_device *ed;
    char *s0, *s1;

    fpga_mcr = *BOARD_MASTER_CONTROL_REG;
    if (cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000)
    {
        printf("Cavium B / FPGA Version: 0x%04x / Master Control: 0x%04x\n",
                                                               *BOARD_VERSION_ID_REG, *BOARD_MASTER_CONTROL_REG);
        if ((fpga_mcr & GES_OWNED_MASK) == GES_OCT_B_OWNED)
        {

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_PRESTERA_INIT);
#endif

            if (prInit () != 0)
            {
                printf("Error During Prestera Initialization!\n");
            }
        }
        else if ((fpga_mcr & GES_OWNED_MASK) != GES_OCT_A_OWNED)
        {
            printf("Prestera was NOT initialized!\n");
        }
        if ((fpga_mcr & RHWK_OWNED_MASK) == RHWK_OCT_B_OWNED)
        {

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_REDHAWK_INIT);
#endif

            if (rhInit () != 0)
            {
                printf("Error During RedHawk Initialization!\n");
            }
        }
        else if ((fpga_mcr & RHWK_OWNED_MASK) != RHWK_OCT_A_OWNED)
        {
            printf("Redhawk was NOT initialized!\n");
        }
        if ((fpga_mcr & RTM_OWNED_MASK) == RTM_OCT_B_OWNED)
        {
            if (*BOARD_RTM_GE_CARDID == GE_RTM_CARDID)
            {

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_EAGLE_INIT);
#endif

                if (egInit (1) != 0)
                {
                    printf("Error During Eagle Initialization!\n");
                }
            }
            else
            {
                printf("RTM is not recognized / Address: 0x%08x has CardID: 0x%04x\n",
                                                                      BOARD_RTM_GE_CARDID, *BOARD_RTM_GE_CARDID);
            }
        }
        else if ((fpga_mcr & RTM_OWNED_MASK) != RTM_OCT_A_OWNED)
        {
            printf("RTM not found / Eagle was not initialized\n");
        }
        if ((fpga_mcr & SFP_OWNED_MASK) == SFP_OCT_B_OWNED)
        {

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_PHYLINK_INIT);
#endif

            phyLinkSetup(1);
        }
        else if ((fpga_mcr & SFP_OWNED_MASK) != SFP_OCT_A_OWNED)
        {
            printf("SFPs were NOT initialized!\n");
        }
    }
    else
    {
        printf("Cavium A / FPGA Version: 0x%04x / Master Control: 0x%04x\n",
                                                               *BOARD_VERSION_ID_REG, *BOARD_MASTER_CONTROL_REG);
        if ((fpga_mcr & GES_OWNED_MASK) == GES_OCT_A_OWNED)
        {

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_PRESTERA_INIT);
#endif

            if (prInit () != 0)
            {
                printf("Error During Prestera Initialization!\n");
            }
        }
        else if ((fpga_mcr & GES_OWNED_MASK) != GES_OCT_B_OWNED)
        {
            printf("Prestera was NOT initialized!\n");
        }
        if ((fpga_mcr & RHWK_OWNED_MASK) == RHWK_OCT_A_OWNED)
        {

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_REDHAWK_INIT);
#endif

            if (rhInit () != 0)
            {
                printf("Error During RedHawk Initialization!\n");
            }
        }
        else if ((fpga_mcr & RHWK_OWNED_MASK) != RHWK_OCT_B_OWNED)
        {
            printf("Redhawk was NOT initialized!\n");
        }
        if ((fpga_mcr & RTM_OWNED_MASK) == RTM_OCT_A_OWNED)
        {
            if (*BOARD_RTM_GE_CARDID == GE_RTM_CARDID)
            {

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_EAGLE_INIT);
#endif

                if (egInit (1) != 0)
                {
                    printf("Error During Eagle Initialization!\n");
                }
            }
            else
            {
                printf("RTM is not recognized / Address: 0x%08x has CardID: 0x%04x\n",
                                                                      BOARD_RTM_GE_CARDID, *BOARD_RTM_GE_CARDID);
            }
        }
        else if ((fpga_mcr & RTM_OWNED_MASK) != RTM_OCT_B_OWNED)
        {
            printf("RTM not found / Eagle was not initialized\n");
        }
        if ((fpga_mcr & SFP_OWNED_MASK) == SFP_OCT_A_OWNED)
        {

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_PHYLINK_INIT);
#endif

            phyLinkSetup(1);
        }
        else if ((fpga_mcr & SFP_OWNED_MASK) != SFP_OCT_B_OWNED)
        {
            printf("SFPs were NOT initialized!\n");
        }
    }
    /* initialize SPI ports */
    ed = eth_devices;
    do
    {
        if ((strcmp(ed->name, "octspi0") == 0) ||
            (strcmp(ed->name, "octspi1") == 0))
        {
            if (ed->init(ed, gd->bd))
            {
                ed->state = ETH_STATE_ACTIVE;
            }
        }
        ed = ed->next;
    }
    while (ed != eth_devices);

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_VERSION_NUM_STORE);
#endif

    uboot_version_num_store();

#ifdef CONFIG_OCTEON_GEF_BOOT_PROGRESS_SUPPORT
    BOOT_PROGRESS_UPDATE(BPM_MAC_ADDR_UPDATE);
#endif

    uboot_mac_addr_update();
    /* configure the Redhawk for SPI internal loopback (transmit to receive) if configured */
    if (((cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000) && ((fpga_mcr & RHWK_OWNED_MASK) == RHWK_OCT_B_OWNED)) ||
        ((!(cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000)) && ((fpga_mcr & RHWK_OWNED_MASK) == RHWK_OCT_A_OWNED)))
    {
        s0 = getenv("rhspittrl");
        if ((s0 != NULL) && (strcmp(s0, "yes") == 0))
        {
            regSet(redHawkRegs, CfgRegCoLoopbackMode__PSpiTx2RxLpbk, 0, 1); /* Enable internal loopback */
        }
    }
    /* configure the Eagle SFPs if configured for Passthrough and own the RTM */
    if (((cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000) && ((fpga_mcr & RTM_OWNED_MASK) == RTM_OCT_B_OWNED)) ||
        ((!(cvmx_read_csr(CVMX_GPIO_RX_DAT) & 0x8000)) && ((fpga_mcr & RTM_OWNED_MASK) == RTM_OCT_A_OWNED)))
    {
        if (*BOARD_RTM_GE_CARDID == GE_RTM_CARDID)
        {
            s0 = getenv("spi0_pt");
            s1 = getenv("spi1_pt");
            if (((s0 != NULL) && (strcmp(s0, "yes") == 0)) ||
                ((s1 != NULL) && (strcmp(s1, "yes") == 0)))
            {
                dpSfpEagleAutonegCompleteCheck();
            }
        }
    }
}

int do_sfp_show (void)
{
    int interface;

    for (interface = 0; interface < MAX_NUM_SFP; interface++)
    {
        printf ("Interface %d:\n", interface);
        switch (octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, ID))
        {
            case 0:
                printf ("    ID: Unknown or unspecified\n");
                break;
            case 1:
                printf ("    ID: GBIC\n");
                break;
            case 2:
                printf ("    ID: Module/connector soldered to motherboard\n");
                break;
            case 3:
                printf ("    ID: SFP transceiver\n");
                break;
            default:
                printf ("    ID: 0x%02x\n", octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, ID));
                break;
        }
        printf ("    Ext ID: 0x%02x\n", octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, EXT_ID));
        switch (octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, CONNECTOR))
        {
            case 0:
                printf ("    Connector: Unknown or unspecified\n");
                break;
            case 1:
                printf ("    Connector: SC\n");
                break;
            case 2:
                printf ("    Connector: Fiber Channel Style 1 copper connector\n");
                break;
            case 3:
                printf ("    Connector: Fiber Channel Style 2 copper connector\n");
                break;
            case 4:
                printf ("    Connector: BNC/TNC\n");
                break;
            case 5:
                printf ("    Connector: Fiber Channel coaxial headers\n");
                break;
            case 6:
                printf ("    Connector: Fiber Jack\n");
                break;
            case 7:
                printf ("    Connector: LC\n");
                break;
            case 8:
                printf ("    Connector: MT-RJ\n");
                break;
            case 9:
                printf ("    Connector: MU\n");
                break;
            case 10:
                printf ("    Connector: SG\n");
                break;
            case 11:
                printf ("    Connector: Optical Pigtail\n");
                break;
            case 32:
                printf ("    Connector: HSSDC II\n");
                break;
            case 33:
                printf ("    Connector: Copper Pigtail\n");
                break;
            default:
                printf ("    Connector: 0x%02x\n", octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, CONNECTOR));
                break;
        }
        printf ("    Link Length: 9/125 mm Fiber (units of kilometers) - 0x%02x\n",
                octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, FIBER_9_125MM_UNITS_KM));
        printf ("    Link Length: 9/125 mm Fiber (units of 100 meters) - 0x%02x\n",
                octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, FIBER_9_125MM_UNITS_100M));
        printf ("    Link Length: 50/125 mm Fiber (units of 10 meters) - 0x%02x\n",
                octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, FIBER_50_125MM_UNITS_10M));
        printf ("    Link Length: 62.5/125 mm Fiber (units of 10 meters) - 0x%02x\n",
                octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, FIBER_62P5_125MM_UNITS_10M));
        printf ("    Link Length: Copper (units of meters) - 0x%02x\n",
                octeon_twsi_read8(BOARD_SFP0_TWSI_ADDR + interface, COPPER_UNITS_M));
    }
    return (0);
}

int do_sfp_init(void)
{
    /* initialize SFPs */
    printf ("CP SFP Type: ");
    sfpInit (PRES_FP_CP_0, 1);
    sfpInit (PRES_FP_CP_1, 1);
    npaEgEnablePort( &gEagleObj, EAGLE_DATA_PORTS + 0 );
    sfpInit (PRES_RTM_CP_0, 1);
    npaEgEnablePort( &gEagleObj, EAGLE_DATA_PORTS + 1 );
    sfpInit (PRES_RTM_CP_1, 1);
    printf ("\n");
    return (0);
}

int octeon_post_error_store(uint8_t error_code)
{
    int loc;

    /* find location to store error code */
    for (loc = 0; loc < BOARD_POST_LOG_SIZE; loc++)
    {
        if (octeon_twsi_read8(BOARD_EEPROM_TWSI_ADDR, BOARD_POST_LOG_START + loc) == NO_POST_ERROR)
        {
            octeon_twsi_write8(BOARD_EEPROM_TWSI_ADDR, BOARD_POST_LOG_START + loc, error_code);
            return 0;
        }
    }
    return -1;
}

int octeon_post_error_retrieve(uint8_t *post_error_code_buf_ptr)
{
    int loc;

    /* retrieve the entire buffer */
    for (loc = 0; loc < BOARD_POST_LOG_SIZE; loc++)
    {
        post_error_code_buf_ptr[loc] = octeon_twsi_read8(BOARD_EEPROM_TWSI_ADDR, BOARD_POST_LOG_START + loc);
    }
    return 0;
}

int octeon_post_error_clear(void)
{
    int loc;

    /* clear the entire buffer */
    for (loc = 0; loc < BOARD_POST_LOG_SIZE; loc++)
    {
        octeon_twsi_write8_addr16(BOARD_EEPROM_TWSI_ADDR, BOARD_POST_LOG_START + loc, NO_POST_ERROR);
    }
    return 0;
}
