/*
 * Copyright (c) 2011-2012, Freescale Semiconductor, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*!
 * @file enet_drv.c
 * @brief Driver of the i.MX ENET controller.
 *
 * @ingroup diag_enet
 */

//#include "sdk.h"
#include "hal_build.h"
#include "imx_enet.h"
#include "registers/regsenet.h"

#include "enet_private.h"

/*!
 *Global variable which defines the buffer descriptions for receiving frame
 *  comment:: it must aligned by 128-bits.
 */
static imx_enet_bd_t imx_enet_rx_bd[ENET_BD_RX_NUM * NUM_OF_ETH_DEVS] __attribute__ ((aligned(32)));

/*!
 *Global variable which defines the buffer descriptions for receiving frame
 *  comment:: it must aligned by 128-bits.
 */
static imx_enet_bd_t imx_enet_tx_bd[ENET_BD_TX_NUM * NUM_OF_ETH_DEVS] __attribute__ ((aligned(32)));

/*!
 * Global variable which contains the frame buffers ,
 */
static unsigned char imx_enet_rx_buf[ENET_BD_RX_NUM * NUM_OF_ETH_DEVS][2048]
    __attribute__ ((aligned(32)));

/*!
 * Global variable which contains the frame buffers ,
 */
static unsigned char imx_enet_tx_buf[ENET_BD_TX_NUM * NUM_OF_ETH_DEVS][2048]
    __attribute__ ((aligned(32)));

/*!
 * This function gets the value of the PHY registers through the MII interface.
 */
int imx_enet_mii_read(volatile ENET_Type * enet_reg, unsigned char phy_addr,
                      unsigned char reg_addr, unsigned short int *value)
{
    unsigned long waiting = ENET_MII_TIMEOUT;

    if (enet_reg->EIR & ENET_EIR_MII_MASK) {
        enet_reg->EIR = ENET_EIR_MII_MASK;
    }

    enet_reg->MMFR = ENET_MII_READ(phy_addr, reg_addr);   /*Write CMD */

    while (1) {
        if (enet_reg->EIR & ENET_EIR_MII_MASK) {
            enet_reg->EIR = ENET_EIR_MII_MASK;
            break;
        }
        if ((--waiting) == 0)
            return -1;
        npl_timer_delay_ms( 1 );
    }

    *value = ENET_MII_GET_DATA(enet_reg->MMFR);
    return 0;
}

/*!
 * This function sets the value of the PHY registers through the MII interface.
 */
int imx_enet_mii_write(volatile ENET_Type * enet_reg, unsigned char phy_addr,
                       unsigned char reg_addr, unsigned short int value)
{
    unsigned long waiting = ENET_MII_TIMEOUT;

    if (enet_reg->EIR & ENET_EIR_MII_MASK) {
        enet_reg->EIR = ENET_EIR_MII_MASK;
    }

    enet_reg->MMFR = ENET_MII_WRITE(phy_addr, reg_addr, value);   /* Write CMD */

    while (1) {
        if (enet_reg->EIR & ENET_EIR_MII_MASK) {
            enet_reg->EIR = ENET_EIR_MII_MASK;
            break;
        }

        if ((--waiting) == 0)
            return -1;

        npl_timer_delay_ms( 1 );
    }

    return 0;
}

/*!
 * The function initializes the description buffer for receiving or transmitting.
 */
static void imx_enet_bd_init(imx_enet_priv_t * dev, int dev_idx)
{
    int i;
    imx_enet_bd_t *p;
    imx_enet_bd_t *rx_bd_base = imx_enet_rx_bd, *tx_bd_base = imx_enet_tx_bd;

    rx_bd_base += (dev_idx * ENET_BD_RX_NUM);
    tx_bd_base += (dev_idx * ENET_BD_TX_NUM);

    p = dev->rx_bd = (imx_enet_bd_t *) rx_bd_base;

    for (i = 0; i < ENET_BD_RX_NUM; i++, p++) {
        p->status = BD_RX_ST_EMPTY;
        p->length = 0;
        p->data = (unsigned char *)imx_enet_rx_buf[i + dev_idx * ENET_BD_RX_NUM];
        //printf("rx bd %x, buffer is %x\n", (unsigned int)p, (unsigned int)p->data);
    }

    dev->rx_bd[i - 1].status |= BD_RX_ST_WRAP;
    dev->rx_cur = dev->rx_bd;

    p = dev->tx_bd = (imx_enet_bd_t *) tx_bd_base;

    for (i = 0; i < ENET_BD_TX_NUM; i++, p++) {
        p->status = 0;
        p->length = 0;
        p->data = (unsigned char *)imx_enet_tx_buf[i + dev_idx * ENET_BD_TX_NUM];
        //printf("tx bd %x, buffer is %x\n", (unsigned int)p, (unsigned int)p->data);
    }

    dev->tx_bd[i - 1].status |= BD_TX_ST_WRAP;
    dev->tx_cur = dev->tx_bd;

    /*TODO:: add the sync function for items */
}

/*!
 * This function initializes the ENET controller.
 */

static void imx_enet_chip_init(imx_enet_priv_t * dev)
{
//    volatile hw_enet_t *enet_reg = (hw_enet_t *) dev->enet_reg;
    volatile ENET_Type *enet_reg = (ENET_Type *) dev->enet_reg;

    unsigned int ipg_clk;
printf("enet_reg->ECR  = ENET_ECR_RESET(1);\n");
    enet_reg->ECR  = ENET_ECR_RESET(1);

    while (enet_reg->ECR & ENET_ECR_RESET(1)) {
        npl_timer_delay_ms( 1 );
    }
printf("enet_reg->EIMR\n");
//    enet_reg->EIMR = 0x00000000;
    enet_reg->EIMR = 0xFFFF0000;

    enet_reg->EIR  = 0xFFFFFFFF;

    /*
     * setup the MII gasket for RMII mode
     */
printf("enet_reg->RCR\n");
    enet_reg->RCR = (enet_reg->RCR) &( ~(0x0000003F)) | (ENET_RCR_MII_MODE(1)| ENET_RCR_RMII_10T(1) | ENET_RCR_PROM(1)| ENET_RCR_FCE(1));

printf("enet_reg->TCR\n");
    enet_reg->TCR |= ENET_TCR_FDEN(1);
printf("enet_reg->MIBC\n");
    enet_reg->MIBC |= ENET_MIBC_MIB_DIS(1);

    enet_reg->IAUR = 0;
    enet_reg->IALR = 0;
    enet_reg->GAUR = 0;
    enet_reg->GALR = 0;
printf("enet_reg->MSCR\n");
    //Internal Module Clock Frequency = 66MHz
    //MII_SPPED=0xD
    //enet_reg->MSCR.U = (enet_reg->MSCR.U & (~0x7e)) | (((ipg_clk + 499999) / 5000000) << 1);
    enet_reg->MSCR = (enet_reg->MSCR & (~0x7e)) | (ENET_MSCR_MII_SPEED(0xD));
printf("enet_reg->MRBR\n");
    //Enable ETHER_EN
    enet_reg->MRBR = 2048 - 16;
    enet_reg->RDSR = (unsigned long)dev->rx_bd;
    enet_reg->TDSR = (unsigned long)dev->tx_bd;

#if 0//defined(CHIP_MX6DQ) || defined(CHIP_MX6SDL)
    /* Enable Swap to support little-endian device */
    enet_reg->ECR.U |= (0x1 << 8); //BM_ENET_ECR_DBSWP;
    /* set ENET tx at store and forward mode */
    enet_reg->TFWR.U |= BM_ENET_TFWR_STRFWD; //(0x1 << 8);
#endif
}


/*!
 * This function initializes the PHY connected to the ENET controller.
 */
void imx_enet_phy_init(imx_enet_priv_t * dev)
{
    unsigned short value = 0;
    unsigned long id = 0;

    // Read PHY ID registers.
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_IDENTIFY_1, &value);
    id = (value & PHY_ID1_MASK) << PHY_ID1_SHIFT;
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_IDENTIFY_2, &value);
    id |= (value & PHY_ID2_MASK) << PHY_ID2_SHIFT;
    id &= 0xfffffff0; // mask off lower 4 bits

    printf("\n\nENET DP83822 PHY: ID=%lx\n\n", id);

    dev->phy_id = id;

    // Reset PHY
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
    value |= PHY_CTRL_RESET;
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, value);

    // Wait for reset to complete.
    do {
        imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
    } while (value & PHY_CTRL_RESET);

    /* restart auto-negotiation - full duplex */
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
    value |= 0x1300;
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, value);
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
    printf("\n\nThe value of PHY_CTRL_REG = %x\n\n", value);


    /* Enable RMII : RCSR = 0x61 */
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_RCSR_ADDR, PHY_ENABLE_RMII);
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_RCSR_ADDR, &value);
    printf("\n\nThe value of PHY_RCSR_ADDR = %x\n\n", value);


    /* Disable EEE : EECFG3 = 0x18A */
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_REGCR_ADDR, PHY_EXTENDED_REG_ADDRESS);
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_ADDAR_ADDR, PHY_EECFG3_ADDR);

    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_REGCR_ADDR, PHY_EXTENDED_REG_DATA);
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_ADDAR_ADDR, PHY_DISABLE_EEE);
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_ADDAR_ADDR, &value);
    printf("\n\nThe value of PHY_EECFG3_ADDR = %x\n\n", value);

    /* IOMUX-GPIO3 Clock source: RMII Master Ref Clock = 50MHz, Control = Based on the Ref CLock*/
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_REGCR_ADDR, PHY_EXTENDED_REG_ADDRESS);
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_ADDAR_ADDR, PHY_IOCTRL1_ADDR);

    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_REGCR_ADDR, PHY_EXTENDED_REG_DATA);
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_ADDAR_ADDR, PHY_IOCTRL1_RMII_CLK_50MHZ);
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_ADDAR_ADDR, &value);
    printf("\n\nThe value of PHY_IOCTRL1_ADDR = %x\n\n", value);

    // Read strap latch-in register #1 PHY status.
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_REGCR_ADDR, PHY_EXTENDED_REG_ADDRESS);
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_ADDAR_ADDR, PHY_STRAP_IN_1_ADDR);

    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_REGCR_ADDR, PHY_EXTENDED_REG_DATA);
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_ADDAR_ADDR, &value);
    printf("\n\nThe value of Strap Latch In Register 1 = %x\n\n", value);

    // Read strap latch-in register #2 PHY status.
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_REGCR_ADDR, PHY_EXTENDED_REG_ADDRESS);
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_ADDAR_ADDR, PHY_STRAP_IN_2_ADDR);

    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_REGCR_ADDR, PHY_EXTENDED_REG_DATA);
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_ADDAR_ADDR, &value);
    printf("\n\nThe value of Strap Latch In Register 2 = %x\n\n", value);

    // Reset PHY
    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
    value |= PHY_CTRL_RESET;
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, value);

    // Wait for reset to complete.
    do {
        imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
    } while (value & PHY_CTRL_RESET);

    // Read current PHY status.
    imx_enet_get_phy_status(dev);

}

uint32_t imx_enet_get_phy_status(imx_enet_priv_t * dev)
{
    uint16_t value;

    // Reset saved status.
    dev->status = 0;

    imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_STATUS_REG, &value);

    printf("****** Enet phy status %0d: %04x\n", dev->phy_addr, value);    //  0x7809 or 0x782d

    if (value & PHY_STATUS_LINK_ST)
    {
        dev->status |= ENET_STATUS_LINK_ON;
    }
    else
    {
        dev->status &= ~ENET_STATUS_LINK_ON;
    }
// Below is specific to the DP83822 PHY
    if(value & (1<<14) || value & (1<<12))
    {
        dev->status |= ENET_STATUS_FULL_DPLX;
    } else if(value & (1<<13) || value & (1<<11))
    {
        dev->status &= ~ENET_STATUS_FULL_DPLX;
    }

    if(value & (1<<14) || value & (1<<13))
    {
        dev->status |= ENET_STATUS_100M;
        dev->status &= ~ENET_STATUS_10M;
        dev->status &= ~ENET_STATUS_1000M;
    } else if(value & (1<<13) || value & (1<<11))
    {
        dev->status |= ENET_STATUS_10M;
        dev->status &= ~ENET_STATUS_100M;
        dev->status &= ~ENET_STATUS_1000M;
    }


     printf("ENET %0d: [ %s ] [ %s ] [ %s ]:\n", dev->phy_addr,
            (dev->status & ENET_STATUS_FULL_DPLX) ? "FULL_DUPLEX" : "HALF_DUPLEX",
            (dev->status & ENET_STATUS_LINK_ON) ? "connected" : "disconnected",
            (dev->status & ENET_STATUS_1000M) ? "1000M bps" : (dev->status & ENET_STATUS_100M) ?
            "100M bps" : "10M bps");

    return dev->status;
}

void imx_enet_phy_enable_external_loopback(imx_enet_priv_t * dev)
{
    uint16_t val;

    // Config External Loopback on the PHY
    // BMCR on the DP83822 - register address 0x16 as specified by TI datasheet DP83822
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_BISCR_REG, 0x110); // External Loopback = 1  and Power Mode = 1
}

void imx_enet_phy_enable_mii_loopback(imx_enet_priv_t * dev)
{
    uint16_t val;
    // Config MII Loopback on the PHY
    // BMCR on the DP83822 - register address 0x0 as specified by IEEE802.3 clause 22
    imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, 0x5100); // MII Loopback enable, select speed 10Mbps, Enable Auto Negotiate
}

unsigned long imx_enet_poll(imx_enet_priv_t * dev)
{
    volatile ENET_Type *enet_reg = dev->enet_reg;
    unsigned int value = 0;


// ACDEBUG
    printf("\n Reading EIR: %x \n", value);


    value = enet_reg->EIR;
    enet_reg->EIR = value & (~ENET_EIR_MII(1));


    if (value & (ENET_EIR_BABT(1) | ENET_EIR_LC(1) | ENET_EIR_RL(1) | ENET_EIR_UN(1))) {
        printf("WARNING[POLL]: There are error(%x) for transmit\n", value & (ENET_EIR_BABT(1) | ENET_EIR_LC(1) | ENET_EIR_RL(1) | ENET_EIR_UN(1)));
        dev->tx_busy = 0;
    } else {
        if (value & ENET_EIR_TXF(1)) {
            dev->tx_busy = 0;
        }
    }

    if (value & ENET_EIR_RXF(1)) {
        //imx_enet_check_rx_bd(sc);
    }

//    if (value & ENET_EIR_EBERR(1)) {
//        printf("WARNGING[POLL]: Hearbeat error!\n");
//    }

    if (value & ENET_EIR_EBERR(1)) {
        printf("WARNING[POLL]: Ethernet Bus Error!\n");
    }

    return value;
}

int imx_enet_send(imx_enet_priv_t * dev, unsigned char *buf, int length, unsigned long key)
{
    volatile ENET_Type *enet_reg = dev->enet_reg;
    imx_enet_bd_t *p = dev->tx_cur;

printf("\n\nSending data buffer length %d\n", length);
printf("\nShow the ENET Control Register %x\n\n", enet_reg->ECR);

    memcpy(p->data, buf, length);

    p->length = length;
    p->status &= ~(BD_TX_ST_LAST | BD_TX_ST_RDY | BD_TX_ST_TC | BD_TX_ST_ABC);
    p->status |= BD_TX_ST_LAST | BD_TX_ST_RDY | BD_TX_ST_TC;

    if (p->status & BD_TX_ST_WRAP) {
        p = dev->tx_bd;
    } else
        p++;

    dev->tx_cur = p;
    dev->tx_busy = 1;
    dev->tx_key = key;
    enet_reg->TDAR = ENET_RX_TX_ACTIVE;

    return 0;
}

int imx_enet_recv(imx_enet_priv_t * dev, unsigned char *buf, int *length)
{
    imx_enet_bd_t *p = dev->rx_cur;
    volatile ENET_Type *enet_reg = dev->enet_reg;

    if (p->status & BD_RX_ST_EMPTY) {
        return -1;
    }

    if (!(p->status & BD_RX_ST_LAST)) {
        printf("BUG[RX]: status=%x, length=%x\n", p->status, p->length);
        return -1;
    }

    if ((p->status & BD_RX_ST_ERRS) || (p->length > ENET_FRAME_LEN)) {
        printf("BUG1[RX]: status=%x, length=%x\n", p->status, p->length);
    } else {
        memcpy(buf, p->data, p->length - 4);
        *length = p->length - 4;
    }

    p->status = (p->status & BD_RX_ST_WRAP) | BD_RX_ST_EMPTY;

    if (p->status & BD_RX_ST_WRAP) {
        p = dev->rx_bd;
    } else {
        p++;
    }

    dev->rx_cur = p;
    enet_reg->ECR |= ENET_ECR_ETHEREN(1);
    //enet_reg->RDAR |= ENET_RX_TX_ACTIVE;

    return 0;
}

int imx_enet_init(imx_enet_priv_t * dev, unsigned long reg_base, int phy_addr)
{

    dev->enet_reg = (ENET_Type *) reg_base;
    dev->tx_busy = 0;
    dev->status = 0;
    dev->phy_addr = phy_addr;   /* 0 or 1 */
    printf("Set up Ethernet Driver for PHY #%d\n", phy_addr);
    imx_enet_bd_init(dev, phy_addr); // Setup the Ethernet Driver
    printf("Set up MII Interface\n");
    imx_enet_chip_init(dev);  // Setup MII
    printf("Set up PHY device\n");
    imx_enet_phy_init(dev); // Engage the PHY and Reset the PHY
    return 0;
}

static void imx_enet_set_mac_address(volatile ENET_Type * enet_reg, unsigned char *enaddr)
{
    unsigned long value;

    value = enaddr[0];
    value = (value << 8) + enaddr[1];
    value = (value << 8) + enaddr[2];
    value = (value << 8) + enaddr[3];
    enet_reg->PALR = value;

    value = enaddr[4];
    value = (value << 8) + enaddr[5];
    enet_reg->PAUR = (value << 16);
}

void imx_enet_start(imx_enet_priv_t * dev, unsigned char *enaddr)
{
    volatile ENET_Type *enet_reg = dev->enet_reg;

    imx_enet_set_mac_address(dev->enet_reg, enaddr);

    dev->tx_busy = 0;
    enet_reg->ECR |= ENET_ECR_ETHEREN(1);

    dev->enet_reg->RDAR |= ENET_RX_TX_ACTIVE;
}

void imx_enet_stop(imx_enet_priv_t * dev)
{
    volatile ENET_Type *enet_reg = dev->enet_reg;
    enet_reg->ECR &= ~ENET_ECR_ETHEREN(1);
}

int imx_enet_isolate_phy(imx_enet_priv_t * dev)
{
    unsigned short value = 0;

    if (!imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
        value |= (0x01 << 10);
        if (!imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, value)) {
            return 0;
        }
    }
    return -1;
}

int imx_enet_unisolate_phy(imx_enet_priv_t * dev)
{
    unsigned short value = 0;

    if (!imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value)) {
        value &= ~(0x01 << 10);
        if (!imx_enet_mii_write(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, value)) {
            imx_enet_mii_read(dev->enet_reg, dev->phy_addr, PHY_CTRL_REG, &value);
            return 0;
        }
    }
    return -1;
}

int imx_enet_mii_type(imx_enet_priv_t * dev, enum imx_mii_type mii_type)
{
    volatile ENET_Type *enet_reg = dev->enet_reg;

    switch (mii_type) {
    case MII:
        /*clear RMII */
        printf("Selec MII mode\n");
        enet_reg->RCR &= ~(ENET_RCR_RMII_MODE(1));
        break;
    case RMII:
        /*set RMII */
        printf("Select RMII mode\n");
        enet_reg->RCR |= (ENET_RCR_RMII_MODE(1));
        printf("Select RMII mode - succesful\n");
        break;
    default:
        printf("BUG:unknown MII type=%x\n", mii_type);
        break;
    }
    return 0;
}
