#define HCLK_13MHz

#define SDRAMCLK_CTRL            *(volatile unsigned int *)(0x40004068)
#define MPMCControl              *(volatile unsigned int *)(0x31080000)
#define MPMCConfig               *(volatile unsigned int *)(0x31080008)
#define MPMCAHBControl0          *(volatile unsigned int *)(0x31080400)
#define MPMCAHBControl2          *(volatile unsigned int *)(0x31080440)
#define MPMCAHBControl3          *(volatile unsigned int *)(0x31080460)
#define MPMCAHBControl4          *(volatile unsigned int *)(0x31080480)
#define MPMCDynamicConfig0       *(volatile unsigned int *)(0x31080100)
#define MPMCDynamicRasCas0       *(volatile unsigned int *)(0x31080104)
#define MPMCDynamicReadConfig    *(volatile unsigned int *)(0x31080028)
#define MPMCDynamictRP           *(volatile unsigned int *)(0x31080030)
#define MPMCDynamictRAS          *(volatile unsigned int *)(0x31080034)
#define MPMCDynamictSREX         *(volatile unsigned int *)(0x31080038)
#define MPMCDynamictWR           *(volatile unsigned int *)(0x31080044)
#define MPMCDynamictRC           *(volatile unsigned int *)(0x31080048)
#define MPMCDynamictRFC          *(volatile unsigned int *)(0x3108004C)
#define MPMCDynamictXSR          *(volatile unsigned int *)(0x31080050)
#define MPMCDynamictRRD          *(volatile unsigned int *)(0x31080054)
#define MPMCDynamictMRD          *(volatile unsigned int *)(0x31080058)
#define MPMCDynamicCDLR          *(volatile unsigned int *)(0x3108005C)
#define MPMCDynamicControl       *(volatile unsigned int *)(0x31080020)
#define MPMCDynamicRefresh       *(volatile unsigned int *)(0x31080024)
#define MPMCAHBTime0             *(volatile unsigned int *)(0x31080408)
#define MPMCAHBTime1             *(volatile unsigned int *)(0x31080448)
#define MPMCAHBTime2             *(volatile unsigned int *)(0x31080468)
#define MPMCAHBTime3             *(volatile unsigned int *)(0x31080488)

#define FLASHCLK_CTRL            *(volatile unsigned int *)(0x400040C8)
#define MLC_DATA_BUFFER          *(volatile unsigned int *)(0x200A8000)
#define MLC_CMD                  *(volatile unsigned int *)(0x200B8000)
#define MLC_ADDR                 *(volatile unsigned int *)(0x200B8004)
#define MLC_ECC_AUTO_DEC_REG     *(volatile unsigned int *)(0x200B8014)
#define MLC_ICR                  *(volatile unsigned int *)(0x200B8030)
#define MLC_TIME_REG             *(volatile unsigned int *)(0x200B8034)
#define MLC_LOCK_PR              *(volatile unsigned int *)(0x200B8044)
#define MLC_ISR                  *(volatile unsigned int *)(0x200B8048)
#define MLC_CEH                  *(volatile unsigned int *)(0x200B804C)

#define INTERFACE_READY          ((unsigned int)0x00000002)
#define ECC_READY                ((unsigned int)0x00000004)
#define ECC_DECODER_FAILURE      ((unsigned int)0x00000040)
#define SDRAM_BASE               ((unsigned int)0x80000000)
#define SMALL_PAGE_SIZE          ((unsigned int)0x00000200)

typedef void (*ENTRY_FUNC)(void);
static ENTRY_FUNC entry_func;

void delay(int delay);
void sdram_init(void);
unsigned int read_block_x_page_y(unsigned int block_number, unsigned int page_number);

void main(void)
{
   unsigned int block_number;
   unsigned int page_number;
   unsigned int data;
   unsigned int ret;
   unsigned int i, j;

   sdram_init();

   FLASHCLK_CTRL        = 0x00000022;

   MLC_CEH              = 0x00000001;
   MLC_LOCK_PR          = 0x0000A25E;
   MLC_ICR              = 0x00000000;
   MLC_TIME_REG         = 0x02193131;
   MLC_CMD              = 0x000000FF;

   while ( !( MLC_ISR & INTERFACE_READY ) );

   block_number         = 2;
   page_number          = 0;

   ret                  = read_block_x_page_y(block_number, page_number);

   if ( ret != 0xAA )
   {
      block_number        += 1;
      page_number          = 0;

      ret                  = read_block_x_page_y(block_number, page_number);
   }

   for ( i = 0; i < 0x80; i++ )
   {
      data                 = MLC_DATA_BUFFER;
      *(volatile unsigned int *)(SDRAM_BASE + (4 * i)) = data;
   }

   for ( j = 0; j < 7; j++ )
   {
      page_number         += 1;
      ret                  = read_block_x_page_y(block_number, page_number);

      for ( i = 0; i < 0x80; i++ )
      {
         data                 = MLC_DATA_BUFFER;
         *(volatile unsigned int *)(SDRAM_BASE + (SMALL_PAGE_SIZE *  page_number) + (4 * i)) = data;
      }
   }

   entry_func = (ENTRY_FUNC)SDRAM_BASE;
   entry_func();
}  /* blinky_main */

void delay(int delay)
{
   while ( delay )
   {
      delay--;
   }
}  /* delay */

void sdram_init(void)
{
   unsigned int dwtemp;

   SDRAMCLK_CTRL         = 0x0001C000;
   MPMCControl           = 0x00000001;
   MPMCConfig            = 0x00000000;
   MPMCAHBControl0       = 0x00000001;
   MPMCAHBControl2       = 0x00000001;
   MPMCAHBControl3       = 0x00000001;
   MPMCAHBControl4       = 0x00000001;
   MPMCDynamicConfig0    = 0x00005482;

#ifdef HCLK_13MHz
   MPMCDynamicRasCas0    = 0x00000301;
#endif
#ifdef HCLK_26MHz
   MPMCDynamicRasCas0    = 0x00000301;
#endif
#ifdef HCLK_39MHz
   MPMCDynamicRasCas0    = 0x00000301;
#endif
#ifdef HCLK_52MHz
   MPMCDynamicRasCas0    = 0x00000302;
#endif
#ifdef HCLK_65MHz
   MPMCDynamicRasCas0    = 0x00000302;
#endif
#ifdef HCLK_78MHz
   MPMCDynamicRasCas0    = 0x00000302;
#endif
#ifdef HCLK_91MHz
   MPMCDynamicRasCas0    = 0x00000302;
#endif
#ifdef HCLK_104MHz
   MPMCDynamicRasCas0    = 0x00000303;
#endif

   MPMCDynamicReadConfig = 0x00000011;

#ifdef HCLK_13MHz
   MPMCDynamictRP        = 0x00000000;
#endif
#ifdef HCLK_26MHz
   MPMCDynamictRP        = 0x00000000;
#endif
#ifdef HCLK_39MHz
   MPMCDynamictRP        = 0x00000000;
#endif
#ifdef HCLK_52MHz
   MPMCDynamictRP        = 0x00000001;
#endif
#ifdef HCLK_65MHz
   MPMCDynamictRP        = 0x00000001;
#endif
#ifdef HCLK_78MHz
   MPMCDynamictRP        = 0x00000001;
#endif
#ifdef HCLK_91MHz
   MPMCDynamictRP        = 0x00000001;
#endif
#ifdef HCLK_104MHz
   MPMCDynamictRP        = 0x00000002;
#endif

#ifdef HCLK_13MHz
   MPMCDynamictRAS       = 0x00000000;
#endif
#ifdef HCLK_26MHz
   MPMCDynamictRAS       = 0x00000001;
#endif
#ifdef HCLK_39MHz
   MPMCDynamictRAS       = 0x00000002;
#endif
#ifdef HCLK_52MHz
   MPMCDynamictRAS       = 0x00000002;
#endif
#ifdef HCLK_65MHz
   MPMCDynamictRAS       = 0x00000003;
#endif
#ifdef HCLK_78MHz
   MPMCDynamictRAS       = 0x00000004;
#endif
#ifdef HCLK_91MHz
   MPMCDynamictRAS       = 0x00000004;
#endif
#ifdef HCLK_104MHz
   MPMCDynamictRAS       = 0x00000005;
#endif

#ifdef HCLK_13MHz
   MPMCDynamictSREX      = 0x00000001;
#endif
#ifdef HCLK_26MHz
   MPMCDynamictSREX      = 0x00000002;
#endif
#ifdef HCLK_39MHz
   MPMCDynamictSREX      = 0x00000003;
#endif
#ifdef HCLK_52MHz
   MPMCDynamictSREX      = 0x00000004;
#endif
#ifdef HCLK_65MHz
   MPMCDynamictSREX      = 0x00000005;
#endif
#ifdef HCLK_78MHz
   MPMCDynamictSREX      = 0x00000006;
#endif
#ifdef HCLK_91MHz
   MPMCDynamictSREX      = 0x00000007;
#endif
#ifdef HCLK_104MHz
   MPMCDynamictSREX      = 0x00000008;
#endif

   MPMCDynamictWR        = 0x00000001;

#ifdef HCLK_13MHz
   MPMCDynamictRC        = 0x00000001;
#endif
#ifdef HCLK_26MHz
   MPMCDynamictRC        = 0x00000002;
#endif
#ifdef HCLK_39MHz
   MPMCDynamictRC        = 0x00000003;
#endif
#ifdef HCLK_52MHz
   MPMCDynamictRC        = 0x00000004;
#endif
#ifdef HCLK_65MHz
   MPMCDynamictRC        = 0x00000005;
#endif
#ifdef HCLK_78MHz
   MPMCDynamictRC        = 0x00000006;
#endif
#ifdef HCLK_91MHz
   MPMCDynamictRC        = 0x00000007;
#endif
#ifdef HCLK_104MHz
   MPMCDynamictRC        = 0x00000008;
#endif

#ifdef HCLK_13MHz
   MPMCDynamictRFC       = 0x00000001;
#endif
#ifdef HCLK_26MHz
   MPMCDynamictRFC       = 0x00000002;
#endif
#ifdef HCLK_39MHz
   MPMCDynamictRFC       = 0x00000003;
#endif
#ifdef HCLK_52MHz
   MPMCDynamictRFC       = 0x00000004;
#endif
#ifdef HCLK_65MHz
   MPMCDynamictRFC       = 0x00000005;
#endif
#ifdef HCLK_78MHz
   MPMCDynamictRFC       = 0x00000006;
#endif
#ifdef HCLK_91MHz
   MPMCDynamictRFC       = 0x00000007;
#endif
#ifdef HCLK_104MHz
   MPMCDynamictRFC       = 0x00000008;
#endif

#ifdef HCLK_13MHz
   MPMCDynamictXSR       = 0x00000001;
#endif
#ifdef HCLK_26MHz
   MPMCDynamictXSR       = 0x00000002;
#endif
#ifdef HCLK_39MHz
   MPMCDynamictXSR       = 0x00000003;
#endif
#ifdef HCLK_52MHz
   MPMCDynamictXSR       = 0x00000004;
#endif
#ifdef HCLK_65MHz
   MPMCDynamictXSR       = 0x00000005;
#endif
#ifdef HCLK_78MHz
   MPMCDynamictXSR       = 0x00000006;
#endif
#ifdef HCLK_91MHz
   MPMCDynamictXSR       = 0x00000007;
#endif
#ifdef HCLK_104MHz
   MPMCDynamictXSR       = 0x00000008;
#endif

#ifdef HCLK_13MHz
   MPMCDynamictRRD       = 0x00000000;
#endif
#ifdef HCLK_26MHz
   MPMCDynamictRRD       = 0x00000000;
#endif
#ifdef HCLK_39MHz
   MPMCDynamictRRD       = 0x00000000;
#endif
#ifdef HCLK_52MHz
   MPMCDynamictRRD       = 0x00000000;
#endif
#ifdef HCLK_65MHz
   MPMCDynamictRRD       = 0x00000001;
#endif
#ifdef HCLK_78MHz
   MPMCDynamictRRD       = 0x00000001;
#endif
#ifdef HCLK_91MHz
   MPMCDynamictRRD       = 0x00000001;
#endif
#ifdef HCLK_104MHz
   MPMCDynamictRRD       = 0x00000001;
#endif

   MPMCDynamictMRD       = 0x00000001;
   MPMCDynamicCDLR       = 0x00000000;
   MPMCDynamicControl    = 0x00000193;
   delay(100);
   MPMCDynamicControl    = 0x00000113;
   MPMCDynamicRefresh    = 0x00000002;
   delay(100);

#ifdef HCLK_13MHz
   MPMCDynamicRefresh    = 0x0000000C;
#endif
#ifdef HCLK_26MHz
   MPMCDynamicRefresh    = 0x00000019;
#endif
#ifdef HCLK_39MHz
   MPMCDynamicRefresh    = 0x00000023;
#endif
#ifdef HCLK_52MHz
   MPMCDynamicRefresh    = 0x00000033;
#endif
#ifdef HCLK_65MHz
   MPMCDynamicRefresh    = 0x00000040;
#endif
#ifdef HCLK_78MHz
   MPMCDynamicRefresh    = 0x0000004D;
#endif
#ifdef HCLK_91MHz
   MPMCDynamicRefresh    = 0x00000059;
#endif
#ifdef HCLK_104MHz
   MPMCDynamicRefresh    = 0x00000065;
#endif

#ifdef HCLK_13MHz
   MPMCDynamicRasCas0    = 0x00000301;
#endif
#ifdef HCLK_26MHz
   MPMCDynamicRasCas0    = 0x00000301;
#endif
#ifdef HCLK_39MHz
   MPMCDynamicRasCas0    = 0x00000301;
#endif
#ifdef HCLK_52MHz
   MPMCDynamicRasCas0    = 0x00000302;
#endif
#ifdef HCLK_65MHz
   MPMCDynamicRasCas0    = 0x00000302;
#endif
#ifdef HCLK_78MHz
   MPMCDynamicRasCas0    = 0x00000302;
#endif
#ifdef HCLK_91MHz
   MPMCDynamicRasCas0    = 0x00000302;
#endif
#ifdef HCLK_104MHz
   MPMCDynamicRasCas0    = 0x00000303;
#endif

   MPMCDynamicConfig0    = 0x00005482;
   MPMCDynamicControl    = 0x00000093;
   dwtemp = *(volatile unsigned int *)(0x80018000);
   MPMCDynamicControl    = 0x00000093;
   dwtemp = *(volatile unsigned int *)(0x8102C000);
   MPMCDynamicControl    = 0x00000010;
   MPMCAHBTime0          = 0x00000064;
   MPMCAHBTime1          = 0x00000190;
   MPMCAHBTime2          = 0x00000190;
   MPMCAHBTime3          = 0x00000190;
} /* sdrm_init */

unsigned int read_block_x_page_y(unsigned int block_number, unsigned int page_number)
{
   unsigned int first_block_page_address  = ((block_number << 5) & 0xE0) | (page_number & 0x1F);
   unsigned int second_block_page_address = (((block_number << 5) >> 8) & 0xFF);
   unsigned int ret                       = 0xAA;

   MLC_CMD              = 0x00000000;
   MLC_ADDR             = 0x00000000;
   MLC_ADDR             = first_block_page_address;
   MLC_ADDR             = second_block_page_address;

   MLC_ECC_AUTO_DEC_REG = 0x00000000;

   while ( !( MLC_ISR & ECC_READY ) );

   if ( MLC_ISR & ECC_DECODER_FAILURE )
   {
      ret                 = 0;
   }

   return ret;
} /* read_block_x_page_y */
