#include "platform.h"
#include "quad_flash.h"

#define	qflash_HW_SPI	DEV_SPI0

#define HW_SPI_PIN_H() { \
	while(!(qflash_HW_SPI->STA & DEV_SPIn_STA_TX_EMPTY)); \
	qflash_HW_SPI->CTL &= ~DEV_SPIn_CTL_SPI_CS_NSSLOW; \
}
#define HW_SPI_PIN_L() (qflash_HW_SPI->CTL |=  DEV_SPIn_CTL_SPI_CS_NSSLOW)


__OS1 __INIT uint8_t hw_spi0_rw(uint8_t data)
{
	uint8_t revalue;
	while(!(qflash_HW_SPI->STA&DEV_SPIn_STA_TX_EMPTY)){;}
	qflash_HW_SPI->TX_DATA = data;
	while(qflash_HW_SPI->STA&DEV_SPIn_STA_RX_EMPTY){;}
	revalue =  qflash_HW_SPI->RX_DATA;
	return revalue;
}

__OS1 __INIT static void hw_quad_flash_type0()
{

	uint8_t reg_status2;

	HW_SPI_PIN_L();
	hw_spi0_rw(__P25XX_ReadStatusReg2);
	reg_status2 = hw_spi0_rw(0xffUL);
	HW_SPI_PIN_H();

	if((reg_status2&0x02UL)==0)
	{
		HW_SPI_PIN_L();
		hw_spi0_rw(__P25XX_WriteEnable);
		HW_SPI_PIN_H();
		HW_SPI_PIN_L();
		hw_spi0_rw(__P25XX_WriteStatusReg2);
		hw_spi0_rw(reg_status2|0x02UL);
		HW_SPI_PIN_H();

		HW_SPI_PIN_L();
		hw_spi0_rw(__P25XX_ReadStatusReg1);

		while ((hw_spi0_rw(0xFFUL) & 0x01UL) != 0UL)
		{
			;
		}
		HW_SPI_PIN_H();
	}

}

__OS1 __INIT static void hw_quad_flash_type1()
{

	uint8_t reg_status1;

	HW_SPI_PIN_L();
	hw_spi0_rw(__EN25X_EnteOTP);
	HW_SPI_PIN_H();

	HW_SPI_PIN_L();
	hw_spi0_rw(__EN25XX_ReadStatusReg);
	reg_status1 = hw_spi0_rw(0xffUL);
	HW_SPI_PIN_H();
	if((reg_status1&0x40UL)==0)
	{
		HW_SPI_PIN_L();
		hw_spi0_rw(__EN25XX_WriteEnable);
		HW_SPI_PIN_H();
		HW_SPI_PIN_L();
		hw_spi0_rw(__EN25XX_WriteStatusReg);
		hw_spi0_rw(reg_status1|0x40UL);

		HW_SPI_PIN_H();
		HW_SPI_PIN_L();
		hw_spi0_rw(__EN25XX_ReadStatusReg);

		while ((hw_spi0_rw(0xFFUL) & 0x01UL) != 0UL)
		{
			;
		}
		HW_SPI_PIN_H();
	}

	HW_SPI_PIN_L();
	hw_spi0_rw(__EN25X_ExitOTP);
	HW_SPI_PIN_H();
}

__OS1 __INIT static void hw_quad_flash_type2()
{

	uint8_t reg_status1,reg_status2;

//	HW_SPI_PIN_L();
//	hw_spi0_rw(__EN25X_EnteOTP);
//	HW_SPI_PIN_H();

	HW_SPI_PIN_L();
	hw_spi0_rw(__EN25XX_ReadStatusReg);//0x05
	reg_status1 = hw_spi0_rw(0xffUL);
	HW_SPI_PIN_H();

	HW_SPI_PIN_L();
	hw_spi0_rw(__BY25XX_ReadStatusReg2);//0x35
	reg_status2 = hw_spi0_rw(0xffUL);
	HW_SPI_PIN_H();


	//if((reg_status2 & 0x02UL)==0)
	{
		HW_SPI_PIN_L();
		hw_spi0_rw(__EN25XX_WriteEnable);//0X06
		HW_SPI_PIN_H();

		HW_SPI_PIN_L();
		hw_spi0_rw(__EN25XX_WriteStatusReg);//0X01
		hw_spi0_rw(reg_status1);
		hw_spi0_rw(reg_status2|0x02UL);
		HW_SPI_PIN_H();

		HW_SPI_PIN_L();
		hw_spi0_rw(__EN25XX_ReadStatusReg);

		while ((hw_spi0_rw(0xFFUL) & 0x01UL) != 0UL)
		{
			;
		}
		HW_SPI_PIN_H();
	}

//	HW_SPI_PIN_L();
//	hw_spi0_rw(__EN25X_ExitOTP);
//	HW_SPI_PIN_H();
}

__INIT __OS1 void NORCTRL_QuadSPIinit(uint32_t flash_type,qflash_pin_info_t* pin_info)
{

	DEV_RMU->RSTEN0 |= DEV_RMU_RSTEN0_SPI0;
	DEV_CMU->CLKEN0 |= DEV_CMU_CLKEN0_SPI0;

	DEV_CMU->SPInCLK[0] = DEV_CMU_SPInCLK_SEL_OSC_DEV | DEV_CMU_SPInCLK_DIV_4;

	DEV_GPIO->CTL[pin_info->sck] 	= pin_info->spi_mfp;
	DEV_GPIO->CTL[pin_info->nss] 	= pin_info->spi_mfp;
	DEV_GPIO->CTL[pin_info->dat0] 	= pin_info->spi_mfp;
	DEV_GPIO->CTL[pin_info->dat1] 	= pin_info->spi_mfp;
	DEV_GPIO->CTL[pin_info->dat2] 	= DEV_GPIO_CTL_PE_ENABLE | DEV_GPIO_CTL_PS_PULLUP;
	DEV_GPIO->CTL[pin_info->dat3] 	= DEV_GPIO_CTL_PE_ENABLE | DEV_GPIO_CTL_PS_PULLUP;

	qflash_HW_SPI->CTL = DEV_SPIn_CTL_SPI_TX_EN_ENABLE
						|DEV_SPIn_CTL_SPI_RX_EN_ENABLE
						|DEV_SPIn_CTL_SPI_WIDTH_SINGLE
						|DEV_SPIn_CTL_MS_MODE_MASTER
						|DEV_SPIn_CTL_SPI_MODE_MODE0
						|(8<<19)|(8<<24);

	qflash_HW_SPI->CTL |= DEV_SPIn_CTL_RX_FIFO_RST_RESET | DEV_SPIn_CTL_TX_FIFO_RST_RESET;
	qflash_HW_SPI->CTL &= ~(DEV_SPIn_CTL_RX_FIFO_RST_RESET | DEV_SPIn_CTL_TX_FIFO_RST_RESET);
	qflash_HW_SPI->PD = DEV_SPIn_PD_RX_UF;
	qflash_HW_SPI->CTL |= DEV_SPIn_CTL_SPI_EN_ENABLE;

	if(flash_type==0)
	{
		hw_quad_flash_type0();
	}
	else if(flash_type==1)
	{
		hw_quad_flash_type1();
	}
	else if(flash_type==2)
	{
		hw_quad_flash_type2();
	}

	DEV_GPIO->CTL[pin_info->sck]	= pin_info->nor_mfp;
	DEV_GPIO->CTL[pin_info->nss]	= pin_info->nor_mfp;
	DEV_GPIO->CTL[pin_info->dat0] 	= pin_info->nor_mfp;
	DEV_GPIO->CTL[pin_info->dat1] 	= pin_info->nor_mfp;
	DEV_GPIO->CTL[pin_info->dat2] 	= pin_info->nor_mfp | DEV_GPIO_CTL_PE_ENABLE | DEV_GPIO_CTL_PS_PULLUP;
	DEV_GPIO->CTL[pin_info->dat3] 	= pin_info->nor_mfp | DEV_GPIO_CTL_PE_ENABLE | DEV_GPIO_CTL_PS_PULLUP;
}

