void _fw_usb_suspend_reboot()
{
	/* reset usb/wlan dma */
	_fw_reset_dma_fifo();

	/* restore gpio setting and usb/wlan dma state */
	_fw_restore_dma_fifo();

	/* set clock to bypass mode - 40Mhz from XTAL */
	iowrite32(MAGPIE_REG_CPU_PLL_BYPASS_ADDR, BIT0 | BIT4);

	A_DELAY_USECS(100); /* wait for stable */

	iowrite32(MAGPIE_REG_CPU_PLL_ADDR, BIT16);

	A_DELAY_USECS(100); /* wait for stable */
	A_UART_HWINIT((40*1000*1000), 19200);

	A_CLOCK_INIT(40);

	if (!bEepromExist) { /* jump to flash boot (eeprom data in flash) */
		bJumptoFlash = TRUE;
		A_PRINTF("Jump to Flash BOOT\n");
		app_start();
	} else {
		A_PRINTF("receive the suspend command...\n");
		/* reboot..... */
		A_USB_JUMP_BOOT();
	}

}
static void _fw_power_off()
{
	/*
	 *  1. set CPU bypass
	 *  2. turn off CPU PLL
	 *  3. turn off ETH PLL
	 *  4. disable ETH PLL bypass and update
	 *  4.1 set suspend timeout 
	 *  5. set SUSPEND_ENABLE
	 */

	iowrite32(MAGPIE_REG_CPU_PLL_BYPASS_ADDR, BIT0 | BIT4);

	A_DELAY_USECS(100); // wait for stable

	iowrite32(MAGPIE_REG_CPU_PLL_ADDR, BIT16);

	A_DELAY_USECS(100); // wait for stable

	A_UART_HWINIT((40*1000*1000), 19200);
	A_CLOCK_INIT(40);

	io32_set(MAGPIE_REG_ETH_PLL_ADDR, BIT16);

	io32_set(MAGPIE_REG_ETH_PLL_BYPASS_ADDR, BIT4 | BIT0);

	io32_set(MAGPIE_REG_SUSPEND_ENABLE_ADDR, 0x10 << 8);
}
/*
 * -- patch zfTurnOffPower --
 *
 * . set suspend counter to non-zero value
 * . 
 */
void zfTurnOffPower_patch(void)
{
	A_PRINTF("+++ goto suspend ......\n");

	/* setting the go suspend here, power down right away */
	io32_set(0x10000, BIT3);

	A_DELAY_USECS(100);

	// TURN OFF ETH PLL
	_fw_power_off();

	//32clk wait for External ETH PLL stable
	A_DELAY_USECS(100);
    
	iowrite32(0x52000, 0x70303); /* read back 0x703f7 */
	iowrite32(0x52008, 0x0e91c); /* read back 0x1e948 */
    
	io32_set(MAGPIE_REG_SUSPEND_ENABLE_ADDR, BIT0);

	// wake up, and turn on cpu, eth, pcie and usb pll 
	_fw_power_on();
	// restore gpio and other settings
	_fw_restore_dma_fifo();

	/* clear suspend */
	io32_clr(MAGPIE_REG_SUSPEND_ENABLE_ADDR, BIT0);
	io32_clr(0x52028, BIT8 | BIT12 | BIT16);
}
/*
 * -- urn_off_merlin --
 * . values suggested from Lalit
 *
 */
static void turn_off_merlin()
{
	volatile uint32_t default_data[9];
	uint32_t i=0;

	if(1)
	{
		A_PRINTF("turn_off_merlin_ep_start ......\n");
		A_DELAY_USECS(measure_time);
		default_data[0] = 0x9248fd00;
		default_data[1] = 0x24924924;
		default_data[2] = 0xa8000019;
		default_data[3] = 0x17160820;
		default_data[4] = 0x25980560;
		default_data[5] = 0xc1c00000;
		default_data[6] = 0x1aaabe40;
		default_data[7] = 0xbe105554;
		default_data[8] = 0x00043007;
        
		for(i=0; i<9; i++)
		{
			A_DELAY_USECS(10);
        
			iowrite32(0x10ff4040, default_data[i]);
		}
		A_DELAY_USECS(10);
		iowrite32(0x10ff4044, BIT0);
		A_PRINTF("turn_off_merlin_ep_end ......\n");
	}
}
static void turn_off_phy_rc()
{
    
	volatile uint32_t default_data[9];
	uint32_t i=0;
    
	A_PRINTF("turn_off_phy_rc\n");
    
	default_data[0] = 0x9248fd00;
	default_data[1] = 0x24924924;
	default_data[2] = 0xa8000019;
	default_data[3] = 0x13160820;//PwdClk1MHz=0
	default_data[4] = 0x25980560;
	default_data[5] = 0xc1c00000;
	default_data[6] = 0x1aaabe40;
	default_data[7] = 0xbe105554;
	default_data[8] = 0x00043007;
        
	for(i=0; i<9; i++)
	{
		// check for the done bit to be set 
     
		while (1)
		{
			if (ioread32(0x40028) & BIT31)
				break;
		}

		A_DELAY_USECS(1);

		iowrite32(0x40024, default_data[i]);
	}
	iowrite32(0x40028, BIT0);
}
/**
 * @brief PCI reset 
 * XXX: Move this to RAM
 */ 
void
__pci_reset(void)
{
    volatile A_UINT32      r_data;
    
    /**
     * Poll until the Host has reset
     */ 
    A_PRINTF("Waiting for host reset..");
    for (;;) {
        r_data =  __pci_reg_read(MAG_REG_AHB_RESET);

        if ( r_data & PCI_AHB_RESET_DMA_HST_RAW)
            break;
    } 
    A_PRINTF("received.\n");

    /**
     * Pull the AHB out of reset
     */ 

    r_data = __pci_reg_read(MAG_REG_AHB_RESET);
    r_data &= ~PCI_AHB_RESET_DMA;
    __pci_reg_write(MAG_REG_AHB_RESET, r_data);

    A_DELAY_USECS(10);

    /**
     * Put the AHB into reset
     */ 
    
    r_data = __pci_reg_read(MAG_REG_AHB_RESET);
    r_data |= PCI_AHB_RESET_DMA;
    __pci_reg_write(MAG_REG_AHB_RESET, r_data);

    A_DELAY_USECS(10);
    
    /**
     * Pull the AHB out of reset
     */ 
    
    r_data = __pci_reg_read(MAG_REG_AHB_RESET);
    r_data &= ~PCI_AHB_RESET_DMA;
    __pci_reg_write(MAG_REG_AHB_RESET, r_data);

    A_DELAY_USECS(10);
}
void _fw_usbfifo_recv_command(VBUF *buf)
{
	A_UINT8 *cmd_data;
	A_UINT32 tmp;

	cmd_data = (A_UINT8 *)(buf->desc_list->buf_addr + buf->desc_list->data_offset);
	tmp = *((A_UINT32 *)cmd_data);
	if ( tmp == 0xFFFFFFFF ) {	
		// reset usb/wlan dma
		_fw_reset_dma_fifo();

		// restore gpio setting and usb/wlan dma state
		_fw_restore_dma_fifo();

		// set clock to bypass mode - 40Mhz from XTAL 
		HAL_WORD_REG_WRITE(MAGPIE_REG_CPU_PLL_BYPASS_ADDR, (BIT0|BIT4));

		A_DELAY_USECS(100); // wait for stable

		HAL_WORD_REG_WRITE(MAGPIE_REG_CPU_PLL_ADDR, (BIT16));

		A_DELAY_USECS(100); // wait for stable
		A_UART_HWINIT((40*1000*1000), 19200);

		A_CLOCK_INIT(40);

		if (!bEepromExist) { //jump to flash boot (eeprom data in flash)
			bJumptoFlash = TRUE;
			A_PRINTF("Jump to Flash BOOT\n");
			app_start();
		}else{
			A_PRINTF("receive the suspend command...\n");
			// reboot.....
			A_USB_JUMP_BOOT();	        
		}

	} else {
		m_origUsbfifoRecvCmd(buf);
	}
}
static void _fw_restore_dma_fifo(void)
{
	io32_clr(0x5601C, BIT18);
    
	/* reset pcie_rc shift */
	io32_clr(0x50010, BIT10 | BIT8 | BIT7);
	A_DELAY_USECS(1);
	io32_set(0x50010, BIT10 | BIT8 | BIT7);

	/* reset pci_rc phy */
	io32_set(MAGPIE_REG_RST_RESET_ADDR,
		 PCI_RC_PHY_SHIFT_RESET_BIT
		 | PCI_RC_PLL_RESET_BIT | PCI_RC_PHY_RESET_BIT
		 | PCI_RC_RESET_BIT);
	A_DELAY_USECS(20);

	// enable dma swap function
	MAGPIE_REG_USB_RX0_SWAP_DATA = 0x1;
	MAGPIE_REG_USB_TX0_SWAP_DATA = 0x1;
	MAGPIE_REG_USB_RX1_SWAP_DATA = 0x1;
	MAGPIE_REG_USB_RX2_SWAP_DATA = 0x1;
}
static void _fw_reset_dma_fifo()
{
	io8_set(0x100ae, 0x10);
	io8_set(0x100af, 0x10);
	A_PRINTF("_fw_reset_dma_fifo\n");

	// disable ep3 int enable, so that resume back won't send wdt magic pattern out!!!
	mUSB_STATUS_IN_INT_DISABLE();

	/* update magic pattern to indicate this is a suspend */
	iowrite32(WATCH_DOG_MAGIC_PATTERN_ADDR, SUS_MAGIC_PATTERN);

	A_PRINTF("org 0x4048  0x%x ......\n", ioread32(0x10ff4048));
	A_PRINTF("org 0x404C  0x%x ......\n", ioread32(0x10ff404C));
	A_PRINTF("org 0x4088  0x%x ......\n", ioread32(0x10ff4088));

	/* 1010.1010.1010.0110.1010 for UB94 */
	iowrite32(0x10ff4088, 0xaaa6a);
	iowrite32(0x10ff404C, 0x0);

	A_DELAY_USECS(1000);
	A_PRINTF("0x4048  0x%x ......\n", ioread32(0x10ff4048));
	A_PRINTF("0x404C  0x%x ......\n", ioread32(0x10ff404C));
	A_PRINTF("0x4088  0x%x ......\n", ioread32(0x10ff4088));
         
	// turn off merlin
	turn_off_merlin();
	// pcie ep
	A_PRINTF("turn_off_magpie_ep_start ......\n");
	A_DELAY_USECS(measure_time);
	io32_set(0x40040, BIT0 | BIT1);
	turn_off_phy();
	io32_clr(0x40040, BIT0 | BIT1);
	A_PRINTF("turn_off_magpie_ep_end ......\n");

	// pcie rc 
	A_PRINTF("turn_off_magpie_rc_start ......\n");
	A_DELAY_USECS(measure_time);
	io32_clr(0x40040, BIT0);
	turn_off_phy_rc();
	A_PRINTF("turn_off_magpie_rc_end ......down\n");
	A_DELAY_USECS(measure_time);

	A_PRINTF("0x4001C  %p ......\n", ioread32(0x4001c));
	A_PRINTF("0x40040  %p ......\n", ioread32(0x40040));
    
	/* turn off pcie_pll - power down (bit16) */
	A_PRINTF(" before pwd PCIE PLL CFG:0x5601C: 0x%08x\n",
		 ioread32(0x5601C));
	io32_set(0x5601C, BIT18);
	A_PRINTF(" after pwd PCIE PLL CFG:0x5601C:  0x%08x\n",
		 ioread32(0x5601C));

	/* set everything to reset state?, requested by Oligo */
	io32_set(0x50010, BIT13 | BIT12
		 | BIT11 | BIT9 | BIT7 | BIT6);

	iowrite32(0x5C000, 0);

	A_DELAY_USECS(10);

	/* reset usb DMA controller */
	iowrite32_usb(ZM_SOC_USB_DMA_RESET_OFFSET, 0x0);

	io32_set(0x50010, BIT4);
	A_DELAY_USECS(5);
	io32_clr(0x50010, BIT4);

	iowrite32_usb(ZM_SOC_USB_DMA_RESET_OFFSET, BIT0);
}
/*!- Initialize eeprom, actually we link up the pcie_rc for accessing the eeprom in client card
 *
 * Ryan - Add setup for PLL, refer to bug#37418
 *
 *  5. clear PCIE_RC_PLL PCIE_PHY_SHIFT, PCIE_PHY, PCIE_RC rst bit
 *  6. clear PCIE_PLL bypass mode and PWD bit (BIT16 and BIT18)
 *  7. set bus master and memory space enable 
 *  8. set app_ltssm_enable
 *
 *  200ns in each access
 *
 */
LOCAL void
cmnos_eep_init(void)
{
    uint32_t mStsData;
    volatile int32_t i = 10000;
    volatile reg_value = 0x0;

#if defined(PROJECT_MAGPIE)
    if( TRUE != eep_state )
    {
        DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x40;

        /* 5 */
#if defined(MAGPIE_FPGA)
        if (*(volatile uint32_t *)(WATCH_DOG_MAGIC_PATTERN_ADDR) == WDT_MAGIC_PATTERN )
        {
        // fpga will hang since external pcie_rc is not able to reset, do a wdt check here, and avoid toching pcie_rc phy reset
        // not know will real chip have same issue, ryan
        //
            DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x41;
        
/*        
    // Paddu sugguest to remove these, since PCIE_RC's reset state is 1 already
    //
            HAL_WORD_REG_WRITE(MAGPIE_REG_RST_RESET_ADDR,  \
                (HAL_WORD_REG_READ(MAGPIE_REG_RST_RESET_ADDR)|  \
                    (PCI_RC_PLL_RESET_BIT|PCI_RC_RESET_BIT)));

            A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);
            
            DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x42;
*/         
            HAL_WORD_REG_WRITE(MAGPIE_REG_RST_RESET_ADDR, \
                (HAL_WORD_REG_READ(MAGPIE_REG_RST_RESET_ADDR)&   \
                    (~(PCI_RC_PLL_RESET_BIT|PCI_RC_RESET_BIT))));

            A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);
        }
        else
#endif
        {
/*
     // Paddu sugguest to remove these, since PCIE_RC's reset state is 1 already
     // rom1.0 fix: looks like resetting the rc even already in reset state is fine 
     //             but this would fix the eeprom-less issue, when we do the 2n init
*/
            /* asser the reset to pcie_rc */
            DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x43;
            CMD_PCI_RC_RESET_ON();
            A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);

            /* dereset the reset */
            DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x44;
            CMD_PCI_RC_RESET_CLR();
            A_DELAY_USECS(500);
        }

/*!
 * Ryan - clr MAGPIE_REG_AHB_ARB_ADDR, BIT1 is needed no mater FPGA or ASIC
 */
//#if defined(MAGPIE_FPGA)
    // workaround for FPGA, do we need to enable the PCIE_RC DMA just for accessing the EEPROM?
    //HAL_WORD_REG_WRITE(0x00050018, 0x6);, purpose is to enable pcie_rc access internal memory
    //HAL_WORD_REG_WRITE(MAGPIE_REG_AHB_ARB_ADDR, (HAL_WORD_REG_READ(MAGPIE_REG_AHB_ARB_ADDR)|(BIT1|BIT2)));
        
        DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x49;
        HAL_WORD_REG_WRITE(MAGPIE_REG_AHB_ARB_ADDR,
            (HAL_WORD_REG_READ(MAGPIE_REG_AHB_ARB_ADDR)|(BIT1)));
    	A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);
//#endif

        /* 7.5. asser pcie_ep reset */
        HAL_WORD_REG_WRITE(0x00040018, (HAL_WORD_REG_READ(0x00040018) & ~(0x1 << 2))); 

#if defined(MAGPIE_ASIC)
        /* PLL setup should be ASIC/DV specific */
        /* 6. set PCIE_PLL in bypass mode, and get out of power-down,  */
        DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x50;
        HAL_WORD_REG_WRITE(MAGPIE_REG_PCIE_PLL_CONFIG_ADDR, \
            (HAL_WORD_REG_READ(MAGPIE_REG_PCIE_PLL_CONFIG_ADDR)&(~(BIT16|BIT18))));

        /* 100us delay wait for PCIE PLL stable */
        A_DELAY_USECS(100); 
#endif      

        /* 7. set bus master and memory space enable */
        DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x45;
        HAL_WORD_REG_WRITE(0x00020004, (HAL_WORD_REG_READ(0x00020004)|(BIT1|BIT2)));
        A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);

        /* 7.5. de-asser pcie_ep reset */
        HAL_WORD_REG_WRITE(0x00040018, (HAL_WORD_REG_READ(0x00040018)|(0x1 << 2)));
        A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);

        /* 8. set app_ltssm_enable */
        DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x46;
        HAL_WORD_REG_WRITE(0x00040000, (HAL_WORD_REG_READ(0x00040000)|0xffc1));
        
        /*!
         * Receive control (PCIE_RESET), 
         *  0x40018, BIT0: LINK_UP, PHY Link up -PHY Link up/down indicator
         *  in case the link up is not ready and we access the 0x14000000, 
         *  vmc will hang here
         */

        /* poll 0x40018/bit0 (1000 times) until it turns to 1 */
        while(i-->0)
        {
            reg_value = HAL_WORD_REG_READ(0x00040018);
            if( reg_value & BIT0 ) 
                break;
            A_DELAY_USECS(PCIE_RC_ACCESS_DELAY); 
        }

        /* init fail, can't detect PCI_RC LINK UP, give up the init */
        if( i<=0 )
        {
			DEBUG_SYSTEM_STATE |= BIT26;
            goto ERR_DONE;
        }

        DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x47;
        HAL_WORD_REG_WRITE(0x14000004, (HAL_WORD_REG_READ(0x14000004)|0x116));
        A_DELAY_USECS(PCIE_RC_ACCESS_DELAY);

        DEBUG_SYSTEM_STATE = (DEBUG_SYSTEM_STATE&(~0xff)) | 0x48;
        HAL_WORD_REG_WRITE(0x14000010, (HAL_WORD_REG_READ(0x14000010)|EEPROM_CTRL_BASE));
        eep_state = TRUE;
    }

#elif defined(PROJECT_K2)
    eep_state = TRUE;
#endif /* End of #if defined(PROJECT_MAGPIE) */
    if (TRUE == eep_state)
    {
        /* Read offset 1 location to determine if this EEPROM is protected somewhere */
        HAL_WORD_REG_READ(EEPROM_ADDR_BASE + 4);

    	while(1)
        {
            mStsData = HAL_WORD_REG_READ((EEPROM_CTRL_BASE+H_EEPROM_STS_DATA));

            /* If this location is protected or EEPROM does not exist, return immediately */
            if ( mStsData & (B_EEP_STS_PROTECTED | B_EEP_STS_DATA_NOT_EXIST) )
            {
                eep_state = FALSE;
                break;
            }

            if ( ( mStsData & (B_EEP_STS_STATE_BUSY | B_EEP_STS_IS_BUSY) ) == 0 )
            {
                if (mStsData & 0xffff)
                    cmnos_eeprom_write_hword( (uint16_t)1, (uint16_t)0 );

                break;
            }

    		A_DELAY_USECS(100);
        }
    }
ERR_DONE:
    
}


void
cmnos_eep_module_install(struct eep_api *tbl)
{
    tbl->_eep_init          = cmnos_eep_init;
    tbl->_eep_read          = cmnos_eep_read;
    tbl->_eep_write         = cmnos_eep_write;
    tbl->_eep_is_exist      = cmnos_eep_is_exist;
}