/*******************************************************************************
* $Source$
* $Revision$
* $Date$
*
* Copyright (C) 1990-2000 Texas Instruments Incorporated.
* All rights reserved.
*******************************************************************************/
/*******************************************************************************
* FILENAME
*   post.c
*
* DESCRIPTION
*   Power-On Self-Test code programmed into the TMS320C6211/6711 DSK Flash ROM.
*
* !!NOTE!!
*  Any future revision of this code should reorder the tests such that the
*  timer test is conducted first. In its present form the timer is used in all
*  tests (delay_msec()) prior to its own specific test. This could allow a timer
*  failure to be misdiagnosed as another test's failure(code displayed on LEDs).
* !!NOTE!!
*
* PUBLIC FUNCTIONS
*   None.
*
* PRIVATE FUNCTIONS
*   All.
*
* AUTHOR
*   Zhaohong Zhang, Tom Dillon
*
* NOTES
*   This source code is ultimately used to create a JEDEC programming file used
*   to program the Flash ROM on the 'C6211/C6711 DSK.
*
* UPDATE
*   Changed SDRAM parameters.
*   Reduced time for tests by 90%
*   Updated memory test for depth and alternating pattern
*
*******************************************************************************/
#include <stdio.h>
#include <csl.h>
#include <csl_chip.h>
#include <csl_emif.h>
#include <csl_timer.h>
#include <csl_mcbsp.h>
#include <bsl.h>
#include <bsl_board.h>
#include <bsl_dip.h>
#include "post.h"
//#include "c6211dsk.h"

#define SLOW 500
#define FAST 50 
                                                 
/*******************************************************************************
 * Global variables                                                            *
 *******************************************************************************/
TIMER_Handle hTimer;
TIMER_Config myTimerConfig = {
                   0x00000300,    /* CTL register - CPU CLK/4        */
                   0xFFFFFFFF,    /* PRD register                    */
                   0x00000000     /* CNT register                    */
                   };
MCBSP_Handle hMcbsp;
AD535_Handle hAD535;
AD535_Config myConfig = { AD535_LOOPBACK_DISABLE,
                          AD535_MICGAIN_OFF,
                          AD535_GAIN_0DB,
                          AD535_GAIN_0DB
                        };
  unsigned int user_dip_settings;
  unsigned int pwb_assy_rev;
  int ext_mem_size;
  Uint32 post_speed;
                                                 
short sin_table[] = {0, 23170>>2, 32767>>2, 23170>>2,0, -23170>>2, -32767>>2, -23170>>2}; 

/*******************************************************************************
* FUNCTION : main
*
* ARGUMENTS :
*   VOID
*
* DESCRIPTION :
*   The code, at power-up, executes to perform a series of tests. The LEDs on
*   the DSK display progress codes during execution and a diagnostic or pass
*   code upon detection of an error or completion.
*
* OUTPUTS :
*   
*   LED Diagnostic Codes: (0=off, 1=on)
*   C     L L L
*   O     E E E
*   D     D D D
*   E     2 1 0
*   -     - - -
*   0     0 0 0 Start state
*   1     0 0 1 TEST 1: DSP internal SRAM test
*   2     0 1 0 TEST 2: External SDRAM test
*   3     0 1 1 TEST 3: DSP McBSP0 loopback test
*   4     1 0 0 TEST 4: External codec read/write test
*   5     1 0 1 TEST 5: External codec tone generation test
*   6     1 1 0 TEST 6: External LED and DSP timer tests
*   7     1 1 1 TEST 7: UNUSED/AVAILABLE FOR FUTURE TEST USE
*   BLINK ALL   All tests completed successfully
*
*   INT 0
*
*******************************************************************************/
int main() {

  /* Initialize the chip support and board support libraries, required */
  CSL_init();
  BSL_init();

  /* DSP initialization                                                       */
  CHIP_RSET(CSR,0x100);                 /* Disable all interrupts              */
  CHIP_RSET(IER,1);                     /* Disable all interrupts except NMI   */
  CHIP_RSET(ICR,0xffff);                /* Clear all pending interrupts        */

/******************************************************************************\
 * CONFIGURE EMIF                                                             *
\******************************************************************************/  
  EMIF_configArgs(0x00003300,            /* EMIF global control register         */
               0xFFFFFF30,            /* CE0 - SDRAM                          */
               0xFFFFFF23,            /* CE1 - 32-bit asynch                  */
               0xFFFFFF23,            /* CE2 - 32-bit asynch on daughterboard */
               0xFFFFFF23,            /* CE3 - 32-bit asynch on daughterboard */
               0x07227000,            /* SDRAM control register (100 MHz)     */
               0x0000061A,            /* SDRAM Timing register                */
               0x00054529             /* SDRAM Extension register             */
              );

/******************************************************************************\
 * INITIALIZE TIMER                                                           *
\******************************************************************************/  
  /*  */
  hTimer = TIMER_open(TIMER_DEVANY, TIMER_OPEN_RESET);
  TIMER_config(hTimer, &myTimerConfig);
  TIMER_start(hTimer);
  TIMER_pause(hTimer);

/*-----------------------------------------------------------------------*\
 * Read DIP switches                                                     *
\*-----------------------------------------------------------------------*/
  user_dip_settings=((DIP_get(DIP_3)<<2) +
                     (DIP_get(DIP_2)<<1) +
                      DIP_get(DIP_1)
                    );
  pwb_assy_rev=get_bdrev();   
                                                                              
/*************************************************************************
* Standard 6211 DSK includes 2 MT48LC1M16A1-7 devices =>4MB SDRAM        *
*   16Mb (16-bit x 2 banks x 512K) parts = 2MB / part                    *
*   EMIF_SDCTRL=0x07227000                                               *
*   EMIF_SDEXT=0x54529                         Board Rev = 1             *
*------------------------------------------------------------------------*
* Standard 6711 DSK includes 2 MT48LC4M16A2-8 devices =>16MB SDRAM       *
*   64Mb (16-bit x 4 banks x 1M)   parts = 8MB / part                    *
*   EMIF_SDCTRL=0x57116000                                               *
*   EMIF_SDEXT=0x54529 (Hitachi 0x54509)       Board Rev = 2             *
*------------------------------------------------------------------------*
* Other 6711 DSK configurations are as follows:                          *
*   128Mb (16-bit x 4 banks x 2M)  parts = 16MB / part (=>32MB SDRAM)    *
*   EMIF_SDCTRL=0x53116000                                               *
*   EMIF_SDEXT=0x54529 (Hitachi 0x54509)       Board Rev = 3             *
*   ---------------------------------------------------------------------*
*   256Mb (16-bit x 4 banks x 4M)  parts = 32MB / part (=>64MB SDRAM)    *
*   EMIF_SDCTRL=0x63116000                                               *
*   EMIF_SDEXT=0x54529                         Board Rev = 4             *
*************************************************************************/

  /*-----------------------------------------------------------------------*/
  /* Modify SDRAM parameter value(s) according to board revision           */
  /*-----------------------------------------------------------------------*/
  switch (pwb_assy_rev) {
    case 0: EMIF_RSET(SDCTL,0x07126000);
            ext_mem_size = EXTERNAL_MEM_SIZE;
            break;
    case 1: EMIF_RSET(SDCTL,0x07227000);
            ext_mem_size = EXTERNAL_MEM_SIZE;
            break;
    case 2: EMIF_RSET(SDCTL,0x57116000);
            ext_mem_size = 4*EXTERNAL_MEM_SIZE;
            break;
    case 3: EMIF_RSET(SDCTL,0x53116000);
            ext_mem_size = 8*EXTERNAL_MEM_SIZE;
            break;
    case 4: EMIF_RSET(SDCTL,0x63116000);
            ext_mem_size = 16*EXTERNAL_MEM_SIZE;
            break;
  }

  if(user_dip_settings == 5)
    post_speed=FAST;
  else
    post_speed=SLOW;

  /*****************************************************************************
   * Start state
   ****************************************************************************/
  delay_msec(post_speed);
  LED_off(LED_ALL);           /* turn off all three leds    */
  delay_msec(post_speed);
  

  /*****************************************************************************
   * TEST 1: DSP internal SRAM test
   ****************************************************************************/
  LED_off(LED_ALL);                       /* Display test # on LEDs */
  LED_on(LED_1);
  delay_msec(post_speed);

  if(mem_test(ALL_5,INTERNAL_MEM_START,INTERNAL_MEM_SIZE))
  {
     exit(0);
  } 

  if(mem_test(ALL_A,INTERNAL_MEM_START,INTERNAL_MEM_SIZE))
  {
     exit(0);
  } 

  /*****************************************************************************
   * TEST 2: External SDRAM test
   ****************************************************************************/
  LED_off(LED_ALL);                       /* Display test # on LEDs */
  LED_on(LED_2);
  delay_msec(post_speed);

  if(mem_test_alt(ALT_5A,EXTERNAL_MEM_START,ext_mem_size))
  {
     exit(0);
  } 
 
  if(mem_test_alt(ALT_A5,EXTERNAL_MEM_START,ext_mem_size))
  {
    exit(0);
  } 
 
  /*****************************************************************************
   * TEST 3: DSP McBSP0 loopback test
   ****************************************************************************/
  LED_off(LED_ALL);                       /* Display test # on LEDs */
  LED_on(LED_1);
  LED_on(LED_2);
  delay_msec(post_speed);

  /* open McBSP channel before testing */
  hMcbsp = MCBSP_open(MCBSP_DEV0, MCBSP_OPEN_RESET);

    if (mcbsp0_test () != 0) 
    {
       exit(0);
    } 
  /* close McBSP channel before proceeding */
  MCBSP_close(hMcbsp);
  
  /*****************************************************************************
   * TEST 4: External codec read/write test
   ****************************************************************************/
  LED_off(LED_ALL);                       /* Display test # on LEDs */
  LED_on(LED_3);
  delay_msec(post_speed);

  hAD535 = AD535_open(AD535_localId);
  AD535_config(hAD535, &myConfig);
        
  play_codec(40*post_speed, 0);

  /*****************************************************************************
   * TEST 5: External codec tone generation test
   ****************************************************************************/
  LED_off(LED_ALL);                       /* Display test # on LEDs */
  LED_on(LED_1);
  LED_on(LED_3);
  delay_msec(post_speed);

  play_codec(post_speed, 1);

  /*****************************************************************************
  * TEST 6: External LED and DSP timer tests
  *****************************************************************************/
  LED_off(LED_ALL);                       /* Display test # on LEDs */
  LED_on(LED_2);
  LED_on(LED_3);
  delay_msec(post_speed);

  /*****************************************************************************
  * TEST 7: UNUSED/AVAILABLE FOR FUTURE TEST USE
  *****************************************************************************/

  /*****************************************************************************
  * All tests completed successfully
  *****************************************************************************/
  led_blink(5, 2*post_speed);
 
  return(0);

}

/*******************************************************************************
* FUNCTION : mem_test
*
* ARGUMENTS :
*   INT pattern           <-- Pattern to be written or read from the memory
*   INT start_address     <-- Address from which to start testing memory
*   INT size_in_word      <-- Number of words to test in memory
*
* DESCRIPTION :
*   Write the pattern to memory beginning at the start_address through the
*   number of locations specified by size_in_word. Read the same locations
*   and generate an error if the value read back differs from the pattern
*   written.
*
* OUTPUTS :
*   INT error             <-- True if value read differs from pattern written
*
*******************************************************************************/
int mem_test (int pattern, int start_address, int size_in_word )
{
  int i;
  int error = 0;
  int *mem_ptr = (int *)start_address;

  /* Write pattern to the memory */
  for(i=0;i<size_in_word;i++)
  {
    *mem_ptr++ = pattern;
  }

  /* Read memory and compare contents to the pattern written */
  mem_ptr = (int *)start_address;
  for(i=0;i<size_in_word;i++)
  {
    if ( *mem_ptr++ != pattern) error++;
  }
  return error;
}

/*******************************************************************************
* FUNCTION : mem_test_alt
*
* ARGUMENTS :
*   INT pattern           <-- Pattern to be written or read from the memory
*   INT start_address     <-- Address from which to start testing memory
*   INT size_in_word      <-- Number of words to test in memory
*
* DESCRIPTION :
*   Write the pattern to odd memory locations beginning at the start_address 
*   through the number of locations specified by size_in_word.  AND Write the
*   complement of the pattern to even memory locations. Read the same locations
*   and generate an error if the value read back differs from the pattern
*   written.
*
* OUTPUTS :
*   INT error             <-- True if value read differs from pattern written
*
*******************************************************************************/
int mem_test_alt (int pattern, int start_address, int size_in_word )
{
  int i;
  int temp_read, temp_expected;
  int error = 0;
  int *mem_ptr = (int *)start_address;

  /* Write pattern to the memory */
  for(i=0;i<size_in_word;i++)
  {
	if(i%2)
	  *mem_ptr++ = ~pattern;
	else
	  *mem_ptr++ = pattern;
  }

  /* Read memory and compare contents to the pattern written */
  mem_ptr = (int *)start_address;
  for(i=0;i<size_in_word;i++)
  {
	temp_read = *mem_ptr++;

	if(i%2)
	  temp_expected = ~pattern;
	else
	  temp_expected = pattern;

    if ( temp_read != temp_expected ) error++;
  }
  return error;
}


/*******************************************************************************
* FUNCTION : mcbsp0_test
*
* ARGUMENTS :
*   VOID
*   
* DESCRIPTION :
*   Tests multi-channel serial port 0 in internal loopback mode after setting
*   up its own clock.
*   
* OUTPUTS :
*   INT 0                 <-- If successful
*   
*******************************************************************************/
/*-------------------------------------------------------------------------*/
/* mcbsp0_test() - used to test McBSP0                                     */
/*-------------------------------------------------------------------------*/
int mcbsp0_test()
{
  volatile Uint32 temp =0,temp1;
  	
  /* set up McBSP0 */
  MCBSP_configArgs(hMcbsp,
                0x00C1A001, /* SPCR- serial port control reg.              */
                0x00010040, /* RCR - recieve control reg.16 bit data/frame */
                0x00010040, /* XCR - xmit control reg. 16 bit data/frame   */
                0x2014004A, /* SRGR- sample rate generator, baud rate 1MHz */
                0x00000000, /* MCR - multichannel control reg.             */
                0x00000000, /* RCER- recieve channel enable reg.           */
                0x00000000, /* RCER- recieve channel enable reg.           */
                0x00000A00  /* PCR - pin control reg.                      */
               );
  
  MCBSP_write(hMcbsp, 0xAAAA);
  temp1 = MCBSP_read(hMcbsp);
  while(!MCBSP_rrdy(hMcbsp)); 
  temp1 = MCBSP_read(hMcbsp);
  
  MCBSP_write(hMcbsp, 0x5555);
  while(!MCBSP_xrdy(hMcbsp));
  while(!MCBSP_rrdy(hMcbsp)); 
  temp = MCBSP_read(hMcbsp);
  temp &= 0xffff;

  if (temp != 0x5555)
  {
    temp = 1;
    return temp;
  }
    
  MCBSP_write(hMcbsp, 0xAAAA);
  while(!MCBSP_xrdy(hMcbsp));
  while(!MCBSP_rrdy(hMcbsp)); 
  temp = MCBSP_read(hMcbsp);
  temp &= 0xffff;
    
  if (temp != 0xAAAA)
  {
    temp = 1;
    return temp;
  }    
  return 0;
}

/*******************************************************************************
* FUNCTION : led_blink
*
* ARGUMENTS :
*   INT count             <-- Number of times to blink the LEDs
*   INT ms_period         <-- Time the LED(s) is(are) active (illuminated)
*   
* DESCRIPTION :
*   Toggles the user LEDs for a given count and period (in milliseconds).
*   
* OUTPUTS :
*   VOID
*   
*******************************************************************************/
void led_blink(int count, int ms_period)
{
  int i;
  
  for (i=0;i<count;i++)
  {
    LED_off(LED_ALL);           /* turn off all three leds    */
    delay_msec((Uint32)ms_period/2);
    LED_on(LED_ALL);            /* turn on all user leds      */
    delay_msec((Uint32)ms_period/2);
  }
  LED_off(LED_ALL);             /* turn off all three leds    */
}

/*-------------------------------------------------------------------------*/
/* get_bdrev() - used to read board revision bits                          */
/*-------------------------------------------------------------------------*/
Uint32 get_bdrev(void) {

  return((BOARD_readReg(BOARD_REG_IOPORT)>>29)&0x7);
}

/*******************************************************************************
* FUNCTION : delay_msec
*
* ARGUMENTS :
*   Uint32 msec            <-- Period to delay in milliseconds
*
* DESCRIPTION :
*
*
* OUTPUTS :
*   VOID
*
*******************************************************************************/
void delay_msec(Uint32 msec){
  /* Assume 150 MHz CPU, timer peirod = 4/150 MHz */
  Uint32 timer_limit;
  Uint32 timer_start;

  timer_limit = ((Uint32)msec*9375)<<2;
  timer_start = TIMER_getCount(hTimer);
  TIMER_resume(hTimer);
  while ( (TIMER_getCount(hTimer) - timer_start) < timer_limit );
  TIMER_pause(hTimer);
}
 

/*******************************************************************************
* FUNCTION : play_codec
*
* ARGUMENTS :
*   INT number         <-- Number of samples
*   INT tone_playbk    <-- Audio in playback if 0, Tone if 1
*
* DESCRIPTION :
*   This function initializes the DSP's McBSP and the AIC's codec before
*   playing the codec input through its output or generating a tone.
*
* OUTPUTS :
*   VOID
*
*******************************************************************************/
void play_codec(int number, int tone_playbk)
{
  int i,j;

  AD535_reset(hAD535);
  
  AD535_writeReg(hAD535, AD535_REG_CTRL3, 0x06);  /* set up reg 3 */
  AD535_writeReg(hAD535, AD535_REG_CTRL4, 0x00);  /* set up reg 4 */
  AD535_writeReg(hAD535, AD535_REG_CTRL5, 0x02);  /* set up reg 5 */

  if(tone_playbk) {
    for (i=0;i<number;i++){
      for (j=0;j<8;j++)
        AD535_write(hAD535, (int)sin_table[j]);
    }
  }
  else {
    for (i=0;i<number;i++)
      AD535_write(hAD535, AD535_read(hAD535) );
  }
}

/* END OF FILE */