/*****************************************************************************
 *
 *   Copyright(C) 2011, Embedded Artists AB
 *   All rights reserved.
 *
 ******************************************************************************
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * products. This software is supplied "AS IS" without any warranties.
 * Embedded Artists AB assumes no responsibility or liability for the
 * use of the software, conveys no license or title under any patent,
 * copyright, or mask work right to the product. Embedded Artists AB
 * reserves the right to make changes in the software without
 * notification. Embedded Artists AB also make no representation or
 * warranty that such application will be suitable for the specified
 * use without further testing or modification.
 *****************************************************************************/



/******************************************************************************
 * Includes
 *****************************************************************************/
#include "../board.h"

#if BOARD == BOARD_EA4357

#include "LPC43xx.h"
#include "lpc_types.h"
#include "lpc43xx_scu.h"
#include "lpc43xx_timer.h"
#include "lpc43xx_cgu.h"
#include "sdram.h"
#include <string.h>

/******************************************************************************
 * Defines and typedefs
 *****************************************************************************/

/* SDRAM refresh time to 16 clock num */
#define EMC_SDRAM_REFRESH(freq,time)  \
  (((uint64_t)((uint64_t)time * freq)/16000000000ull)+1)

/******************************************************************************
 * External global variables
 *****************************************************************************/

/******************************************************************************
 * Local variables
 *****************************************************************************/

/******************************************************************************
 * Local Functions
 *****************************************************************************/


/*-------------------------PRIVATE FUNCTIONS------------------------------*/
/*********************************************************************
 * @brief		Calculate EMC Clock from nano second
 * @param[in]	freq - frequency of EMC Clk
 * @param[in]	time - nano second
 * @return 		None
 **********************************************************************/
uint32_t NS2CLK(uint32_t freq, uint32_t time){
 return (((uint64_t)time*freq/1000000000));
}

static void pinConfig(void)
{
	/* Set up EMC pin */
	scu_pinmux(	 2	,	 9	,	MD_PLN_FAST	,	3	);//A0
	scu_pinmux(	 2	,	10	,	MD_PLN_FAST	,	3	);//A1
	scu_pinmux(	 2	,	11	,	MD_PLN_FAST	,	3	);//A2
	scu_pinmux(	 2	,	12	,	MD_PLN_FAST	,	3	);//A3
	scu_pinmux(	 2	,	13	,	MD_PLN_FAST	,	3	);//A4
	scu_pinmux(	 1	,	 0	,	MD_PLN_FAST	,	2	);//A5
	scu_pinmux(	 1	,	 1	,	MD_PLN_FAST	,	2	);//A6
	scu_pinmux(	 1	,	 2	,	MD_PLN_FAST	,	2	);//A7
	scu_pinmux(	 2	,	 8	,	MD_PLN_FAST	,	3	);//A8
	scu_pinmux(	 2	,	 7	,	MD_PLN_FAST	,	3	);//A9
	scu_pinmux(	 2	,	 6	,	MD_PLN_FAST	,	2	);//A10
	scu_pinmux(	 2	,	 2	,	MD_PLN_FAST	,	2	);//A11
	scu_pinmux(	 2	,	 1	,	MD_PLN_FAST	,	2	);//A12
	scu_pinmux(	 2	,	 0	,	MD_PLN_FAST	,	2	);//A13
	scu_pinmux(	 6	,	 8	,	MD_PLN_FAST	,	1	);//A14
	scu_pinmux(	 6	,	 7	,	MD_PLN_FAST	,	1	);//A15
	scu_pinmux(	13	,	16	,	MD_PLN_FAST	,	2	);//A16
	scu_pinmux(	13	,	15	,	MD_PLN_FAST	,	2	);//A17
	scu_pinmux(	14	,	 0	,	MD_PLN_FAST	,	3	);//A18
	scu_pinmux(	14	,	 1	,	MD_PLN_FAST	,	3	);//A19
	scu_pinmux(	14	,	 2	,	MD_PLN_FAST	,	3	);//A20
	scu_pinmux(	14	,	 3	,	MD_PLN_FAST	,	3	);//A21
	scu_pinmux(	14	,	 4	,	MD_PLN_FAST	,	3	);//A22
	scu_pinmux(	10	,	 4	,	MD_PLN_FAST	,	3	);//A23
	
	scu_pinmux(	 1	,	 7	,	MD_PLN_FAST	,	3	);//D0
	scu_pinmux(	 1	,	 8	,	MD_PLN_FAST	,	3	);//D1
	scu_pinmux(	 1	,	 9	,	MD_PLN_FAST	,	3	);//D2
	scu_pinmux(	 1	,	10	,	MD_PLN_FAST	,	3	);//D3
	scu_pinmux(	 1	,	11	,	MD_PLN_FAST	,	3	);//D4
	scu_pinmux(	 1	,	12	,	MD_PLN_FAST	,	3	);//D5
	scu_pinmux(	 1	,	13	,	MD_PLN_FAST	,	3	);//D6
	scu_pinmux(	 1	,	14	,	MD_PLN_FAST	,	3	);//D7
	scu_pinmux(	 5	,	 4	,	MD_PLN_FAST	,	2	);//D8
	scu_pinmux(	 5	,	 5	,	MD_PLN_FAST	,	2	);//D9
	scu_pinmux(	 5	,	 6	,	MD_PLN_FAST	,	2	);//D10
	scu_pinmux(	 5	,	 7	,	MD_PLN_FAST	,	2	);//D11
	scu_pinmux(	 5	,	 0	,	MD_PLN_FAST	,	2	);//D12
	scu_pinmux(	 5	,	 1	,	MD_PLN_FAST	,	2	);//D13
	scu_pinmux(	 5	,	 2	,	MD_PLN_FAST	,	2	);//D14
	scu_pinmux(	 5	,	 3	,	MD_PLN_FAST	,	2	);//D15
	scu_pinmux(	13	,	 2	,	MD_PLN_FAST	,	2	);//D16
	scu_pinmux(	13	,	 3	,	MD_PLN_FAST	,	2	);//D17
	scu_pinmux(	13	,	 4	,	MD_PLN_FAST	,	2	);//D18
	scu_pinmux(	13	,	 5	,	MD_PLN_FAST	,	2	);//D19
	scu_pinmux(	13	,	 6	,	MD_PLN_FAST	,	2	);//D20
	scu_pinmux(	13	,	 7	,	MD_PLN_FAST	,	2	);//D21
	scu_pinmux(	13	,	 8	,	MD_PLN_FAST	,	2	);//D22
	scu_pinmux(	13	,	 9	,	MD_PLN_FAST	,	2	);//D23
	scu_pinmux(	14	,	 5	,	MD_PLN_FAST	,	3	);//D24
	scu_pinmux(	14	,	 6	,	MD_PLN_FAST	,	3	);//D25
	scu_pinmux(	14	,	 7	,	MD_PLN_FAST	,	3	);//D26
	scu_pinmux(	14	,	 8	,	MD_PLN_FAST	,	3	);//D27
	scu_pinmux(	14	,	 9	,	MD_PLN_FAST	,	3	);//D28
	scu_pinmux(	14	,	10	,	MD_PLN_FAST	,	3	);//D29
	scu_pinmux(	14	,	11	,	MD_PLN_FAST	,	3	);//D30
	scu_pinmux(	14	,	12	,	MD_PLN_FAST	,	3	);//D31
		
	scu_pinmux(	 1	,	 3	,	MD_PLN_FAST	,	3	);//OE
	scu_pinmux(	 1	,	 6	,	MD_PLN_FAST	,	3	);//WE
	
	scu_pinmux(	 1	,	 4	,	MD_PLN_FAST	,	3	);//BLS0
	scu_pinmux(	 6	,	 6	,	MD_PLN_FAST	,	1	);//BLS1	
	scu_pinmux(	13	,	13	,	MD_PLN_FAST	,	2	);//BLS2
	scu_pinmux(	13	,	10	,	MD_PLN_FAST	,	2	);//BLS3
	
	scu_pinmux(	 1	,	 5	,	MD_PLN_FAST	,	3	);//CS0	
	scu_pinmux(	 6	,	 3	,	MD_PLN_FAST	,	3	);//CS1
	scu_pinmux(	13	,	12	,	MD_PLN_FAST	,	2	);//CS2
	scu_pinmux(	13	,	11	,	MD_PLN_FAST	,	2	);//CS3
	
	scu_pinmux(	 6	,	 4	,	MD_PLN_FAST	,	3	);//CAS
	scu_pinmux(	 6	,	 5	,	MD_PLN_FAST	,	3	);//RAS
	
	scu_pinmux(  6	,	 9	,	MD_PLN_FAST	,	3	);//DYCS0
	scu_pinmux(	 6	,	 1	,	MD_PLN_FAST	,	1	);//DYCS1
	scu_pinmux(	13	,	14	,	MD_PLN_FAST	,	2	);//DYCS2
	scu_pinmux(	15	,	14	,	MD_PLN_FAST	,	3	);//DYCS3

	scu_pinmux(	 6	,	11	,	MD_PLN_FAST	,	3	);//CKEOUT0
	scu_pinmux(	 6	,	 2	,	MD_PLN_FAST	,	1	);//CKEOUT1
	scu_pinmux(	13	,	 1	,	MD_PLN_FAST	,	2	);//CKEOUT2
	scu_pinmux(	14	,	15	,	MD_PLN_FAST	,	3	);//CKEOUT3
	
	scu_pinmux(	 6	,	12	,	MD_PLN_FAST	,	3	);//DQMOUT0
	scu_pinmux(	 6	,	10	,	MD_PLN_FAST	,	3	);//DQMOUT1
	scu_pinmux(	13	,	 0	,	MD_PLN_FAST	,	2	);//DQMOUT2
	scu_pinmux(	14	,	13	,	MD_PLN_FAST	,	3	);//DQMOUT3
}



/******************************************************************************
 * Public Functions
 *****************************************************************************/


/******************************************************************************
 *
 * Description:
 *    Initialize the SDRAM
 *
 *****************************************************************************/
uint32_t sdram_init (void)
{
	uint32_t pclk, temp;
 	uint64_t tmpclk;
  
  pinConfig(); //Full 32-bit Data bus, 24-bit Address 
    
	/* Select EMC clock-out */
	LPC_SCU->SFSCLK_0 = MD_PLN_FAST;
	LPC_SCU->SFSCLK_1 = MD_PLN_FAST;
	LPC_SCU->SFSCLK_2 = MD_PLN_FAST;
	LPC_SCU->SFSCLK_3 = MD_PLN_FAST;

	LPC_EMC->CONTROL 	= 0x00000001;
	LPC_EMC->CONFIG  	= 0x00000000;
  LPC_EMC->DYNAMICCONFIG0    = 1<<14 | 0<<12 | 2<<9 | 1<<7; /* 256Mb, 8Mx32, 4 banks, row=12, column=9 */

	pclk = CGU_GetPCLKFrequency(CGU_PERIPHERAL_M4CORE);

  LPC_EMC->DYNAMICRASCAS0    = 0x00000202; /* 2 RAS, 2 CAS latency */
	LPC_EMC->DYNAMICREADCONFIG = 0x00000001; /* Command delayed strategy, using EMCCLKDELAY */
  
	LPC_EMC->DYNAMICRP         = NS2CLK(pclk, 20);
	LPC_EMC->DYNAMICRAS        = NS2CLK(pclk, 42);
	LPC_EMC->DYNAMICSREX       = NS2CLK(pclk, 63);
	LPC_EMC->DYNAMICAPR        = 0x00000005;
	LPC_EMC->DYNAMICDAL        = 0x00000005;
	LPC_EMC->DYNAMICWR         = 2;
	LPC_EMC->DYNAMICRC         = NS2CLK(pclk, 63);
	LPC_EMC->DYNAMICRFC        = NS2CLK(pclk, 63);
	LPC_EMC->DYNAMICXSR        = NS2CLK(pclk, 63);
	LPC_EMC->DYNAMICRRD        = NS2CLK(pclk, 14);
	LPC_EMC->DYNAMICMRD        = 0x00000002;

	TIM_Waitus(100);						   /* wait 100ms */
	LPC_EMC->DYNAMICCONTROL    = 0x00000183; /* Issue NOP command */

	TIM_Waitus(200);						   /* wait 200ms */
	LPC_EMC->DYNAMICCONTROL    = 0x00000103; /* Issue PALL command */

	LPC_EMC->DYNAMICREFRESH    = EMC_SDRAM_REFRESH(pclk,70); /* ( n * 16 ) -> 32 clock cycles */

	//for(i = 0; i < 0x80; i++);	           /* wait 128 AHB clock cycles */
	TIM_Waitus(200);						   /* wait 200ms */

	tmpclk = (uint64_t)15625*(uint64_t)pclk/1000000000/16;
	LPC_EMC->DYNAMICREFRESH    = tmpclk; /* ( n * 16 ) -> 736 clock cycles -> 15.330uS at 48MHz <= 15.625uS ( 64ms / 4096 row ) */

	LPC_EMC->DYNAMICCONTROL    = 0x00000083; /* Issue MODE command */

	//Timing for 48/60/72MHZ Bus
	temp = *((volatile uint32_t *)(SDRAM_BASE | (2<<4| 2)<<(9+2+2))); /* 4 burst, 2 CAS latency */
	temp = temp;
	LPC_EMC->DYNAMICCONTROL    = 0x00000000; /* Issue NORMAL command */

	//[re]enable buffers
	LPC_EMC->DYNAMICCONFIG0    |= 1<<19;

  return TRUE;
}

uint32_t sdram_test( void )
{
  volatile uint32_t *wr_ptr; 
  volatile uint16_t *short_wr_ptr;
  uint32_t data;
  uint32_t i, j;

  wr_ptr = (uint32_t *)SDRAM_BASE;
  short_wr_ptr = (uint16_t *)wr_ptr;
    
  /* 16 bit write */
  for (i = 0; i < SDRAM_SIZE/0x40000; i++)
  {
    for (j = 0; j < 0x100; j++)
    {
      *short_wr_ptr++ = (i + j) & 0xFFFF;
      *short_wr_ptr++ = ((i + j) + 1) & 0xFFFF;
    }
  }

  /* Verifying */
  wr_ptr = (uint32_t *)SDRAM_BASE;
  for (i = 0; i < SDRAM_SIZE/0x40000; i++)
  {
    for (j = 0; j < 0x100; j++)
    {
      data = *wr_ptr;          
      if (data != (((((i + j) + 1) & 0xFFFF) << 16) | ((i + j) & 0xFFFF)))
      {
        return 0x0;
      }
      wr_ptr++;
    }
  }
  return 0x1;
}

#endif
