/************************************************************
* Local Function Definitions                                *
************************************************************/

#pragma CODE_SECTION(NAND_ECC_correct,".text:nand_ecc_patch")
static uint32_t NAND_ECC_correct(void *unused, uint8_t *data, uint8_t *readECC)
{
  volatile uint32_t temp, corrState, numE;
  int i;
  uint16_t addOffset, corrValue;
  uint16_t* syndrome10 = (uint16_t *)readECC;

  // Clear bit13 of NANDFCR
  temp = AEMIF->NANDERRADD1;
  
  // Load the syndrome10 (from 7 to 0) values
  for(i=8;i>0;i--)
  {
    AEMIF->NAND4BITECCLOAD = (syndrome10[i-1] & 0x000003FF);
  }
  
  // Read the EMIF status and version (dummy call) 
  temp = AEMIF->ERCSR;
  
  // Check if error is detected
  temp = (AEMIF->NAND4BITECC1 & 0x03FF03FF) | (AEMIF->NAND4BITECC2 & 0x03FF03FF) |
         (AEMIF->NAND4BITECC3 & 0x03FF03FF) | (AEMIF->NAND4BITECC4 & 0x03FF03FF);
  if(temp == 0)
  {
    return 0;
  }

  // Start calcuating the correction addresses and values
  AEMIF->NANDFCR |= (0x1U << 13);
  
  // Loop until timeout or the ECC calculations are complete (bit 11:10 == 00b)
  i = 1000;
  do
  {
    temp = (AEMIF->NANDFSR & 0x00000F00)>>10;
    i--;
  }
  while((i>0) && (temp != 0x0));

  // Read final correction state (should be 0x0, 0x1, 0x2, or 0x3)
  corrState = (AEMIF->NANDFSR & 0x00000F00) >> 8;

  if ((corrState == 1) || (corrState > 3))
  {
    temp = AEMIF->NANDERRVAL1;
    return 1;
  }
  else if (corrState == 0)
  {
    return 0;
  }
  else
  {
    // Error detected and address calculated
    // Number of errors corrected 17:16
    numE = (AEMIF->NANDFSR & 0x00030000) >> 16;

    switch( numE )
    {
      case 3:     // Four errors
        addOffset = 519 - ( (AEMIF->NANDERRADD2 & (0x03FF0000))>>16 );
        if (addOffset < 512)
        {
            // Error in the user data region can be corrected
            corrValue = (AEMIF->NANDERRVAL2 & (0x03FF0000))>>16;
            data[addOffset] ^= (uint8_t)corrValue;
        }
        // Fall through to case 2
      case 2:     // Three errors
        addOffset = 519 - (AEMIF->NANDERRADD2 & (0x000003FF));
        if (addOffset < 512)
        {
            // Error in the user data region can be corrected
            corrValue = AEMIF->NANDERRVAL2 & (0x000003FF);
            data[addOffset] ^= (uint8_t)corrValue;
        }
        // Fall through to case 1
      case 1:     // Two errors
        addOffset = 519 - ( (AEMIF->NANDERRADD1 & (0x03FF0000))>>16 );
        if (addOffset < 512)
        {
            // Error in the user data region can be corrected
            corrValue = (AEMIF->NANDERRVAL1 & (0x03FF0000))>>16;
            data[addOffset] ^= (uint8_t)corrValue;
        }
        // Fall through to case 0
      case 0:     // One error
        addOffset = 519 - (AEMIF->NANDERRADD1 & (0x000003FF));
        if (addOffset < 512)
        {
            // Error in the user data region can be corrected
            corrValue = AEMIF->NANDERRVAL1 & (0x3FF);
            data[addOffset] ^= (uint8_t)corrValue;
        }
        break;
    }
    return 0;
  }
}