/*H***************************************************************************
*
* $Archive:: /boards/dsk6455_v2/lib/dsk6455bsl/dsk6455m.c                     $
* $Revision:: 3                                                               $
* $Date:: 6/29/06 9:44a                                                       $
*
* DESCRIPTION: DSK6455 board initializion implementation.
* 
* NOTES :  BSL Version# 3.24 
*
* (C) Copyright 2005 by Spectrum Digital Incorporated
* All rights reserved
*
*H***************************************************************************/
#include "dsk6455m.h"

#define PLL1_BASE_ADDR (0x029A0000)

#define PLL1_PLLCTL    (*(volatile Uint32*)(PLL1_BASE_ADDR + 0x00000100))
#define PLL1_PLLM      (*(volatile Uint32*)(PLL1_BASE_ADDR + 0x00000110)) 
#define PLL1_PREDIV    (*(volatile Uint32*)(PLL1_BASE_ADDR + 0x00000114))
#define PLL1_PLLDIV3   (*(volatile Uint32*)(PLL1_BASE_ADDR + 0x00000120))
#define PLL1_PLLCMD    (*(volatile Uint32*)(PLL1_BASE_ADDR + 0x00000138))
#define PLL1_PLLSTAT   (*(volatile Uint32*)(PLL1_BASE_ADDR + 0x0000013C))
#define PLL1_DCHANGE   (*(volatile Uint32*)(PLL1_BASE_ADDR + 0x00000144))
#define PLL1_SYSTAT    (*(volatile Uint32*)(PLL1_BASE_ADDR + 0x00000150))
#define PLL1_PLLDIV4   (*(volatile Uint32*)(PLL1_BASE_ADDR + 0x00000160))

#define PLL2_BASE_ADDR (0x029C0000)

#define PLL2_PLLCTL    (*(volatile Uint32*)(PLL2_BASE_ADDR + 0x00000100)) // PLL2 control register
#define PLL2_PLLM      (*(volatile Uint32*)(PLL2_BASE_ADDR + 0x00000110)) // PLL2 multiplier control register 
#define PLL2_PREDIV    (*(volatile Uint32*)(PLL2_BASE_ADDR + 0x00000114)) // PLL2 pre-divider control register
#define PLL2_PLLDIV1   (*(volatile Uint32*)(PLL2_BASE_ADDR + 0x00000118)) // PLL2 controller divider 1 register
#define PLL2_PLLCMD    (*(volatile Uint32*)(PLL2_BASE_ADDR + 0x00000138)) // PLL2 controller command register
#define PLL2_PLLSTAT   (*(volatile Uint32*)(PLL2_BASE_ADDR + 0x0000013C)) // PLL2 controller status register
#define PLL2_DCHANGE   (*(volatile Uint32*)(PLL2_BASE_ADDR + 0x00000144)) // PLL2 PLLDIV ratio change status register
#define PLL2_SYSTAT    (*(volatile Uint32*)(PLL2_BASE_ADDR + 0x00000150)) // PLL2 SYSCLK status register

#define EMIFA_BASE_ADDR (0x70000000)

#define EMIFA_MIDR     (*(volatile Uint32*)(EMIFA_BASE_ADDR + 0x00000000))
#define EMIFA_STAT     (*(volatile Uint32*)(EMIFA_BASE_ADDR + 0x00000004))
#define EMIFA_BPRIO    (*(volatile Uint32*)(EMIFA_BASE_ADDR + 0x00000020))
#define EMIFA_CE2CFG   (*(volatile Uint32*)(EMIFA_BASE_ADDR + 0x00000080))
#define EMIFA_CE3CFG   (*(volatile Uint32*)(EMIFA_BASE_ADDR + 0x00000084))
#define EMIFA_CE4CFG   (*(volatile Uint32*)(EMIFA_BASE_ADDR + 0x00000088))
#define EMIFA_CE5CFG   (*(volatile Uint32*)(EMIFA_BASE_ADDR + 0x0000008C))
#define EMIFA_AWCC     (*(volatile Uint32*)(EMIFA_BASE_ADDR + 0x000000A0))

#define DDR_BASE_ADDR (0x78000000)

#define DDR_MIDR     (*(volatile Uint32*)(DDR_BASE_ADDR + 0x00000000))
#define DDR_SDCFG    (*(volatile Uint32*)(DDR_BASE_ADDR + 0x00000008))
#define DDR_SDRFC    (*(volatile Uint32*)(DDR_BASE_ADDR + 0x0000000C))
#define DDR_SDTIM1   (*(volatile Uint32*)(DDR_BASE_ADDR + 0x00000010))
#define DDR_SDRIM2   (*(volatile Uint32*)(DDR_BASE_ADDR + 0x00000014))
#define DDR_DDRPHYC  (*(volatile Uint32*)(DDR_BASE_ADDR + 0x000000E4))

/* Initialize the board */
void DSK6455M_init()
{
    volatile Uint32 test;
	volatile Uint32 *pcfg;

    /* This section is coded such that the next two statements will execute in */
	/* under 16 SYSCLK3 cycles */
	pcfg = (volatile Uint32 *)0x2ac0004;

    /* Unlock PERCFG0 through PERLOCK */
	*pcfg++ = 0x0f0a0b00;

    /* Enable EMAC, Timers, McBSPs, I2C, GPIO in PERCFG0 */
    *pcfg = 0xC0015555;

    /* Read back PERSTAT0 */
    test = *((Uint32 *)0x02AC0014);

    /* Wait at least 128 CPU cycles */
    DSK6455M_wait(128);

	/* Enable DDR and EMIFA in PERCFG1 */
	*((Uint32 *)0x02AC002C) = 0x3;

    /* Initialize PLL */
    HimalayaM_PLL1_Init(20);  // For board rev > 0, 50MHz CLKIN

    HimalayaM_PLL2_Init();

	/* Configure async EMIF */
    EMIFA_CE2CFG = 0x00240120; /* 8-bit async, 10 cycle read/write strobe */
    EMIFA_CE3CFG = 0x00240120; /* 8-bit async, 10 cycle read/write strobe */
    EMIFA_CE4CFG = 0x00240122; /* 32-bit async, 10 cycle read/write strobe */
    EMIFA_CE5CFG = 0x00240122; /* 32-bit async, 10 cycle read/write strobe */
    EMIFA_BPRIO  = 0x000000FE; /* Enable priority based starvation control SPRU971A sec. 7.2 */

	/* Configure DDR for 500MHz operation */
    DDR_SDCFG    = 0x00D38822; /* Unlock boot + timing, CAS4, 4 banks, 10 bit column */
    DSK6455M_waitusec(200);

    DDR_SDRFC    = 0x000007A2; /* Refresh */
    DDR_SDTIM1   = 0x3EDB4B91; /* Timing 1 */
    DDR_SDRIM2   = 0x00A2C722; /* Timing 2 */
    DDR_DDRPHYC  = 0x00000005; /* PHY read latency for CAS 4 is 4 + 2 - 1 */

    DDR_SDCFG    = 0x00538822; /* Lock, CAS4, 4 banks, 10 bit column, lock timing */
    DSK6455M_waitusec(200);
    
   	DSK6455M_I2C_init();
}
Uint32 HimalayaM_PLL1_Init (Uint32 multi_val)
{

   Uint32 i;

   /*------------------------------------------------------------------*/
   /* STEP 1: In PLLCTL, write PLLENSRC = 0 to enable PLLEN bit        */
   /*------------------------------------------------------------------*/  
    PLL1_PLLCTL = (PLL1_PLLCTL & 0xFFFFFFDF);
         
   /*------------------------------------------------------------------*/
   /* STEP 2: In PLLCTL, write PLLEN = 0 (Bypass mode)                 */
   /*------------------------------------------------------------------*/
    PLL1_PLLCTL = (PLL1_PLLCTL & 0xFFFFFFFE);

   /*------------------------------------------------------------------*/
   /* STEP 3: Wait min 4 cycles of the CLKIN1                          */
   /*------------------------------------------------------------------*/
    for (i=0; i<32; i++) {}

   /*------------------------------------------------------------------*/
   /* STEP 4: In PLLCTL, write PLLRST = 1 (PLL is reset)               */
   /*------------------------------------------------------------------*/
    PLL1_PLLCTL = (PLL1_PLLCTL | 0x8);

   /*------------------------------------------------------------------*/
   /* STEP 5: Program PREDIV and PLLM      			       */
   /*------------------------------------------------------------------*/
    
    /* Part A, set PREDIV to /1 */
    PLL1_PREDIV = ((PLL1_PREDIV & 0xFFFFFFE0) | 0x00008000);

    /* Make sure multi-val is non zero */
    if (multi_val == 0) 
    {
        multi_val = 1;
    }

    /* Part B, set PLLM to multi_val */
    PLL1_PLLM = (multi_val - 1);

   /*------------------------------------------------------------------*/
   /* STEP 6: Wait for PLL to Reset Properly                           */
   /*------------------------------------------------------------------*/
    for (i=0; i<256; i++) {}	/* minimum 128 CLKIN1 cycles */
				/* @ CLKIN1 = 60MHz => 16.7ns * 256 = 4.3 us */

   /*------------------------------------------------------------------*/
   /* STEP 7: In PLLCTL, write PLLRST = 0 to bring PLL out of Reset    */
   /*------------------------------------------------------------------*/
    PLL1_PLLCTL = (PLL1_PLLCTL & 0xFFFFFFF7);

   /*-------------------------------------------------------------------*/
   /* STEP 8: Wait for PLL to lock, allow atleast 2000 cycles of CLKIN1 */
   /*-------------------------------------------------------------------*/
    for (i=0; i<4096; i++) {}	/* minimum 2000 CLKIN1 cycles */
				/* @ CLKIN1 = 60MHz => 16.7ns * 4096 = 68.4us */

   /*------------------------------------------------------------------*/
   /* STEP 9: In PLLCTL, write PLLEN = 1 to enable PLL mode            */
   /*------------------------------------------------------------------*/
    PLL1_PLLCTL = (PLL1_PLLCTL | 0x1);
    
   /*------------------------------------------------------------------*/
   /* Now PLL1 Controller is initialized to PLL mode                   */
   /*------------------------------------------------------------------*/
    return (1);

}

/*--------------------------------------------------------------*/
/* Himalaya_PLL2_Init()                                             */
/* Clock setup for the RGMII interface                          */
/*--------------------------------------------------------------*/

Uint32 HimalayaM_PLL2_Init ()
{
    //*(int *)PLLDIV1_2 = (5 - 1) | 0x8000;        /* set PLLDIV1 */
    PLL2_PLLDIV1 = (5 - 1) | 0x00008000; 

    /* Check that the GOSTAT bit in PLLSTAT is cleared to show that no GO operation is currently in progress.*/
    while( (PLL2_PLLSTAT) & 0x00000001);

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

    /* Read the GOSTAT bit in PLLSTAT to make sure the bit returns to 0 to indicate that the GO operation has completed.*/
    while( (PLL2_PLLSTAT) & 0x00000001);
   
    return(1);
}

/* Spin in a delay loop for delay iterations */
void DSK6455M_wait(Uint32 delay)
{
    volatile Uint32 i, n;

    n = 0;
    for (i = 0; i < delay; i++)
    {
        n = n + 1;
    }
}

/* Spin in a delay loop for delay microseconds */
void DSK6455M_waitusec(Uint32 delay)
{
    DSK6455M_wait(delay * 39);
}

