#include "abstract.h"
#include "mcu_settings.h"
#include "base_types.h"
#include "hsspi_flash.h"
#include "bsp_ddrhsspi.h"

static void ClearWatchdog(void)
{
    // Satisfy compiler regarding "order of volatile accesses" warning in if-statement
    uint32_t u32CurrentLowerLimit = HWDG_RUNLLC; 
    
    // Clear hardware watchdog if lower limit of window has been exceeded
    if (HWDG_CNT > u32CurrentLowerLimit)
    {
        IRQ_DISABLE_LOCAL();
        HWDG_TRG0 = HWDG_TRG0CFG;
        HWDG_TRG1 = HWDG_TRG1CFG;
        IRQ_RESTORE();
    }
}

/******************************************************************************
 ** \brief hsspi_SingleErase_4K
 **
 ** \param [in] Address      DDRHSSPI address 0x4XXXXXXX
 **
 ** \return Execution result
 ** \retval FLASH_OK  
 ** \retval FLASH_ADDR_RANGE_ERR  :Outside the address range the address must be within 0x40000000~0x44000000.
 ** \retval FLASH_ADDR_ALIGN_ERR  :The address must be even
 **
 *****************************************************************************/
uint8_t hsspi_SingleErase_4K(uint32_t Address)
{
    int8_t i = 0;
    uint8_t addr; 
    uint32_t address = Address;
    if(Address < 0x80000000 || Address > 0x84000000)
      return FLASH_ADDR_RANGE_ERR;
    if(Address % 2 == 1)
      return FLASH_ADDR_ALIGN_ERR;
    
    hsspi_CheckQuadBitSingle_GigaDevice();
   
    ClearWatchdog();
    
    address -= 0x80000000;
    
    hsspi_WriteEnable();
    /******** Transfer in Direct Mode (Command:21)********   LC[7:6]=0 EEh:Dummy=6 , QUAD[1]=1 Quad*/
    DDRHSSPI0_DMBCC = 5;        /*2.[bit15:0] Byte Count Control = 6*/
    DDRHSSPI0_TXFIFO0 = 0x00001021;  /*  ERASE Flash. 21h*/
    
    for(i = 3; i >= 0 ; i--)    //4 byte address
    {
        addr = (address >> (i * 8)) & 0xff;
        DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
    }
    DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
    while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
        ClearWatchdog();
    }
    return FLASH_OK;
}

/******************************************************************************
 ** \brief hsspi_SingleErase_32K
 **
 ** \param [in] Address      DDRHSSPI address 0x4XXXXXXX
 **
 ** \return Execution result
 ** \retval FLASH_OK  
 ** \retval FLASH_ADDR_RANGE_ERR  :Outside the address range the address must be within 0x40000000~0x44000000.
 ** \retval FLASH_ADDR_ALIGN_ERR  :The address must be even
 **
 *****************************************************************************/
uint8_t hsspi_SingleErase_32K(uint32_t Address, uint8_t AddrType)
{
    int8_t i = 0;
    uint8_t addr; 
    uint32_t address = Address;
    if(Address < 0x80000000 || Address > 0x84000000)
      return FLASH_ADDR_RANGE_ERR;
    if(Address % 2 == 1)
      return FLASH_ADDR_ALIGN_ERR;
    
    /*DDRHSSPI    Cypress S25FL256S*/
    /******** Direct Mode Configuration ********   Figure 4-11 Programmer's Flowchart: DDRHSSPI in Direct Mode of Operation*/
    DDRHSSPI0_PCC0 =  0x00010220;    /*1.[bit20:16]Slave Selection De-Assertion Timeout = 1: SDR = 4 x SCLK cycle, DDR = 3.5 x SCLK cycle(Minimum setting)*/
    /*  [bit12:9] Clock Division = 1: Divide by 4. SCLK:60MHz*/
    /*  [bit6:5]  Slave Select to Clock Delay = 1: 1.75 SCLK*/
    DDRHSSPI0_MCTRL = 0x00000000;    /*1.[bit1]    Command Sequencer Mode Enable = 0: Direct Mode is enabled. Command Sequencer Mode is disabled.*/
    DDRHSSPI0_DMTRP = 0x00;          /*2.[bit5]    SDR Mode*/
    /*  [bit3:0]  Transfer Protocol: TX-and-RX in Legacy Mode is configured.*/
    DDRHSSPI0_DMFIFOCFG = 0x001C080F;/*3.[bit20]   TX-FIFO Flush = 1: Writing "1" flushes the TX-FIFO and TX Shift Register.*/
    /*  [bit19]   RX-FIFO Flush = 1: Writing "1" flushes the RX-FIFO and RX Shift Register.*/
    /*  [bit18]   TXCTRL Bit to be Written to TX-FIFO*/
    /*  [bit17:16]FIFO Width = 0: TX-FIFO, RX-FIFO and Shift-Register are 8-bit wide.*/
    /*  [bit12:8] TX-FIFO Threshold Level = 8*/
    /*  [bit4:0]  RX-FIFO Threshold Level = 15*/
    DDRHSSPI0_TXE = 0x0;             /*  TX interrupts are not used.*/
    DDRHSSPI0_RXE = 0x0;             /*  RX interrupts are not used.*/
    DDRHSSPI0_TXC = 0x00000077;      /*  TX interrupt flags are cleared.*/
    DDRHSSPI0_RXC = 0x000000FB;      /*  RX interrupt flags are cleared.*/
    DDRHSSPI0_DMPSEL = 0x0;          /*  [bit1:0]  Peripheral Select = 0: oDDRHSSPIn_SSEL0 is asserted.*/
    DDRHSSPI0_MCTRL = 0x00000001;    /*5.[bit0]    Module Enable = 1: DDRHSSPI is enabled.*/
    DDRHSSPI0_DMCFG = 0x02;          /*Figure 4-10 Programmer's Flowchart: General Steps 3.*/
    /*  [bit1]   Slave Select De-Assertion Control = 1: Byte Counter Mode. DDRHSSPIn_DMBCC.BCC is used to decide when to de-assert the Slave Select.*/
    
    bsp_HDOG_Feed();
   
    ClearWatchdog();
    
    address -= 0x80000000;
    if(FlashType == WINBOND_64M)
    {
        bsp_HDOG_Feed();
        /******** Transfer in Direct Mode (Command:F0)********/
        DDRHSSPI0_DMBCC = 0x0002;        /*2.[bit15:0] Byte Count Control = 2*/
        DDRHSSPI0_TXFIFO0 = 0x00001066;  /*  QUAD Flash. Software Reset Command (RESET F0h)*/
        DDRHSSPI0_TXFIFO0 = 0x00001000;
        DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
        while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
            ;
        }
        DDRHSSPI0_DMBCC = 0x0002;        /*2.[bit15:0] Byte Count Control = 2*/
        DDRHSSPI0_TXFIFO0 = 0x00001099;  /*  QUAD Flash. Software Reset Command (RESET F0h)*/
        DDRHSSPI0_TXFIFO0 = 0x00001000;
        DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
        while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
            ;
        }
		DelayMs(20);
    }
    
    
    
    hsspi_WriteEnable();
   
	if(AddrType == 1)
	{
		/******** Transfer in Direct Mode (Command:21)********   LC[7:6]=0 EEh:Dummy=6 , QUAD[1]=1 Quad*/
		DDRHSSPI0_DMBCC = 5;        /*2.[bit15:0] Byte Count Control = 6*/
		if(FlashType == WINBOND_256M)
		{
			DDRHSSPI0_TXFIFO0 = 0x00001052;  /*  ERASE Flash. 52h*/
		}
		else
		{
			DDRHSSPI0_TXFIFO0 = 0x0000105c;  /*  ERASE Flash. 5ch*/
		}
		
		for(i = 3; i >= 0 ; i--)    //4 byte address
		{
			addr = (address >> (i * 8)) & 0xff;
			DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
		}
	}
	else
	{
		/******** Transfer in Direct Mode (Command:21)********   LC[7:6]=0 EEh:Dummy=6 , QUAD[1]=1 Quad*/
		DDRHSSPI0_DMBCC = 4;        /*2.[bit15:0] Byte Count Control = 6*/
		DDRHSSPI0_TXFIFO0 = 0x00001052;  /*  ERASE Flash. 52h*/
		
		for(i = 2; i >= 0 ; i--)    //3 byte address
		{
			addr = (address >> (i * 8)) & 0xff;
			DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
		}
	}
    DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
    while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
        ClearWatchdog();
    }
    return FLASH_OK;
}
/******************************************************************************
 ** \brief hsspi_SingleErase_64K
 **
 ** \param [in] Address      DDRHSSPI address 0x4XXXXXXX
 **
 ** \return Execution result
 ** \retval FLASH_OK  
 ** \retval FLASH_ADDR_RANGE_ERR  :Outside the address range the address must be within 0x40000000~0x44000000.
 ** \retval FLASH_ADDR_ALIGN_ERR  :The address must be even
 **
 *****************************************************************************/
uint8_t hsspi_SingleErase_64K(uint32_t Address)
{
    int8_t i = 0;
    uint8_t addr; 
    uint32_t address = Address;
    if(Address < 0x80000000 || Address > 0x84000000)
      return FLASH_ADDR_RANGE_ERR;
    if(Address % 2 == 1)
      return FLASH_ADDR_ALIGN_ERR;
    
    hsspi_CheckQuadBitSingle_GigaDevice();
   
    ClearWatchdog();
    
    address -= 0x80000000;
    
    hsspi_WriteEnable();
    /******** Transfer in Direct Mode (Command:21)********   LC[7:6]=0 EEh:Dummy=6 , QUAD[1]=1 Quad*/
    DDRHSSPI0_DMBCC = 5;        /*2.[bit15:0] Byte Count Control = 6*/
    DDRHSSPI0_TXFIFO0 = 0x000010DC;  /*  ERASE Flash. Dch*/
    
    for(i = 3; i >= 0 ; i--)    //4 byte address
    {
        addr = (address >> (i * 8)) & 0xff;
        DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
    }
    DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
    while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
        ClearWatchdog();
    }
    return FLASH_OK;
}
/******************************************************************************
 ** \brief hsspi_SingleErase_CHIP
 **
 ** \param [in] Address      DDRHSSPI address 0x4XXXXXXX
 **
 ** \return Execution result
 ** \retval FLASH_OK  
 ** \retval FLASH_ADDR_RANGE_ERR  :Outside the address range the address must be within 0x40000000~0x44000000.
 ** \retval FLASH_ADDR_ALIGN_ERR  :The address must be even
 **
 *****************************************************************************/
uint8_t hsspi_SingleErase_CHIP(void)
{
    /*DDRHSSPI    Cypress S25FL256S*/
    /******** Direct Mode Configuration ********   Figure 4-11 Programmer's Flowchart: DDRHSSPI in Direct Mode of Operation*/
    DDRHSSPI0_PCC0 =  0x00010220;    /*1.[bit20:16]Slave Selection De-Assertion Timeout = 1: SDR = 4 x SCLK cycle, DDR = 3.5 x SCLK cycle(Minimum setting)*/
    /*  [bit12:9] Clock Division = 1: Divide by 4. SCLK:60MHz*/
    /*  [bit6:5]  Slave Select to Clock Delay = 1: 1.75 SCLK*/
    DDRHSSPI0_MCTRL = 0x00000000;    /*1.[bit1]    Command Sequencer Mode Enable = 0: Direct Mode is enabled. Command Sequencer Mode is disabled.*/
    DDRHSSPI0_DMTRP = 0x00;          /*2.[bit5]    SDR Mode*/
    /*  [bit3:0]  Transfer Protocol: TX-and-RX in Legacy Mode is configured.*/
    DDRHSSPI0_DMFIFOCFG = 0x001C080F;/*3.[bit20]   TX-FIFO Flush = 1: Writing "1" flushes the TX-FIFO and TX Shift Register.*/
    /*  [bit19]   RX-FIFO Flush = 1: Writing "1" flushes the RX-FIFO and RX Shift Register.*/
    /*  [bit18]   TXCTRL Bit to be Written to TX-FIFO*/
    /*  [bit17:16]FIFO Width = 0: TX-FIFO, RX-FIFO and Shift-Register are 8-bit wide.*/
    /*  [bit12:8] TX-FIFO Threshold Level = 8*/
    /*  [bit4:0]  RX-FIFO Threshold Level = 15*/
    DDRHSSPI0_TXE = 0x0;             /*  TX interrupts are not used.*/
    DDRHSSPI0_RXE = 0x0;             /*  RX interrupts are not used.*/
    DDRHSSPI0_TXC = 0x00000077;      /*  TX interrupt flags are cleared.*/
    DDRHSSPI0_RXC = 0x000000FB;      /*  RX interrupt flags are cleared.*/
    DDRHSSPI0_DMPSEL = 0x0;          /*  [bit1:0]  Peripheral Select = 0: oDDRHSSPIn_SSEL0 is asserted.*/
    DDRHSSPI0_MCTRL = 0x00000001;    /*5.[bit0]    Module Enable = 1: DDRHSSPI is enabled.*/
    DDRHSSPI0_DMCFG = 0x02;          /*Figure 4-10 Programmer's Flowchart: General Steps 3.*/
    /*  [bit1]   Slave Select De-Assertion Control = 1: Byte Counter Mode. DDRHSSPIn_DMBCC.BCC is used to decide when to de-assert the Slave Select.*/
    
    bsp_HDOG_Feed();
   
    ClearWatchdog();
    
    hsspi_WriteEnable();
    /******** Transfer in Direct Mode (Command:21)********   LC[7:6]=0 EEh:Dummy=6 , QUAD[1]=1 Quad*/
    DDRHSSPI0_DMBCC = 1;        /*2.[bit15:0] Byte Count Control = 6*/
    DDRHSSPI0_TXFIFO0 = 0x00001060;  /*  ERASE Flash. C7/60h*/
  
    DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
    while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
        ClearWatchdog();
    }
    return FLASH_OK;
}

/******************************************************************************
 ** \brief hsspi_QuadProgram
 **
 ** \param [in] Address      DDRHSSPI address 0x4XXXXXXX
 ** \param [in] data      Pointer to transmit buffer
 ** \param [in] TxSize    Number of data bytes to transmit
 **
 ** \return Execution result
 ** \retval FLASH_OK  
 ** \retval FLASH_ADDR_RANGE_ERR  :Outside the address range the address must be within 0x40000000~0x44000000.
 ** \retval FLASH_ADDR_ALIGN_ERR  :The address must be even
 ** \retval FLASH_SIZE_ERR  :The size must be even
 **
 *****************************************************************************/
uint8_t hsspi_QuadProgram(uint32_t Address, uint8_t *data, uint32_t TxSize, uint8_t AddrType)
{
	int16_t i = 0;
	uint32_t Length = 0;
	uint8_t addr; 
	uint16_t Count;
	uint32_t address = Address;
	uint8_t temp;
	
	if(Address < 0x80000000 || Address > 0x84000000)
		return FLASH_ADDR_RANGE_ERR;
	
	/******** Direct Mode Configuration ********/
	DDRHSSPI0_PCC0 =  0x00010420;    /*1.[bit20:16]Slave Selection De-Assertion Timeout = 1: SDR = 4 x SCLK cycle, DDR = 3.5 x SCLK cycle(Minimum setting)*/
	/*  [bit12:9] Clock Division = 0: Divide by 2. SCLK:60MHz*/
	/*  [bit6:5]  Slave Select to Clock Delay = 1: 1.75 SCLK*/
	DDRHSSPI0_MCTRL = 0x00000000;    /*1.[bit1]    Command Sequencer Mode Enable = 0: Direct Mode is enabled. Command Sequencer Mode is disabled.*/
	DDRHSSPI0_DMTRP = 0x0A;          /*2.[bit5]    SDR Mode*/
	/*  [bit3:0]  Transfer Protocol: TX-Only in Quad Mode is configured.*/
	DDRHSSPI0_DMFIFOCFG = 0x001C080F;/*3.[bit20]   TX-FIFO Flush = 1: Writing "1" flushes the TX-FIFO and TX Shift Register.*/
	/*  [bit19]   RX-FIFO Flush = 1: Writing "1" flushes the RX-FIFO and RX Shift Register.*/
	/*  [bit18]   TXCTRL Bit to be Written to TX-FIFO*/
	/*  [bit17:16]FIFO Width = 0: TX-FIFO, RX-FIFO and Shift-Register are 8-bit wide.*/
	/*  [bit12:8] TX-FIFO Threshold Level = 8*/
	/*  [bit4:0]  RX-FIFO Threshold Level = 15*/
	DDRHSSPI0_TXE = 0x0;             /*  TX interrupts are not used.*/
	DDRHSSPI0_RXE = 0x0;             /*  RX interrupts are not used.*/
	DDRHSSPI0_TXC = 0x00000077;      /*  TX interrupt flags are cleared.*/
	DDRHSSPI0_RXC = 0x000000FB;      /*  RX interrupt flags are cleared.*/
	DDRHSSPI0_DMPSEL = 0x0;          /*  [bit1:0]  Peripheral Select = 0: oDDRHSSPIn_SSEL0 is asserted.*/
	DDRHSSPI0_MCTRL = 0x00000001;    /*5.[bit0]    Module Enable = 1: DDRHSSPI is enabled.*/
	DDRHSSPI0_DMCFG = 0x02;          /*Figure 4-10 Programmer's Flowchart: General Steps 3.*/
	ClearWatchdog();
	
	address -=0x80000000;  //flash chip address
	
	if(address % 256 != 0)
	{
		hsspi_WriteEnable();
		
		DDRHSSPI0_DMTRP = 0x0A;         
		
		if(AddrType == 1)
		{
			DDRHSSPI0_DMBCC = 256 - address % 256 + 5;     
			Count = 256 - address % 256;
			
			
			DDRHSSPI0_TXFIFO0 = 0x00001034;  /*  quad page program Flash. 34h*/
			
			for(i = 3; i >= 0 ; i--)    //4 byte address
			{
				addr = (address >> (i * 8)) & 0xff;
				DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
			}
		}
		else
		{
			DDRHSSPI0_DMBCC = 256 - address % 256 + 4;     
			Count = 256 - address % 256;
			
			
			DDRHSSPI0_TXFIFO0 = 0x00001032;  /*  quad page program Flash. 34h*/
			
			for(i = 2; i >= 0 ; i--)    //4 byte address
			{
				addr = (address >> (i * 8)) & 0xff;
				DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
			}
		}
		
		DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
		
		i = 0;
		while(i < Count)
		{
			if(DDRHSSPI0_DMFIFOSTATUS_TXFLEVEL < 8)
			{
				temp = *(data + i + Length);
				DDRHSSPI0_TXFIFO0 = 0x00001200 | temp;
				i++;
			}
		}
		while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
			ClearWatchdog();
		}
		
		Length += Count; 
		address += Count;
		
		DDRHSSPI0_DMTRP = 0x00;          /*2.[bit5]    SDR Mode*/
		/*  [bit3:0]  Transfer Protocol: TX-and-RX in Octal Mode is configured.*/
		while(hsspi_CheckBusy() == FLASH_BUSY)
		{
		}
	}
	
	while(TxSize > Length)
	{
		hsspi_WriteEnable();
		
		DDRHSSPI0_DMTRP = 0x0A;          /*2.[bit5]    SDR Mode*/
		/*  [bit3:0]  Transfer Protocol: TX-Only in Quad Mode is configured.*/
		if(AddrType == 1)
		{
			if((TxSize - Length) > 256)
			{
				/******** Transfer in Direct Mode (Command:c7)********   LC[7:6]=0 EEh:Dummy=6 , QUAD[1]=1 Quad*/
				DDRHSSPI0_DMBCC = 256 + 5;        /*2.[bit15:0] Byte Count Control = 2*/
				Count = 256;
			}
			else
			{
				DDRHSSPI0_DMBCC = TxSize - Length + 5;
				Count = TxSize - Length;
			}
			
			DDRHSSPI0_TXFIFO0 = 0x00001034;  /*  quad page program Flash. 34h*/
			
			for(i = 3; i >= 0 ; i--)    //4 byte address
			{
				addr = (address >> (i * 8)) & 0xff;
				DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
			}
		}
		else
		{
			if((TxSize - Length) > 256)
			{
				/******** Transfer in Direct Mode (Command:c7)********   LC[7:6]=0 EEh:Dummy=6 , QUAD[1]=1 Quad*/
				DDRHSSPI0_DMBCC = 256 + 4;        /*2.[bit15:0] Byte Count Control = 2*/
				Count = 256;
			}
			else
			{
				DDRHSSPI0_DMBCC = TxSize - Length + 4;
				Count = TxSize - Length;
			}
			
			DDRHSSPI0_TXFIFO0 = 0x00001032;  /*  quad page program Flash. 34h*/
			
			for(i = 2; i >= 0 ; i--)    //4 byte address
			{
				addr = (address >> (i * 8)) & 0xff;
				DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
			}
		}
		
		DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
		
		i = 0;
		while(i < Count)
		{
			if(DDRHSSPI0_DMFIFOSTATUS_TXFLEVEL < 8)
			{
				temp = *(data + i + Length);
				DDRHSSPI0_TXFIFO0 = 0x00001200 | temp;
				i++;
			}
		}
		while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
			ClearWatchdog();
		}
		
		Length += Count; 
		address += Count;
		
		DDRHSSPI0_DMTRP = 0x00;          /*2.[bit5]    SDR Mode*/
		/*  [bit3:0]  Transfer Protocol: TX-and-RX in Octal Mode is configured.*/
		while(hsspi_CheckBusy() == FLASH_BUSY)
		{
		}
	}
	return FLASH_OK;
}

void hsspi_WriteEnable(void)
{
    /******** Transfer in Direct Mode (Command:06)********/
    DDRHSSPI0_DMBCC = 0x0001;        /*2.[bit15:0] Byte Count Control = 2*/
    DDRHSSPI0_TXFIFO0 = 0x00001006;  /*  QUAD Flash. Write Enable (WREN 06h)*/
    DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
    while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
        ClearWatchdog();
    }
}

uint8_t hsspi_CheckBusy(void)
{
    unsigned int RXFIFO[2];
    
    /*Check completion of writing of two QUAD Flashs*/
    DDRHSSPI0_DMFIFOCFG_TXFLSH = 1;  /*  TX-FIFO Flush = 1: Writing "1" flushes the TX-FIFO and TX Shift Register.*/
    DDRHSSPI0_DMFIFOCFG_RXFLSH = 1;  /*  RX-FIFO Flush = 1: Writing "1" flushes the RX-FIFO and RX Shift Register.*/

/******** Transfer in Direct Mode (Command:05)********/
    DDRHSSPI0_DMBCC = 0x0002;        /*2.[bit15:0] Byte Count Control = 4*/
    //DDRHSSPI0_TXFIFO0 = 0x00001081;  /*  QUAD Flash. READ EXTENDED READ PARAMETERS OPERATION (RDERP, 81h)*//*  WIP(Write in Progress) bit is checked.*/
    //DDRHSSPI0_TXFIFO0 = 0x00001000;  /*  Get 1 byte of register data.*/
    DDRHSSPI0_TXFIFO0 = 0x00001005;  /*  QUAD Flash. Read Status Register-1 (RDSR1 05h)*//*  WIP(Write in Progress) bit is checked.*/
    DDRHSSPI0_TXFIFO0 = 0x00001000;  /*  Get 1 byte of register data.*/
    DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
    while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
        ClearWatchdog();
    }

    RXFIFO[0] = DDRHSSPI0_RXFIFO0;  /*Read Instruction part*/
    RXFIFO[1] = DDRHSSPI0_RXFIFO1;
    //RXFIFO[2] = DDRHSSPI0_RXFIFO2;  /*Read Configuration Register part*/
    //RXFIFO[3] = DDRHSSPI0_RXFIFO3;
    ClearWatchdog();

    if(((RXFIFO[1] & 0x01) == 0x0))// && ((RXFIFO[3] & 0x01) == 0x0))
    {
        return FLASH_OK;
    }
    else
    {
        return FLASH_BUSY;
    }
}

void hsspi_DisProtectBit(void)
{
    uint8_t RXFIFO[2];
    
    /*DDRHSSPI    Cypress S25FL256S*/
    /******** Direct Mode Configuration ********   Figure 4-11 Programmer's Flowchart: DDRHSSPI in Direct Mode of Operation*/
    DDRHSSPI0_PCC0 =  0x00010020;    /*1.[bit20:16]Slave Selection De-Assertion Timeout = 1: SDR = 4 x SCLK cycle, DDR = 3.5 x SCLK cycle(Minimum setting)*/
    /*  [bit12:9] Clock Division = 1: Divide by 4. SCLK:60MHz*/
    /*  [bit6:5]  Slave Select to Clock Delay = 1: 1.75 SCLK*/
    DDRHSSPI0_MCTRL = 0x00000000;    /*1.[bit1]    Command Sequencer Mode Enable = 0: Direct Mode is enabled. Command Sequencer Mode is disabled.*/
    DDRHSSPI0_DMTRP = 0x00;          /*2.[bit5]    SDR Mode*/
    /*  [bit3:0]  Transfer Protocol: TX-and-RX in Legacy Mode is configured.*/
    DDRHSSPI0_DMFIFOCFG = 0x001C080F;/*3.[bit20]   TX-FIFO Flush = 1: Writing "1" flushes the TX-FIFO and TX Shift Register.*/
    /*  [bit19]   RX-FIFO Flush = 1: Writing "1" flushes the RX-FIFO and RX Shift Register.*/
    /*  [bit18]   TXCTRL Bit to be Written to TX-FIFO*/
    /*  [bit17:16]FIFO Width = 0: TX-FIFO, RX-FIFO and Shift-Register are 8-bit wide.*/
    /*  [bit12:8] TX-FIFO Threshold Level = 8*/
    /*  [bit4:0]  RX-FIFO Threshold Level = 15*/
    DDRHSSPI0_TXE = 0x0;             /*  TX interrupts are not used.*/
    DDRHSSPI0_RXE = 0x0;             /*  RX interrupts are not used.*/
    DDRHSSPI0_TXC = 0x00000077;      /*  TX interrupt flags are cleared.*/
    DDRHSSPI0_RXC = 0x000000FB;      /*  RX interrupt flags are cleared.*/
    DDRHSSPI0_DMPSEL = 0x0;          /*  [bit1:0]  Peripheral Select = 0: oDDRHSSPIn_SSEL0 is asserted.*/
    DDRHSSPI0_MCTRL = 0x00000001;    /*5.[bit0]    Module Enable = 1: DDRHSSPI is enabled.*/
    DDRHSSPI0_DMCFG = 0x02;          /*Figure 4-10 Programmer's Flowchart: General Steps 3.*/
    /*  [bit1]   Slave Select De-Assertion Control = 1: Byte Counter Mode. DDRHSSPIn_DMBCC.BCC is used to decide when to de-assert the Slave Select.*/
    
    bsp_HDOG_Feed();
   
    ClearWatchdog();
    
    /******** Transfer in Direct Mode (Command:06)********/
    DDRHSSPI0_DMBCC = 0x0001;        /*2.[bit15:0] Byte Count Control = 2*/
    DDRHSSPI0_TXFIFO0 = 0x00001006;  /*  QUAD Flash. Write Enable (WREN 06h)*/
    DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
    while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
        ;
    }
    
    /******** Transfer in Direct Mode (Command:83)********/
    DDRHSSPI0_DMBCC = 0x0002;        /*2.[bit15:0] Byte Count Control = 4*/
    DDRHSSPI0_TXFIFO0 = 0x00001056;  /*  QUAD Flash. Write VDLR (WVDLR 83h)*/
    DDRHSSPI0_TXFIFO0 = 0x00001008;
    DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
    while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
        ;
    }
}


uint8_t hsspi_QuadCheck(uint32_t Address, uint8_t *data, uint32_t TxSize, uint8_t AddrType)
{
    int16_t i = 0;
    uint32_t Length = 0;
    uint8_t addr; 
    uint16_t Count;
    uint32_t address = Address;
    uint8_t temp;
    uint8_t RX_Count = 0;;
    uint32_t RXFIFO[24];
    uint16_t CheckCount = 0;
    
    if(Address < 0x80000000 || Address > 0x84000000)
      return FLASH_ADDR_RANGE_ERR;
    
    /******** Direct Mode Configuration ********/
    DDRHSSPI0_PCC0 =  0x00010424;    /*1.[bit20:16]Slave Selection De-Assertion Timeout = 1: SDR = 4 x SCLK cycle, DDR = 3.5 x SCLK cycle(Minimum setting)*/
    /*  [bit12:9] Clock Division = 0: Divide by 2. SCLK:60MHz*/
    /*  [bit6:5]  Slave Select to Clock Delay = 1: 1.75 SCLK*/
    DDRHSSPI0_MCTRL = 0x00000000;    /*1.[bit1]    Command Sequencer Mode Enable = 0: Direct Mode is enabled. Command Sequencer Mode is disabled.*/
    DDRHSSPI0_DMTRP = 0x00;          /*2.[bit5]    SDR Mode*/
    /*  [bit3:0]  Transfer Protocol: TX-Only in Quad Mode is configured.*/
    DDRHSSPI0_DMFIFOCFG = 0x001C1818;/*3.[bit20]   TX-FIFO Flush = 1: Writing "1" flushes the TX-FIFO and TX Shift Register.*/
    /*  [bit19]   RX-FIFO Flush = 1: Writing "1" flushes the RX-FIFO and RX Shift Register.*/
    /*  [bit18]   TXCTRL Bit to be Written to TX-FIFO*/
    /*  [bit17:16]FIFO Width = 0: TX-FIFO, RX-FIFO and Shift-Register are 8-bit wide.*/
    /*  [bit12:8] TX-FIFO Threshold Level = 24*/
    /*  [bit4:0]  RX-FIFO Threshold Level = 24*/
    DDRHSSPI0_TXE = 0x0;             /*  TX interrupts are not used.*/
    DDRHSSPI0_RXE = 0x0;             /*  RX interrupts are not used.*/
    DDRHSSPI0_TXC = 0x00000077;      /*  TX interrupt flags are cleared.*/
    DDRHSSPI0_RXC = 0x000000FB;      /*  RX interrupt flags are cleared.*/
    DDRHSSPI0_DMPSEL = 0x0;          /*  [bit1:0]  Peripheral Select = 0: oDDRHSSPIn_SSEL0 is asserted.*/
    DDRHSSPI0_MCTRL = 0x00000001;    /*5.[bit0]    Module Enable = 1: DDRHSSPI is enabled.*/
    DDRHSSPI0_DMCFG = 0x02;          /*Figure 4-10 Programmer's Flowchart: General Steps 3.*/
    ClearWatchdog();
    
    address -=0x80000000;  //flash chip address
    
    if(address % 16 != 0)
    {
        /*Check completion of writing of two QUAD Flashs*/
        DDRHSSPI0_DMFIFOCFG_TXFLSH = 1;  /*  TX-FIFO Flush = 1: Writing "1" flushes the TX-FIFO and TX Shift Register.*/
        DDRHSSPI0_DMFIFOCFG_RXFLSH = 1;  /*  RX-FIFO Flush = 1: Writing "1" flushes the RX-FIFO and RX Shift Register.*/
            
		if(AddrType == 1)
		{
			DDRHSSPI0_DMBCC = 16 - address % 16 + 5 + 1;  
			RX_Count = DDRHSSPI0_DMBCC;
			Count = 16 - address % 16;
		   
			
			DDRHSSPI0_TXFIFO0 = 0x0000100C;  /*  quad page program Flash. 34h*/
			
			for(i = 3; i >= 0 ; i--)    //4 byte address
			{
				addr = (address >> (i * 8)) & 0xff;
				DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
			}
		}
		else
		{
			DDRHSSPI0_DMBCC = 16 - address % 16 + 5;  
			RX_Count = DDRHSSPI0_DMBCC;
			Count = 16 - address % 16;
		   
			
			DDRHSSPI0_TXFIFO0 = 0x0000100B;  /*  quad page program Flash. 34h*/
			
			for(i = 2; i >= 0 ; i--)    //4 byte address
			{
				addr = (address >> (i * 8)) & 0xff;
				DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
			}
		}
        
        DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
        
        i = 0;
        while(i < Count + 1)
        {
            if(DDRHSSPI0_DMFIFOSTATUS_TXFLEVEL < 8)
            {
                temp = *(data + i + Length);
                DDRHSSPI0_TXFIFO0 = 0x00001000;
                i++;
            }
        }
        while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
            ClearWatchdog();
        }
        
        RXFIFO[0] = DDRHSSPI0_RXFIFO0;  /*Read Instruction part*/
        RXFIFO[1] = DDRHSSPI0_RXFIFO1;  /*Read Instruction part*/
        RXFIFO[2] = DDRHSSPI0_RXFIFO2;  /*Read Instruction part*/
        RXFIFO[3] = DDRHSSPI0_RXFIFO3;  /*Read Instruction part*/
        RXFIFO[4] = DDRHSSPI0_RXFIFO4;  /*Read Instruction part*/
        RXFIFO[5] = DDRHSSPI0_RXFIFO5;  /*Read Instruction part*/
        RXFIFO[6] = DDRHSSPI0_RXFIFO6;  /*Read Instruction part*/
        RXFIFO[7] = DDRHSSPI0_RXFIFO7;  /*Read Instruction part*/
        RXFIFO[8] = DDRHSSPI0_RXFIFO8;  /*Read Instruction part*/
        RXFIFO[9] = DDRHSSPI0_RXFIFO9;  /*Read Instruction part*/
        RXFIFO[10] = DDRHSSPI0_RXFIFO10;  /*Read Instruction part*/
        RXFIFO[11] = DDRHSSPI0_RXFIFO11;  /*Read Instruction part*/
        RXFIFO[12] = DDRHSSPI0_RXFIFO12;  /*Read Instruction part*/
        RXFIFO[13] = DDRHSSPI0_RXFIFO13;  /*Read Instruction part*/
        RXFIFO[14] = DDRHSSPI0_RXFIFO14;  /*Read Instruction part*/
        RXFIFO[15] = DDRHSSPI0_RXFIFO15;  /*Read Instruction part*/
        RXFIFO[16] = DDRHSSPI0_RXFIFO16;  /*Read Instruction part*/
        RXFIFO[17] = DDRHSSPI0_RXFIFO17;  /*Read Instruction part*/
        RXFIFO[18] = DDRHSSPI0_RXFIFO18;  /*Read Instruction part*/
        RXFIFO[19] = DDRHSSPI0_RXFIFO19;  /*Read Instruction part*/
        RXFIFO[20] = DDRHSSPI0_RXFIFO20;  /*Read Instruction part*/
        RXFIFO[21] = DDRHSSPI0_RXFIFO21;  /*Read Instruction part*/
        RXFIFO[22] = DDRHSSPI0_RXFIFO22;  /*Read Instruction part*/
        RXFIFO[23] = DDRHSSPI0_RXFIFO23;  /*Read Instruction part*/
        
        for(i = 0; i < Count; i++)
        {
			if(AddrType == 1)
			{
				if(RXFIFO[i + 6] != *(data + CheckCount))
				{
					return FLASH_PROGRAM_ERR;
				}
			}
			else
			{
				if(RXFIFO[i + 5] != *(data + CheckCount))
				{
					return FLASH_PROGRAM_ERR;
				}
			}
            CheckCount++;
        }
        
        Length += Count; 
        address += Count;
    }
    
    while(TxSize > Length)
    {
        /*Check completion of writing of two QUAD Flashs*/
        DDRHSSPI0_DMFIFOCFG_TXFLSH = 1;  /*  TX-FIFO Flush = 1: Writing "1" flushes the TX-FIFO and TX Shift Register.*/
        DDRHSSPI0_DMFIFOCFG_RXFLSH = 1;  /*  RX-FIFO Flush = 1: Writing "1" flushes the RX-FIFO and RX Shift Register.*/
        
		if(AddrType == 1)
		{
			if((TxSize - Length) > 16)
			{
				/******** Transfer in Direct Mode (Command:c7)********   LC[7:6]=0 EEh:Dummy=6 , QUAD[1]=1 Quad*/
				DDRHSSPI0_DMBCC = 16 + 5 + 1;        /*2.[bit15:0] Byte Count Control = 2*/
				RX_Count = DDRHSSPI0_DMBCC;
				Count = 16;
			}
			else
			{
				DDRHSSPI0_DMBCC = TxSize - Length + 5 + 1;
				RX_Count = DDRHSSPI0_DMBCC;
				Count = TxSize - Length;
			}
			
			DDRHSSPI0_TXFIFO0 = 0x0000100C;  /*  quad page program Flash. 34h*/
			
			for(i = 3; i >= 0 ; i--)    //4 byte address
			{
				addr = (address >> (i * 8)) & 0xff;
				DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
			}
		}
		else
		{
			if((TxSize - Length) > 16)
			{
				/******** Transfer in Direct Mode (Command:c7)********   LC[7:6]=0 EEh:Dummy=6 , QUAD[1]=1 Quad*/
				DDRHSSPI0_DMBCC = 16 + 5;        /*2.[bit15:0] Byte Count Control = 2*/
				RX_Count = DDRHSSPI0_DMBCC;
				Count = 16;
			}
			else
			{
				DDRHSSPI0_DMBCC = TxSize - Length + 5;
				RX_Count = DDRHSSPI0_DMBCC;
				Count = TxSize - Length;
			}
			
			DDRHSSPI0_TXFIFO0 = 0x0000100B;  /*  quad page program Flash. 34h*/
			
			for(i = 2; i >= 0 ; i--)    //4 byte address
			{
				addr = (address >> (i * 8)) & 0xff;
				DDRHSSPI0_TXFIFO0 = 0x00001000 | addr;
			}

		}
        
        DDRHSSPI0_DMSTART_START = 0x01;  /*7.[bit0]    Start Transfer = 1*/
        
        i = 0;
        while(i < Count + 1)
        {
            if(DDRHSSPI0_DMFIFOSTATUS_TXFLEVEL < 8)
            {
                temp = *(data + i + Length);
                DDRHSSPI0_TXFIFO0 = 0x00001000;
                i++;
            }
        }
        while(DDRHSSPI0_DMSTART_START){  /* In case of user program, countermeasure of infinite loop is recommended. */
            ClearWatchdog();
        }
        
        RXFIFO[0] = DDRHSSPI0_RXFIFO0;  /*Read Instruction part*/
        RXFIFO[1] = DDRHSSPI0_RXFIFO1;  /*Read Instruction part*/
        RXFIFO[2] = DDRHSSPI0_RXFIFO2;  /*Read Instruction part*/
        RXFIFO[3] = DDRHSSPI0_RXFIFO3;  /*Read Instruction part*/
        RXFIFO[4] = DDRHSSPI0_RXFIFO4;  /*Read Instruction part*/
        RXFIFO[5] = DDRHSSPI0_RXFIFO5;  /*Read Instruction part*/
        RXFIFO[6] = DDRHSSPI0_RXFIFO6;  /*Read Instruction part*/
        RXFIFO[7] = DDRHSSPI0_RXFIFO7;  /*Read Instruction part*/
        RXFIFO[8] = DDRHSSPI0_RXFIFO8;  /*Read Instruction part*/
        RXFIFO[9] = DDRHSSPI0_RXFIFO9;  /*Read Instruction part*/
        RXFIFO[10] = DDRHSSPI0_RXFIFO10;  /*Read Instruction part*/
        RXFIFO[11] = DDRHSSPI0_RXFIFO11;  /*Read Instruction part*/
        RXFIFO[12] = DDRHSSPI0_RXFIFO12;  /*Read Instruction part*/
        RXFIFO[13] = DDRHSSPI0_RXFIFO13;  /*Read Instruction part*/
        RXFIFO[14] = DDRHSSPI0_RXFIFO14;  /*Read Instruction part*/
        RXFIFO[15] = DDRHSSPI0_RXFIFO15;  /*Read Instruction part*/
        RXFIFO[16] = DDRHSSPI0_RXFIFO16;  /*Read Instruction part*/
        RXFIFO[17] = DDRHSSPI0_RXFIFO17;  /*Read Instruction part*/
        RXFIFO[18] = DDRHSSPI0_RXFIFO18;  /*Read Instruction part*/
        RXFIFO[19] = DDRHSSPI0_RXFIFO19;  /*Read Instruction part*/
        RXFIFO[20] = DDRHSSPI0_RXFIFO20;  /*Read Instruction part*/
        RXFIFO[21] = DDRHSSPI0_RXFIFO21;  /*Read Instruction part*/
        RXFIFO[22] = DDRHSSPI0_RXFIFO22;  /*Read Instruction part*/
        RXFIFO[23] = DDRHSSPI0_RXFIFO23;  /*Read Instruction part*/
        
        for(i = 0; i < Count; i++)
        {
            if(AddrType == 1)
			{
				if(RXFIFO[i + 6] != *(data + CheckCount))
				{
					return FLASH_PROGRAM_ERR;
				}
			}
			else
			{
				if(RXFIFO[i + 5] != *(data + CheckCount))
				{
					return FLASH_PROGRAM_ERR;
				}
			}
            CheckCount++;
        }
        
        Length += Count; 
        address += Count;
    }
    return FLASH_OK;
}