//***********************************************************************************************//
// Description:
//             ddr basic testcase : write data to ddr and read them out to verify ddr access. 
//                                  with switched clock -- rcc setting first.
//                                  Equals to case "cb00_rcc_basic" + case "ca00_ddr_basic".
//                                  ddr 0 and ddr 1 access interleaved.
//***********************************************************************************************//

#include "lisoc_test.h"
#include "ddr_test.h"
#include "ddr4.h"
#include "rcc.h"
#include "uart.h"
#include "datapath.h"

#define DDR1_CTL_BASE_ADDR     0x40040000
#define DDR0_CTL_BASE_ADDR     0x40030000
#define DDR1_PHY_BASE_ADDR     0x40020000
#define DDR0_PHY_BASE_ADDR     0x40010000
#define DDR0_DAT_BASE_ADDR     0x60000000
#define DDR1_DAT_BASE_ADDR     0x80000000

#define ctl0_phy_init_complete   (DDR0_CTL_BASE_ADDR + 0x2c4)
#define ctl0_sdram_init_done     (DDR0_CTL_BASE_ADDR + 0x2c4)
#define phy0_calib_end           (DDR0_PHY_BASE_ADDR + 0x20c)
#define phy0_calib_done_byte     (DDR0_PHY_BASE_ADDR + 0x20c)
#define ctl1_phy_init_complete   (DDR1_CTL_BASE_ADDR + 0x2c4)
#define ctl1_sdram_init_done     (DDR1_CTL_BASE_ADDR + 0x2c4)
#define phy1_calib_end           (DDR1_PHY_BASE_ADDR + 0x20c)
#define phy1_calib_done_byte     (DDR1_PHY_BASE_ADDR + 0x20c)

uint32_t r_ddr[128];
uint32_t r1_ddr[128];


uint32_t w_ddr[4] = {
  0x12345678,0x5a5a5a5a,0x55555555,0xa5a5a5a5
};

void ddr_wr_test(uint32_t ddr_data_base,uint32_t size)
{
  uint32_t* ddr = (uint32_t*)ddr_data_base;
  uint32_t i;
  uint8_t result = SUCCESS;
  uint32_t ddr_cnt;
  ddr_cnt = 0;

  for(i = 0; i < size/4; i++) {
    ddr[i] = w_ddr[0];
    //delay_us(1);
  }

  for(i = 0; i < size/4; i++) {
    #if 0
    if(ddr[i] != w_ddr[0])
      ddr[i] = w_ddr[0];
    #endif
    if(ddr[i] != w_ddr[0]) {
      result = FAILURE;
      //printf("0x%08x:%x\n",ddr_data_base + i*4,ddr[i]);
      ddr_cnt++;
    }
  }
  #if 0
  for(i = 0; i < size/4; i++) {
    if(i % 4 == 0)
      printf("%08x:",ddr_data_base + offset + i*4);
    printf(" %08x ",r_ddr[i]);
    if(i % 4 == 3)
      printf("\n");
  }
  #endif
  if(result == SUCCESS){
    if(ddr_data_base < DDR1_DAT_BASE_ADDR)
      printf("DDR0 0x%x test \t\t\t\t\tOK.\n",ddr_data_base);
    else
      printf("DDR1 0x%x test \t\t\t\t\tOK.\n",ddr_data_base);
  }else{
    if(ddr_data_base < DDR1_DAT_BASE_ADDR)
      printf("DDR0 0x%x test \t\t\t\tNG cnt:%d.\n",ddr_data_base,ddr_cnt);
    else
      printf("DDR1 0x%x test \t\t\t\tNG cnt:%d.\n",ddr_data_base,ddr_cnt);
  }
}

void ddr_init(void)
{
  if(test_cmd >= FHD60_RAW12_YUV422_8_DQ16_TEST && test_cmd <= UHD60_RAW10_YUV422_8_DQ16_TEST){
    // 1. ddr0 and ddr1 initial
    // 1.1 ddr0 initial
    init_ddr_dq16(DDR0_CTL_BASE_ADDR, DDR0_PHY_BASE_ADDR);
    //printf("ddr0 init complete\n");
    // 1.2 ddr1 initial
    init_ddr_dq16(DDR1_CTL_BASE_ADDR, DDR1_PHY_BASE_ADDR);
  }else{
    // 1. ddr0 and ddr1 initial
    // 1.1 ddr0 initial
    init_ddr(DDR0_CTL_BASE_ADDR, DDR0_PHY_BASE_ADDR);
    printf("ddr0 init complete\n");
    // 1.2 ddr1 initial
    init_ddr(DDR1_CTL_BASE_ADDR, DDR1_PHY_BASE_ADDR);
    printf("ddr1 init complete\n");
  }
}

void ddr_test(void)
{
  printf("ddr test start\n");
  //ddr_wr_test(DDR0_DAT_BASE_ADDR,0x20000000,0);
  //ddr_wr_test(DDR1_DAT_BASE_ADDR,0x20000000,0);
  ddr_wr_test(DDR0_DAT_BASE_ADDR + 0x00000000,0x10000000);
  ddr_wr_test(DDR0_DAT_BASE_ADDR + 0x10000000,0x10000000);

  ddr_wr_test(DDR1_DAT_BASE_ADDR + 0x00000000,0x10000000);
  ddr_wr_test(DDR1_DAT_BASE_ADDR + 0x10000000,0x10000000);

  
  printf("ddr test finish.\n");
}

