/******************************************************************************
 * Copyright (c) 2010 Texas Instruments Incorporated - http://www.ti.com
 * 
 *  Redistribution and use in source and binary forms, with or without 
 *  modification, are permitted provided that the following conditions 
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright 
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the 
 *    documentation and/or other materials provided with the   
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 *****************************************************************************/

/******************************************************************************
 *
 * File	Name:       evmc6678.c
 *
 * Description: This contains   TMS320C6678 specific functions.
 * 
 ******************************************************************************/
 
/************************
 * Include Files
 ************************/
#include "platform_internal.h"

 /**
  *  Handle to access BOOTCFG registers.
  */
#define hPscCfg     ((CSL_PscRegs*)CSL_PSC_REGS)
 
 /**
 @}
 */
/* Boot Cfg Registers */
#define   MAINPLLCTL0_REG       (*((volatile unsigned int *) 0x02620328))
#define   MAINPLLCTL1_REG       (*((volatile unsigned int *) 0x0262032C))
#define   DDR3PLLCTL0_REG       (*((volatile unsigned int *) 0x02620330))
#define   DDR3PLLCTL1_REG       (*((volatile unsigned int *) 0x02620334))
/* PA PLL Registers */
#define   PAPLLCTL0_REG         (*((volatile unsigned int *) 0x02620338))
#define   PAPLLCTL1_REG         (*((volatile unsigned int *) 0x0262033C))

/*PLL controller registers*/
#define   PLLCTL_REG            (*((volatile unsigned int *) 0x02310100))
#define   SECCTL_REG            (*((volatile unsigned int *) 0x02310108))
#define   PLLM_REG              (*((volatile unsigned int *) 0x02310110))
#define   PLLCMD_REG            (*((volatile unsigned int *) 0x02310138))
#define   PLLSTAT_REG           (*((volatile unsigned int *) 0x0231013C))
#define   PLLDIV2_REG           (*((volatile unsigned int *) 0x0231011C))
#define   PLLDIV5_REG           (*((volatile unsigned int *) 0x02310164))
#define   PLLDIV8_REG           (*((volatile unsigned int *) 0x02310170))
#define   PREDIV_REG            (*((volatile unsigned int *) 0x02310114))


CSL_Status CorePllcHwSetup (
    PllcHwSetup          *hwSetup
)
{
    CSL_Status       status = CSL_SOK;
    volatile unsigned int i, loopCount;
    unsigned int ctl,secctl, pllstatus;

    /* Unlock the Boot Config */
    CSL_BootCfgUnlockKicker();

    /*In PLLCTL, write PLLENSRC = 0 (enable PLLEN bit)*/    
    /* Program pllen=0 (pll bypass), pllrst=1 (reset pll), pllsrc = 0 */

    ctl         = PLLCTL_REG;
    ctl        &= ~(0x00000031);
    PLLCTL_REG = ctl;

    /* Enable secondary controller pll bypass */
    secctl     = SECCTL_REG;
    secctl     |= 1 << 23;
    SECCTL_REG = secctl;


/* PLL WORK AROUND FOR THE SI BUG */
    /* Reset the PLL, wait at least 5 us, release reset */
    ctl = ctl | 2;
    PLLCTL_REG = ctl;

    loopCount = 50000;
    while (loopCount--) {
        asm("   NOP");
    }

    ctl = ctl & ~2;
    PLLCTL_REG = ctl;

    loopCount = 50000;
    while (loopCount--) {
        asm("   NOP");
    }

    
    /* Reset the PLL */
      ctl = ctl | (1 << 3);
      PLLCTL_REG = ctl;
/* WORK AROUND ENDS */

    /* Enable the pll divider */
    secctl = SECCTL_REG;
    secctl |= (1 << 16);
    secctl |= (1 << 19);
    SECCTL_REG = secctl;

    MAINPLLCTL0_REG  = hwSetup->preDiv & 0x3f; /* PLLD[5:0] */
    MAINPLLCTL0_REG |= (((hwSetup->pllM) >> 6) & 0x7f) << 12; /* PLLM[12:6] */
    PLLM_REG   = hwSetup->pllM & 0x3f; /* PLLM[5:0] */

    MAINPLLCTL0_REG      |= (((hwSetup->pllM+1)>>1)-1) << 24;  /* BWADJ bits */

    /* PLL Advisory 9 fix */
    MAINPLLCTL1_REG      |= 1 << 6;

    /*If necessary program PLLDIV1n.  Note that you must aplly the GO operation
     to change these dividers to new ratios*/
     if (hwSetup->divEnable & PLLC_DIVEN_PLLDIV2) {
        PLLDIV2_REG = (hwSetup->pllDiv2) | 0x00008000;        
     }
     if (hwSetup->divEnable & PLLC_DIVEN_PLLDIV5) {
        PLLDIV5_REG = (hwSetup->pllDiv5) | 0x00008000;
     }
     if (hwSetup->divEnable & PLLC_DIVEN_PLLDIV8) {
        PLLDIV8_REG = (hwSetup->pllDiv8) | 0x00008000;
     }

    /*Set GOSET bit in PLLCMD to initiate the GO operation to change the divide
    values and align the SYSCLKs as programmed */
    PLLCMD_REG |= 0x00000001;

    loopCount = 2000;
    while (loopCount--) {
        asm("   NOP");
    }

    /* set pllrst to 0 to deassert pll reset */
    ctl = ctl & ~(1<<3);
    PLLCTL_REG = ctl;


    /* wait for the pll to lock, but don't trap if lock is never read */
    for (i = 0; i < 100; i++)  {
        loopCount = 2000;
        while (loopCount--) {
            asm("   NOP");
        }
      pllstatus = PLLSTAT_REG;
      if ( (pllstatus & 0x1) != 0 )
        break;
    }

    /* Clear the secondary controller bypass bit */
    secctl = secctl & ~(1<<23);
    SECCTL_REG = secctl;
    

    /* Set pllen to 1 to enable pll mode */
    ctl = ctl | 0x1;
    PLLCTL_REG = ctl;

    loopCount = 8000;
    while (loopCount--) {
        asm("   NOP");
    }
    
    CSL_BootCfgLockKicker();
    
    return status;
}

CSL_Status CorePllcGetHwSetup (
    PllcHwSetup             *hwSetup
)
{
    CSL_Status       status   = CSL_SOK;

    /* Unlock the Boot Config */
    CSL_BootCfgUnlockKicker();

    hwSetup->divEnable = 0;

    hwSetup->pllM       = (PLLM_REG & 0x3F);
    hwSetup->preDiv     = PREDIV_REG;
    hwSetup->pllDiv2    = PLLDIV2_REG ;
    hwSetup->pllDiv5    = PLLDIV5_REG;
    hwSetup->pllDiv8    = PLLDIV8_REG;

    /* Make sure no GO operation is pending*/
    while((PLLSTAT_REG) & 0x00000001);    

    CSL_BootCfgLockKicker();

    return status;
}

#define BYPASS_BIT_SHIFT 23
#define CLKF_BIT_SHIFT   6
#define PA_PLL_BYPASS_MASK (1 << BYPASS_BIT_SHIFT)    /* Tells whether the PA PLL is in BYPASS mode or not */
#define PA_PLL_CLKOD_MASK  (0x00780000) /* Tells the output divider value for the PA PLL */
#define PA_PLL_CLKF_MASK   (0x0007FFC0) /* Tells the multiplier value for the PA PLL */
#define PA_PLL_CLKR_MASK   (0x0000003F) /* Tells the divider value for the PA PLL */
#define PA_PLL_RESET_MASK  (0x00004000) 
#define PA_PLLM_VAL        (335)
#define PA_PLLD_VAL        (24)

/* Set the desired PA PLL configuration -- assumes 156.25 MHz input clock, should yield 1050 MHz output */
CSL_Status SetPaPllConfig() {
    CSL_Status       status   = CSL_SOK;
    Uint8        passclksel; //   = (DEVSTAT_REG & CSL_BOOTCFG_BOOT_REG0_PA_REFCLK_SEL_MASK);
    unsigned int papllctl0val = PAPLLCTL0_REG;
    unsigned int papllctl1val = PAPLLCTL1_REG;
    unsigned int papllbypass  = 0;
    unsigned int papllclkf    = 19;
    volatile unsigned int loopCount;

    passclksel = CSL_BootCfgGetPARefClockSelect();

    if (passclksel == 0) {
       IFPRINT(platform_write("WARNING: SYSCLK/ALTCORECLK is the input to the PA PLL.\n"));
    }
  
    /* Unlock the Boot Config */
    CSL_BootCfgUnlockKicker();

    /* Advisory 9 fix */
    PAPLLCTL1_REG      |= 1 << 6;
    
    /* write PA */
    PAPLLCTL0_REG &= (~PA_PLL_BYPASS_MASK); //clear bypass bit

  /* Wait 4 cycles for the slowest of PLLOUT or reference clock source (CLKIN) */
  loopCount = 100;
  while (loopCount--) {
      asm("   NOP");
  }

  /* put the PA PLL in reset */
  PAPLLCTL1_REG|= PA_PLL_RESET_MASK;

  /*Wait for PLL to properly reset (128 CLKIN1 cycles) */
  loopCount = 1000;
  while (loopCount--) {
      asm("   NOP");
  }

  /* Program the multiplier value */
  PAPLLCTL0_REG &= (~PA_PLL_CLKF_MASK);          //clear multiplier value
  PAPLLCTL0_REG |= (papllclkf<<CLKF_BIT_SHIFT);  

  /* take the PA PLL out of reset */
  PAPLLCTL1_REG &= (~PA_PLL_RESET_MASK);

  /*Wait for PLL to lock (2000 CLKIN1 cycles) */
  loopCount = 5000;
  while (loopCount--) {
      asm("   NOP");
  }

  /* enable PLL mode */
  PAPLLCTL0_REG|= (papllbypass<<BYPASS_BIT_SHIFT);

  loopCount = 4000;
  while (loopCount--) {
      asm("   NOP");
  }
  
  /* Lock Chip Level Registers */
  CSL_BootCfgLockKicker();

  return status;

}

/***************************************************************************************
 * FUNCTION PURPOSE: Power up all the power domains
 ***************************************************************************************
 * DESCRIPTION: this function powers up the PA subsystem domains
 ***************************************************************************************/
void PowerUpDomains (void)
{


    /* PASS power domain is turned OFF by default. It needs to be turned on before doing any 
     * PASS device register access. This not required for the simulator. */

    /* Set PASS Power domain to ON */        
    CSL_PSC_enablePowerDomain (CSL_PSC_PD_ALWAYSON);

    /* Enable the clocks for PASS modules */
    CSL_PSC_setModuleNextState (CSL_PSC_LPSC_EMIF4F, PSC_MODSTATE_ENABLE);
    CSL_PSC_setModuleNextState (CSL_PSC_LPSC_EMIF25_SPI,  PSC_MODSTATE_ENABLE);

    /* Start the state transition */
    CSL_PSC_startStateTransition (CSL_PSC_PD_ALWAYSON);

    /* Wait until the state transition process is completed. */
    while (!CSL_PSC_isStateTransitionDone (CSL_PSC_PD_ALWAYSON));


    /* PASS power domain is turned OFF by default. It needs to be turned on before doing any 
     * PASS device register access. This not required for the simulator. */

    /* Set PASS Power domain to ON */        
    CSL_PSC_enablePowerDomain (CSL_PSC_PD_PASS);

    /* Enable the clocks for PASS modules */
    CSL_PSC_setModuleNextState (CSL_PSC_LPSC_PKTPROC, PSC_MODSTATE_ENABLE);
    CSL_PSC_setModuleNextState (CSL_PSC_LPSC_CPGMAC,  PSC_MODSTATE_ENABLE);
    CSL_PSC_setModuleNextState (CSL_PSC_LPSC_Crypto,  PSC_MODSTATE_ENABLE);

    /* Start the state transition */
    CSL_PSC_startStateTransition (CSL_PSC_PD_PASS);

    /* Wait until the state transition process is completed. */
    while (!CSL_PSC_isStateTransitionDone (CSL_PSC_PD_PASS));
}

CSL_Status SetDDR3PllConfig() {
 
  CSL_Status       status   = CSL_SOK;
  Int32            loopCount;

  /* Unlock the Boot Config */
  CSL_BootCfgUnlockKicker();

  DDR3PLLCTL0_REG = 0x0A0804C0;

  /* Wait for PLL to lock */
  loopCount = 4000;
  while (loopCount--) {
      asm("   NOP");
  }

  /* Lock Chip Level Registers */
  CSL_BootCfgLockKicker();

  return status;
}


/*--------------------------------------------------------------*/
/* xmc_setup()                                                  */
/* XMC MPAX register setting to access DDR3 config space        */
/*--------------------------------------------------------------*/

#define XMC_BASE_ADDR (0x08000000)
#define XMPAX2_L     (*(int*)(XMC_BASE_ADDR + 0x00000010))
#define XMPAX2_H     (*(int*)(XMC_BASE_ADDR + 0x00000014))

#define DATA0_GTLVL_INIT_RATIO	(*(int*)(0x0262043C))
#define DATA1_GTLVL_INIT_RATIO	(*(int*)(0x02620440))
#define DATA2_GTLVL_INIT_RATIO	(*(int*)(0x02620444))
#define DATA3_GTLVL_INIT_RATIO	(*(int*)(0x02620448))
#define DATA4_GTLVL_INIT_RATIO	(*(int*)(0x0262044C))
#define DATA5_GTLVL_INIT_RATIO	(*(int*)(0x02620450))
#define DATA6_GTLVL_INIT_RATIO	(*(int*)(0x02620454))
#define DATA7_GTLVL_INIT_RATIO	(*(int*)(0x02620458))
#define DATA8_GTLVL_INIT_RATIO	(*(int*)(0x0262045C))

#define RDWR_INIT_RATIO_0	(*(int*)(0x0262040C))
#define RDWR_INIT_RATIO_1	(*(int*)(0x02620410))
#define RDWR_INIT_RATIO_2	(*(int*)(0x02620414))
#define RDWR_INIT_RATIO_3	(*(int*)(0x02620418))
#define RDWR_INIT_RATIO_4	(*(int*)(0x0262041C))
#define RDWR_INIT_RATIO_5	(*(int*)(0x02620420))
#define RDWR_INIT_RATIO_6	(*(int*)(0x02620424))
#define RDWR_INIT_RATIO_7	(*(int*)(0x02620428))
#define RDWR_INIT_RATIO_8	(*(int*)(0x0262042C))

#define DATA0_WRLVL_INIT_RATIO  (*(unsigned int*)(0x0262040C))
#define DATA1_WRLVL_INIT_RATIO  (*(unsigned int*)(0x02620410))
#define DATA2_WRLVL_INIT_RATIO  (*(unsigned int*)(0x02620414))
#define DATA3_WRLVL_INIT_RATIO  (*(unsigned int*)(0x02620418))
#define DATA4_WRLVL_INIT_RATIO  (*(unsigned int*)(0x0262041C))
#define DATA5_WRLVL_INIT_RATIO  (*(unsigned int*)(0x02620420))
#define DATA6_WRLVL_INIT_RATIO  (*(unsigned int*)(0x02620424))
#define DATA7_WRLVL_INIT_RATIO  (*(unsigned int*)(0x02620428))
#define DATA8_WRLVL_INIT_RATIO  (*(unsigned int*)(0x0262042C))


void xmc_setup()
{  
    /* mapping for ddr emif registers XMPAX*2 */
    XMPAX2_L =  0x100000FF;     /* replacement addr + perm*/
    XMPAX2_H =  0x2100000B;    /* base addr + seg size (64KB)*/	//"1B"-->"B" by xj
}

/* Set the desired DDR3 configuration -- assumes 66.67 MHz DDR3 clock input */
CSL_Status DDR3Init() {

    CSL_Status              status   = CSL_SOK;    
    volatile unsigned int loopCount;

    CSL_BootCfgUnlockKicker();        

   /***************** 2.2 DDR3 PLL Configuration ************/

    DDR3PLLCTL1_REG      |= 0x00000040;      //Set ENSAT bit = 1
    DDR3PLLCTL1_REG      |= 0x00002000;      //Set RESET bit = 1
    DDR3PLLCTL0_REG       = 0x090804C0;       //Configure CLKR, CLKF, CLKOD, BWADJ;

    /* Wait for 5us min reset to complete  */
    loopCount = 10000;
    while (loopCount--) {
        asm("   NOP");
    }
    DDR3PLLCTL1_REG      &= ~(0x00002000);   //Clear RESET bit

   /* Wait for PLL to lock = min 500 ref clock cycles. 
      With refclk = 100MHz, = 5000 ns = 5us */
    loopCount = 10000;
    while (loopCount--) {
        asm("   NOP");
    }
    /**************** 3.0 Leveling Register Configuration ********************/
    /* Using partial automatic leveling due to errata */

    /**************** 3.2 Invert Clock Out ********************/
    hBootCfg->DDR3_CONFIG_REG[0] &= ~(0x007FE000);  // clear ctrl_slave_ratio field
    hBootCfg->DDR3_CONFIG_REG[0] |= 0x00200000;     // set ctrl_slave_ratio to 0x100
    hBootCfg->DDR3_CONFIG_REG[12] |= 0x08000000;    // Set invert_clkout = 1
    hBootCfg->DDR3_CONFIG_REG[0] |= 0xF;            // set dll_lock_diff to 15
    hBootCfg->DDR3_CONFIG_REG[23] |= 0x00000200;    //Set bit 9 = 1 to use forced ratio leveling for read DQS

    /*Values with invertclkout = 1 */
    /**************** 3.3+3.4 Partial Automatic Leveling ********************/
    DATA0_WRLVL_INIT_RATIO = 0x20;
    DATA1_WRLVL_INIT_RATIO = 0x24;
    DATA2_WRLVL_INIT_RATIO = 0x3A;
    DATA3_WRLVL_INIT_RATIO = 0x38;
    DATA4_WRLVL_INIT_RATIO = 0x51;
    DATA5_WRLVL_INIT_RATIO = 0x5E;
    DATA6_WRLVL_INIT_RATIO = 0x5E;
    DATA7_WRLVL_INIT_RATIO = 0x5E;
    DATA8_WRLVL_INIT_RATIO = 0x44;

    DATA0_GTLVL_INIT_RATIO = 0xA1;
    DATA1_GTLVL_INIT_RATIO = 0x9E;
    DATA2_GTLVL_INIT_RATIO = 0xA7;
    DATA3_GTLVL_INIT_RATIO = 0xA9;
    DATA4_GTLVL_INIT_RATIO = 0xCA;
    DATA5_GTLVL_INIT_RATIO = 0xBE;
    DATA6_GTLVL_INIT_RATIO = 0xDD;
    DATA7_GTLVL_INIT_RATIO = 0xDD;
    DATA8_GTLVL_INIT_RATIO = 0xBA;

    /*Do a PHY reset. Toggle DDR_PHY_CTRL_1 bit 15 0->1->0 */
    hEmif->DDR_PHY_CTRL_1  &= ~(0x00008000);
    hEmif->DDR_PHY_CTRL_1  |= (0x00008000);
    hEmif->DDR_PHY_CTRL_1  &= ~(0x00008000);

    /***************** 2.3 Basic Controller and DRAM configuration ************/
    hEmif->SDRAM_REF_CTRL    = 0x00005162;    // enable configuration 

    hEmif->SDRAM_TIM_1   = 0x1113783C;
    hEmif->SDRAM_TIM_2   = 0x304F7FE3;
    hEmif->SDRAM_TIM_3   = 0x559F849F;

    hEmif->DDR_PHY_CTRL_1   = 0x0010010F;
    hEmif->ZQ_CONFIG        = 0x70073214; 
    hEmif->PWR_MGMT_CTRL    = 0x0;
 
    /* New value with DYN_ODT disabled and SDRAM_DRIVE = RZQ/7 */ 
    hEmif->SDRAM_CONFIG     = 0x63062A32; 
    hEmif->SDRAM_REF_CTRL   = 0x00001450;       //Refresh rate = (7.8*666MHz]

    hEmif->RDWR_LVL_RMP_CTRL      =  0x80000000; //enable full leveling
    hEmif->RDWR_LVL_CTRL          =  0x80000000; //Trigger full leveling - This ignores read DQS leveling result and uses ratio forced value 

    /************************************************************
      Wait for min 1048576 DDR clock cycles for leveling to complete 
        = 1048576 * 1.5ns = 1572864ns = 1.57ms.
      Actual time = ~10-15 ms 
     **************************************************************/
    loopCount = 1600000;
    while (loopCount--) {
        asm("   NOP");
    }

    /* Lock Chip Level Registers */
    CSL_BootCfgLockKicker();
    
    return (status);
    
}

/* Nothing past this point */


