/*H***************************************************************************
*
* $Archive:: /boards/dsk5509a/examples/post/post.c                            $
* $Revision:: 2                                                               $
* $Date:: 11/11/05 12:01p                                                     $
* $Author:: Vss6admin                                                         $
*
* DESCRIPTION:
*
*   
* (C) Copyright 2005 by Spectrum Digital Incorporated
* All rights reserved
*
*H***************************************************************************/

/*
 *  ======== post.c ========
 *
 *  This is a test program that uses DSK5509A Board Support Library to
 *  perform a confidence test on a DSK5509A.  While it is running, it
 *  will display the current test index in binary on the LEDs.  If it
 *  fails a test, the test index will blink indefinitely to alert you to
 *  the failure.  If all tests pass, all of the LEDs will blink 3 times
 *  then stay on.
 *
 *  The following tests are performed:
 *
 *  Index    Description
 *    1      Codec
 *    2      SDRAM
 *    3      NI Frequency
 *
 *  Please see the DSK5509A BSL Examples for more detailed information.
 */

/*
 *  DSP/BIOS is configured using the DSP/BIOS configuration tool.  Settings
 *  for this example are stored in a configuration file called post.cdb.  At
 *  compile time, Code Composer will auto-generate DSP/BIOS related files
 *  based on these settings.  A header file called postcfg.h contains the
 *  results of the autogeneration and must be included for proper operation.
 *  The name of the file is taken from post.cdb and adding cfg.h.
 */
#include "postcfg.h"

/*
 *  The test uses the Chip Support Library for basic definitions as well as
 *  McBSP manipulation.  Programs that use the CSL must include the
 *  appropriate header files.
 */
#include <csl.h>
#include <csl_mcbsp.h>
#include <csl_dma.h>
#include <csl_timer.h>
#include <csl_gpio.h>

/*
 *  The Board Support Library is divided into several modules, each
 *  of which has its own include file.  The file dsk5509.h must be included
 *  in every program that uses the BSL.  This example also includes
 *  BSL header files for each module it uses.
 */
#include "dsk5509.h"
#include "dsk5509_led.h"
#include "dsk5509_aic23.h"
#include "dsk5509_dip.h"

/* Length of sine wave table */
#define SINE_TABLE_SIZE  48

/* Number of elements for DMA and McBSP loopback tests */
#define N                16

/* Pre-generated sine wave data, 16-bit signed samples */
int sinetable[SINE_TABLE_SIZE] = {
    0x0000, 0x10b4, 0x2120, 0x30fb, 0x3fff, 0x4dea, 0x5a81, 0x658b,
    0x6ed8, 0x763f, 0x7ba1, 0x7ee5, 0x7ffd, 0x7ee5, 0x7ba1, 0x76ef,
    0x6ed8, 0x658b, 0x5a81, 0x4dea, 0x3fff, 0x30fb, 0x2120, 0x10b4,
    0x0000, 0xef4c, 0xdee0, 0xcf06, 0xc002, 0xb216, 0xa57f, 0x9a75,
    0x9128, 0x89c1, 0x845f, 0x811b, 0x8002, 0x811b, 0x845f, 0x89c1,
    0x9128, 0x9a76, 0xa57f, 0xb216, 0xc002, 0xcf06, 0xdee0, 0xef4c
};

/* Codec configuration settings */
DSK5509_AIC23_Config config = { \
    0x0017, // 0 DSK5509_AIC23_LEFTINVOL  Left line input channel volume
    0x0017, // 1 DSK5509_AIC23_RIGHTINVOL Right line input channel volume
    0x00d8, // 2 DSK5509_AIC23_LEFTHPVOL  Left channel headphone volume
    0x00d8, // 3 DSK5509_AIC23_RIGHTHPVOL Right channel headphone volume
    0x0011, // 4 DSK5509_AIC23_ANAPATH    Analog audio path control
    0x0000, // 5 DSK5509_AIC23_DIGPATH    Digital audio path control
    0x0000, // 6 DSK5509_AIC23_POWERDOWN  Power down control
    0x0043, // 7 DSK5509_AIC23_DIGIF      Digital audio interface format
    0x0081, // 8 DSK5509_AIC23_SAMPLERATE Sample rate control
    0x0001  // 9 DSK5509_AIC23_DIGACT     Digital interface activation
};

/* Define test buffer */
Uint16 buffer[256];

/* Variables used by the TEST_sleep() funciton */
Uint16 eventId1;
volatile Uint16 sleepCount = 0;

TIMER_Handle hTimer1;
TIMER_Config timerCfg1 = {
    TIMER_TCR_RMK(  TIMER_TCR_IDLEEN_DISABLE,
                    TIMER_TCR_FUNC_OF( 1 ),
                    TIMER_TCR_TLB_NORESET,
                    TIMER_TCR_SOFT_BRKPTNOW,
                    TIMER_TCR_FREE_WITHSOFT,
                    TIMER_TCR_PWID_OF( 0 ),
                    TIMER_TCR_ARB_RESET,
                    TIMER_TCR_TSS_STOP,
                    TIMER_TCR_CP_CLOCK,
                    TIMER_TCR_POLAR_LOW,
                    TIMER_TCR_DATOUT_0 ),
    TIMER_PRD_RMK(  TIMER_PRD_PRD_OF( 0x4e1f ) ),
    TIMER_PRSC_RMK( TIMER_PRSC_PSC_OF( 0 ),
                    TIMER_PRSC_TDDR_0F( 9 ) )
};

/*
 *  Interrupt Service Routines
 */

void sleepIsr()
{
    sleepCount++;
}

/*
 *  Accessory functions
 */

void TEST_sleep(Int16 sleeptime)
{
    sleepCount = 0;

    /* Get Event Id associated with Timer 1, for use with */
    /* CSL interrupt enable functions.                    */
    eventId1 = TIMER_getEventId(hTimer1);

    /* Map the logical event to a physical interrupt */
    IRQ_map(eventId1);

    /* Clear any pending Timer interrupts */
    IRQ_clear(eventId1);

    /* Enable timer interrupt */
    IRQ_enable(eventId1);

    /* Make sure global interrupts are enabled */
    IRQ_globalEnable();

    /* Start timer 1 */
    TIMER_start(hTimer1);

    while(sleepCount < sleeptime);

    /* Disable timer interrupt */
    IRQ_disable(eventId1);
}

void LED_binary(Int16 ledmask)
{
    Int16 i, bit;

    /* Walk through the bits in num setting corresponding LEDs */
    bit = 1;
    for (i = 0; i < 4; i++)
    {
        if (ledmask & bit)
            DSK5509_LED_on(i);
        else
            DSK5509_LED_off(i);
        bit = bit << 1;
    }

}

void LED_blink(Int16 ledmask, Int16 count)
{
    while (count > 0)
    {
        LED_binary(ledmask);
        TEST_sleep(100);
        LED_binary(0);
        TEST_sleep(150);
        count--;
    }
}

void LED_error(Int16 ledmask)
{
    while(1)
        LED_blink(ledmask, 1);
}

/*
 *  Memory functions
 */

Int16 MEM_fill(Uint32 start, Uint32 len, Uint32 val)
{
    Uint32 i, end;

    /* Calculate end of range */
    end = start + len;

    /* Fill a range with a value */
    for (i = start; i < end; i+=2)
    {
        *((Uint32 *)i) = val;
    }

    /* Verify the data */
    for (i = start; i < end; i+=2)
    {
        if (*((Uint32 *)i) != val)
            return 1;
    }

    return 0;
}

Int16 MEM_addr(Uint32 start, Uint32 len)
{
    Uint32 i, end;

    /* Calculate end of range */
    end = start + len;

    /* Fill the range with its address */
    for (i = start; i < end; i+=2)
    {
        *((Uint32 *)i) = i;
    }

    /* Verify the data */
    for (i = start; i < end; i+=2)
        if (*((Uint32 *)i) != i)
            return 1;

    return 0;
}

Int16 MEM_addrInv(Uint32 start, Uint32 len)
{
    Uint32 i, end;

    /* Calculate end of range */
    end = start + len;

    /* Fill the range with its address */
    for (i = start; i < end; i+=2)
    {
        *((Uint32 *)i) = ~i;
    }

    /* Verify the data */
    for (i = start; i < end; i+=2)
        if (*((Uint32 *)i) != (~i))
            return 1;

    return 0;
}

Int16 MEM_walking(Uint32 add)
{
    Int16 i;
    Uint32 mask, *pdata;

    pdata = (Uint32 *)add;

    /* Walking ones and zeros */
    mask = 1;
    for (i = 0; i < 32; i++)
    {
        /* Test one in bit position i */
        *pdata = mask;
        if (*pdata != mask)
            return 1;

        /* Test zero in bit position i */
        *pdata = ~mask;
        if (*pdata != (~mask))
            return 1;

        mask = mask << 1;
    }

    return 0;
}

Int16 MEM_test(Uint32 start, Uint32 len, Int16 patterntype)
{
    Int16 status = 0;

    if (!patterntype)
    {
        /* Run the fill tests */
        status |= MEM_fill(start, len, 0x55555555);
        status |= MEM_fill(start, len, 0xAAAAAAAA);
    } else
    {
        /* Run the address tests */
        status |= MEM_addr(start, len);
        status |= MEM_addrInv(start, len);
    }

    return status;
}


/*
 *  POST tests
 */

Int16 TEST_sdram()
{
    Int16 status = 0;

    /* Check external memory (byte 0x40000 to byte 0x400000) */
    status |= MEM_test(0x20000, 0x1E0000, 0);
    status |= MEM_test(0x20000, 0x1E0000, 1);
    status |= MEM_walking(0x20000);

    return status;
}

Int16 TEST_codec()
{
    DSK5509_AIC23_CodecHandle hCodec;
    Int16 i, j;

    /* Start the codec */
    hCodec = DSK5509_AIC23_openCodec(0, &config);

    /* Generate a 1KHz sine wave for 1 second */
    for (i = 0; i < 1000; i++)
    {
        for (j = 0; j < SINE_TABLE_SIZE; j++)
        {
            while (!DSK5509_AIC23_write16(hCodec, sinetable[j]));
            while (!DSK5509_AIC23_write16(hCodec, sinetable[j]));
        }
    }

    /* Close codec */
    DSK5509_AIC23_closeCodec(hCodec);

    return 0;
}

Int16 TEST_timer()
{
    /* Wait for 100 timer interrupts */
    TEST_sleep(100);

    return 0;
}

#define PLL_RESV             0x8000
#define PLL_IAI              0x4000
#define PLL_IOB              0x2000
#define PLL_TEST             0x1000
#define PLL_MULT             0x0F80
#define PLL_DIV              0x0060
#define PLL_ENABLE           0x0010
#define PLL_BP_DIV           0x000C
#define PLL_BREAKLN          0x0002
#define PLL_LOCK             0x0001
#define PLL_MULT_MASK        0x0F80
#define PLL_RESET            0x2002

#define C55XX_CLKMD_ADDR     0x1C00

typedef ioport volatile unsigned short * PIOPUS;  /* Generic pointer to io  */

int 
C55xx_PllBypass( void )
{

    volatile unsigned short PllLock;    
    PIOPUS pClkMode = (PIOPUS)C55XX_CLKMD_ADDR;
       
    *pClkMode = PLL_RESET;
   
    PllLock = 10;
    while(PllLock--);
                     
    do
    {
        PllLock = *pClkMode;
    }while( ( PllLock & PLL_LOCK ) == PLL_LOCK );

    return( 0 );
        
}
    
int
C55XX_PllSetFrequency( int InputFrequecy, int OutputFrequency )
{  
    register unsigned short ClkModeSet;
    volatile unsigned short PllLock;    
    PIOPUS pClkMode = (PIOPUS)C55XX_CLKMD_ADDR;
    
    C55xx_PllBypass();
            
    ClkModeSet  =  (unsigned short)(OutputFrequency/InputFrequecy);
    // Only set the pll on if the frequency is greater then the 
    // input i.e. bypass frequency
    //
    if( ClkModeSet > 1 )
    {

		ClkModeSet = ClkModeSet<<7;
        ClkModeSet |= ( PLL_IOB | PLL_ENABLE );

        *pClkMode = ClkModeSet;

	    do
	    {
	        PllLock = *pClkMode;
	    }while( ( PllLock & PLL_LOCK ) != PLL_LOCK );
	}
    return( 0 );
}    

Int16 TEST_ni()
{
	volatile Uint16 value;
	Uint16  Table[16];
	Uint16  Compare;
	Uint16  Wait;
	Int16   Error = 0;
	Int16   i;
	Int16   TabSize = sizeof(Table)/sizeof(Uint16);
	Int16   Timeout;

	for(i=0; i<TabSize; i++ )
	{
		Table[i] = 0;
	}
	for(i=0; i<TabSize; i++ )
	{
		// Set the pll freq and wait for a while
		Wait = 1920/(12*(TabSize-i));
		C55XX_PllSetFrequency(12, (i+1)*12 );
		TEST_sleep(Wait);

		// Include a timeout to prevent hanging forever.  In theory
		// the only time this should hang is if one of the clocks
		// is turned off.
		//
		Timeout = 10000;
		do{
			value = DSK5509_rget(DSK5509_NISTAT);
		}while(((value & NISTAT_VALID) == 0) && (Timeout-- > 0) );

		// Store the code
		Table[i] = value & NISTAT_FREQ_MASK;		
	}

	// Now verify the codes are correct.
	for(i=0; i<TabSize; i++ )
	{	// 208 if sample period, times pll div 4
		Compare = 208 * (i+1) * (12/4);
		// Divide the fx clock
		Compare = Compare / 24; 
		// Toss out the 4 lsbs
		Compare = Compare >> 4;
		if( Table[i] != Compare ) {
			Error++;
		}
	}

	DSK5509_rset(DSK5509_MISC,0);
	return(Error);

}

Int16 TEST_null()
{
    return 0;
}

void TEST_execute(Int16 (*funchandle)(), char *message, Int16 ledmask, Int16 insertdelay)
{
    Int16 status;

    /* Display test ID */
    LED_binary(ledmask);

    /* Call test function */
    status = funchandle();

    /* Pause so LEDs can be read */
    if (insertdelay)
        TEST_sleep(100);

    /* Check for test fail */
    if (status)
    {
        LED_error(ledmask);
    }
}

main()
{
    /* Call BSL init */
    DSK5509_init();
    hTimer1 = TIMER_open(TIMER_DEV1, TIMER_OPEN_RESET);
    TIMER_config(hTimer1, &timerCfg1);
    IRQ_globalEnable();

    /* Initialize modules */
    DSK5509_LED_init();

    /* Run the tests sequentially */
    TEST_execute(TEST_codec, "  Testing CODEC", 1, 0);   /* Codec test */
    TEST_execute(TEST_sdram, "  Testing SDRAM", 2, 0);   /* SDRAM */
    TEST_execute(TEST_ni,    "  Testing NI",    3, 0);   /* NI Codes */

    /* All tests complete, board passes */
    LED_blink(0xf, 3);

    /* Leave all LEDs on */
    LED_binary(0xf);

    /* Disable interrupts */
    IRQ_globalDisable();

}
