/*
 * File:        benchinit.c
 *
 * Notes:
 *
 */

#include "sysinit.h"
#include "mmu.h"
#include "benchinit.h"
#include "macros.h"
#include "ca5_pmu.h"



/* MMU setiing*/

#define START_ADDR_CODE_DDR             (0x80000000)
#define START_ADDR_CONST_DDR            (0x80300000)
#define START_ADDR_DATA_DDR             (0x80400000)
#define START_ADDR_DEV             	(0x40000000)
#define START_ADDR_OCMC            	(0x3F000000)


#define NUM_SECTIONS_CODE_DDR           (2)
#define NUM_SECTIONS_CONST_DDR          (1)
#define NUM_SECTIONS_DATA_DDR           (1)
#define NUM_SECTIONS_DEV           	(1)
#define NUM_SECTIONS_OCMC          	(1)


#define	NUMBER_OF_TESTS			240
#define	NUMBER_OF_PM_RESULTS_PER_TEST	4



static volatile unsigned int pageTable[4*1024] __attribute__((aligned(16*1024)));
uint32 Slice_Period=0 ;
uint32 next_state =0 ;


unsigned long PerfMonReg[NUMBER_OF_TESTS][NUMBER_OF_PM_RESULTS_PER_TEST] ;




void benchinit(void)
{
	unsigned long PerfMonEventSelect[2] = {	DATA_READ,
					DATA_WRITES
					} ;
					
	MMUConfigAndEnable();
	
	perf_init(PerfMonEventSelect);
	
	CP15IcacheEnable();
	CP15DcacheFlush();
	CP15DcacheEnable();	
}


void MMUConfigAndEnable(void)
{
    /*
    ** Define DDR memory region of AM335x. DDR can be configured as Normal
    ** memory with R/W access in user/privileged modes. The cache attributes
    ** specified here are,
    ** Inner - Write through, No Write Allocate
    ** Outer - Write Back, Write Allocate
    */


 
    REGION region_Code_Ddr = {
                        MMU_PGTYPE_SECTION, START_ADDR_CODE_DDR, NUM_SECTIONS_CODE_DDR,
                       MMU_MEMTYPE_NORMAL_NON_SHAREABLE(MMU_CACHE_WB_WA,
                                                         MMU_NON_CACHEABLE),
			/*MMU_MEMTYPE_DEVICE_SHAREABLE,*/
                        MMU_REGION_NON_SECURE, MMU_AP_PRV_RW_USR_RW,
                        (unsigned int*)pageTable
                       };

     REGION region_Const_Ddr = {
                        MMU_PGTYPE_SECTION, START_ADDR_CONST_DDR, NUM_SECTIONS_CONST_DDR,
                       MMU_MEMTYPE_NORMAL_NON_SHAREABLE(MMU_CACHE_WB_WA,
                                                         MMU_NON_CACHEABLE),
			/*MMU_MEMTYPE_DEVICE_SHAREABLE,*/
                        MMU_REGION_NON_SECURE, MMU_AP_PRV_RW_USR_RW,
                        (unsigned int*)pageTable
                       }	;       

    REGION region_Data_Ddr = {
                        MMU_PGTYPE_SECTION, START_ADDR_DATA_DDR, NUM_SECTIONS_DATA_DDR,
                       	MMU_MEMTYPE_NORMAL_NON_SHAREABLE(MMU_NON_CACHEABLE,
                                                         MMU_NON_CACHEABLE),
			//MMU_MEMTYPE_STRONG_ORD_SHAREABLE,
			//MMU_MEMTYPE_DEVICE_NON_SHAREABLE,
			
                        MMU_REGION_NON_SECURE, MMU_AP_PRV_RW_USR_RW,
                        (unsigned int*)pageTable
                       };
   

    /*
    ** Define Device Memory Region. The region between OCMC and DDR is
    ** configed as device memory, with R/W access in user/privileged modes.
    ** Also, the region is marked 'Execute Never'.
    */
    REGION regionDev = {
                        MMU_PGTYPE_SECTION, START_ADDR_DEV, NUM_SECTIONS_DEV,
                        MMU_MEMTYPE_DEVICE_NON_SHAREABLE,
                        MMU_REGION_SECURE,
                        MMU_AP_PRV_RW_USR_RW ,
			/* | MMU_SECTION_EXEC_NEVER*/
                        (unsigned int*)pageTable
                       };
		       
/*
    ** Define OCMC RAM region of AM335x. Same Attributes of DDR region given.
    */
    REGION regionOcmc = {
                         MMU_PGTYPE_SECTION, START_ADDR_OCMC, NUM_SECTIONS_OCMC,
			 MMU_MEMTYPE_NORMAL_NON_SHAREABLE(MMU_CACHE_WB_WA,
                                                         MMU_NON_CACHEABLE),
			 //MMU_MEMTYPE_STRONG_ORD_SHAREABLE,
			 //MMU_MEMTYPE_DEVICE_NON_SHAREABLE,
                         MMU_REGION_NON_SECURE, MMU_AP_PRV_RW_USR_RW,
                         (unsigned int*)pageTable
                        };


    /* Initialize the page table and MMU */
    MMUInit((unsigned int*)pageTable);

    /* Map the defined regions */
    MMUMemRegionMap(&region_Code_Ddr);
    MMUMemRegionMap(&region_Const_Ddr);    
    MMUMemRegionMap(&region_Data_Ddr);
    MMUMemRegionMap(&regionDev);
    MMUMemRegionMap(&regionOcmc);

    /* Now Safe to enable MMU */
    MMUEnable((unsigned int*)pageTable);
}


void perf_init(unsigned long PerfMonEventSelect[])
{
	/* Initialize Performance Monitor, allow control from user mode */
   	 _pmuInit_();
   	/* _pmuUserEnable_();*/
    	_pmuStartCounters_(pmuCOUNTER0 | pmuCOUNTER1 | pmuCYCLE_COUNTER);
      	/* Select event counters */
  
  	_pmuSetCountEvent_(0, PerfMonEventSelect[0]); 
  	_pmuSetCountEvent_(1, PerfMonEventSelect[1]);  


}


void perf_set(long evt0,long evt1  )
{
	if (evt0 )
	_pmuSetCountEvent_(0, evt0); 
	if (evt1)
  	_pmuSetCountEvent_(1, evt1);  
	
	
	
}

void perf_start(void)
{
_pmuEnableCountersGlobal_();

}

void perf_stop(long TestNumberX )
{
	
	_pmuDisableCountersGlobal_();
#if 1
	PerfMonReg[TestNumberX][0]= TestNumberX; 
	PerfMonReg[TestNumberX][1]= _pmuGetCycleCount_(); 	
	PerfMonReg[TestNumberX][2]= _pmuGetEventCount_(0);	
	PerfMonReg[TestNumberX][3]= _pmuGetEventCount_(1);	
#endif
}
