#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>
#include<stdbool.h>

typedef unsigned int Uint32;
typedef char Uint8;
typedef signed int Uint16;



#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
  __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)


#define BYTE_SIZE 				8
#define BYTE_MASK 				0xFF
#define NO_ERRORS 				0

#define KICK0_KEY				0x83E70B13
#define KICK1_KEY				0x95A4F1E0
#define KICK_LOCK				0x00000000
#define ARM_PRIV_MODE_KEY			327680

#define CSL_SYSCFG_KICK0R_KICK0_MASK     	(0xFFFFFFFFu)
#define CSL_SYSCFG_KICK0R_KICK0_SHIFT   	 (0x00000000u)
#define CSL_SYSCFG_KICK0R_KICK0_RESETVAL 	(0x00000000u)
#define CSL_SYSCFG_KICK0R_RESETVAL       	(0x00000000u)

#define CSL_SYSCFG_KICK1R_KICK1_MASK    	 (0xFFFFFFFFu)
#define CSL_SYSCFG_KICK1R_KICK1_SHIFT   	 (0x00000000u)
#define CSL_SYSCFG_KICK1R_KICK1_RESETVAL	 (0x00000000u)
#define CSL_SYSCFG_KICK1R_RESETVAL      	 (0x00000000u)

#define SHARED_CPU_VARS_MEM 0x8001FC00
#define CSL_SYSCFG_0_REGS   0x01C14000
#define CSL_AINTC_0_REGS    (0xFFFEE000u)

#define NUM_AINTC_EVENTID 			101
#define AINTC_SYSINT_0_31_ALL 			0xFFFFFFFF
#define AINTC_SYSINT_32_63_ALL 			0xFFFFFFFF
#define AINTC_SYSINT_64_95_ALL 			0xFFFFFFFF
#define AINTC_SYSINT_96_101_ALL 		0x0000003F

#define AINTC_EVENTID_SYSCFG_CHIPINT1		29
#define AINTC_EVENTID_SYSCFG_CHIPINT2		30
#define AINTC_EVENTID_SYSCFG_CHIPINT3		31

#define CSL_AINTC_CMR7_CHNL_NPLUS1_MASK  (0x0000FF00u)
#define CSL_AINTC_CMR7_CHNL_NPLUS1_SHIFT (0x00000008u)
#define CSL_AINTC_CMR7_CHNL_NPLUS1_RESETVAL (0x00000000u)

#define CSL_AINTC_EISR_INDEX_MASK        (0x000003FFu)
#define CSL_AINTC_EISR_INDEX_SHIFT       (0x00000000u)
#define CSL_AINTC_EISR_INDEX_RESETVAL    (0x00000000u)
#define CSL_AINTC_HIEISR_INDEX_MASK      (0x000003FFu)
#define CSL_AINTC_HIEISR_INDEX_SHIFT     (0x00000000u)
#define CSL_AINTC_HIEISR_INDEX_RESETVAL  (0x00000000u)
#define CSL_AINTC_GER_ENABLE_MASK        (0x00000001u)
#define CSL_AINTC_GER_ENABLE_SHIFT       (0x00000000u)
#define CSL_AINTC_GER_ENABLE_RESETVAL    (0x00000000u)
#define CSL_AINTC_SICR_INDEX_MASK        (0x000003FFu)
#define CSL_AINTC_SICR_INDEX_SHIFT       (0x00000000u)
#define CSL_AINTC_SICR_INDEX_RESETVAL    (0x00000000u)

#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG0_MASK 		(0x00000001u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG0_SHIFT 		(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG0_RESETVAL	(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG0_NOTHING 	(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG0_CLEAR 		(0x00000001u)

#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG3_MASK 		(0x00000008u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG3_SHIFT 		(0x00000003u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG3_RESETVAL 	(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG3_NOTHING 	(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG3_CLEAR 		(0x00000001u)

#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG2_MASK 		(0x00000004u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG2_SHIFT 		(0x00000002u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG2_RESETVAL 	(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG2_NOTHING 	(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG2_CLEAR 		(0x00000001u)

#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG1_MASK 		(0x00000002u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG1_SHIFT 		(0x00000001u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG1_RESETVAL 	(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG1_NOTHING 	(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CLR_CHIPSIG1_CLEAR 		(0x00000001u)
#define CSL_SYSCFG_CHIPSIG_CLR_RESETVAL  		(0x00000000u)

#define CSL_SYSCFG_CHIPSIG_CHIPSIG3_MASK 		(0x00000008u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG3_SHIFT 		(0x00000003u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG3_RESETVAL 		(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG3_NOTHING 		(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG3_ASSERT 		(0x00000001u)

#define CSL_SYSCFG_CHIPSIG_CHIPSIG2_MASK 		(0x00000004u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG2_SHIFT 		(0x00000002u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG2_RESETVAL 		(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG2_NOTHING 		(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG2_ASSERT 		(0x00000001u)

#define CSL_SYSCFG_CHIPSIG_CHIPSIG1_MASK 		(0x00000002u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG1_SHIFT 		(0x00000001u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG1_RESETVAL 		(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG1_NOTHING 		(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG1_ASSERT 		(0x00000001u)

#define CSL_SYSCFG_CHIPSIG_CHIPSIG0_MASK 		(0x00000001u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG0_SHIFT 		(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG0_RESETVAL 		(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG0_NOTHING 		(0x00000000u)
#define CSL_SYSCFG_CHIPSIG_CHIPSIG0_ASSERT 		(0x00000001u)

#define Uint32 unsigned int
#define Bool	bool
#define Uint8	unsigned char
#define TRUE    ((Bool) 1)
#define FALSE   0x000000 // ((Bool) 0)
#define TRUE_Fun    0x010000 // ((Bool) 1)


typedef struct{
        volatile Bool  HEARTBEAT;
        volatile Bool RES1;
        volatile Bool DSP_FUNC1;
        volatile Bool RES2;
        volatile Bool DSP_FUNC2;
        volatile Bool RES3;
        volatile Bool DSP_FUNC3;
        volatile Bool RES4;
        volatile Bool DSP_FUNC4;
} sharedCpuVars;

typedef struct  {
    volatile Uint32 REVID;
    volatile Uint8 RSVD0[4];
    volatile Uint32 DIEIDR0;
    volatile Uint32 DIEIDR1;
    volatile Uint32 DIEIDR2;
    volatile Uint32 DIEIDR3;
    volatile Uint32 DEVIDR0;
    volatile Uint8 RSVD1[4];
    volatile Uint32 BOOTCFG;
    volatile Uint32 CHIPREVIDR;
    volatile Uint8 RSVD2[16];
    volatile Uint32 KICK0R;
    volatile Uint32 KICK1R;
    volatile Uint32 HOST0CFG;
    volatile Uint32 HOST1CFG;
    volatile Uint8 RSVD3[152];
    volatile Uint32 IRAWSTAT;
    volatile Uint32 IENSTAT;
    volatile Uint32 IENSET;
    volatile Uint32 IENCLR;
    volatile Uint32 EOI;
    volatile Uint32 FLTADDRR;
    volatile Uint32 FLTSTAT;
    volatile Uint8 RSVD4[20];
    volatile Uint32 MSTPRI0;
    volatile Uint32 MSTPRI1;
    volatile Uint32 MSTPRI2;
    volatile Uint8 RSVD5[4];
    volatile Uint32 PINMUX0;
    volatile Uint32 PINMUX1;
    volatile Uint32 PINMUX2;
    volatile Uint32 PINMUX3;
    volatile Uint32 PINMUX4;
    volatile Uint32 PINMUX5;
    volatile Uint32 PINMUX6;
    volatile Uint32 PINMUX7;
    volatile Uint32 PINMUX8;
    volatile Uint32 PINMUX9;
    volatile Uint32 PINMUX10;
    volatile Uint32 PINMUX11;
    volatile Uint32 PINMUX12;
    volatile Uint32 PINMUX13;
    volatile Uint32 PINMUX14;
    volatile Uint32 PINMUX15;
    volatile Uint32 PINMUX16;
    volatile Uint32 PINMUX17;
    volatile Uint32 PINMUX18;
    volatile Uint32 PINMUX19;
    volatile Uint32 SUSPSRC;
    volatile Uint32 CHIPSIG;
    volatile Uint32 CHIPSIG_CLR;
    volatile Uint32 CFGCHIP0;
    volatile Uint32 CFGCHIP1;
    volatile Uint32 CFGCHIP2;
    volatile Uint32 CFGCHIP3;
    volatile Uint32 CFGCHIP4;
} CSL_SyscfgRegs;

typedef struct  {
    volatile Uint32 REVID;
    volatile Uint32 CR;
    volatile Uint8 RSVD0[8];
    volatile Uint32 GER;
    volatile Uint8 RSVD1[8];
    volatile Uint32 GNLR;
    volatile Uint32 SISR;
    volatile Uint32 SICR;
    volatile Uint32 EISR;
    volatile Uint32 EICR;
    volatile Uint8 RSVD2[4];
    volatile Uint32 HIEISR;
    volatile Uint32 HIDISR;
    volatile Uint8 RSVD3[20];
    volatile Uint32 VBR;
    volatile Uint32 VSR;
    volatile Uint32 VNR;
    volatile Uint8 RSVD4[36];
    volatile Uint32 GPIR;
    volatile Uint32 GPVR;
    volatile Uint8 RSVD5[376];
    volatile Uint32 SRSR1;
    volatile Uint32 SRSR2;
    volatile Uint32 SRSR3;
    volatile Uint8 RSVD6[116];
    volatile Uint32 SECR1;
    volatile Uint32 SECR2;
    volatile Uint32 SECR3;
    volatile Uint8 RSVD7[116];
    volatile Uint32 ESR1;
    volatile Uint32 ESR2;
    volatile Uint32 ESR3;
    volatile Uint8 RSVD8[116];
    volatile Uint32 ECR1;
    volatile Uint32 ECR2;
    volatile Uint32 ECR3;
    volatile Uint8 RSVD9[116];
    volatile Uint32 CMR0;
    volatile Uint32 CMR1;
    volatile Uint32 CMR2;
    volatile Uint32 CMR3;
    volatile Uint32 CMR4;
    volatile Uint32 CMR5;
    volatile Uint32 CMR6;
    volatile Uint32 CMR7;
    volatile Uint32 CMR8;
    volatile Uint32 CMR9;
    volatile Uint32 CMR10;
    volatile Uint32 CMR11;
    volatile Uint32 CMR12;
    volatile Uint32 CMR13;
    volatile Uint32 CMR14;
    volatile Uint32 CMR15;
    volatile Uint32 CMR16;
    volatile Uint32 CMR17;
    volatile Uint32 CMR18;
    volatile Uint32 CMR19;
    volatile Uint32 CMR20;
    volatile Uint32 CMR21;
    volatile Uint32 CMR22;
    volatile Uint32 CMR23;
    volatile Uint32 CMR24;
    volatile Uint32 CMR25;
    volatile Uint32 CMR26;
    volatile Uint32 CMR27;
    volatile Uint32 CMR28;
    volatile Uint32 CMR29;
    volatile Uint32 CMR30;
    volatile Uint32 CMR31;
    volatile Uint8 RSVD10[1152];
    volatile Uint32 HIPIR1;
    volatile Uint32 HIPIR2;
    volatile Uint8 RSVD11[1144];
    volatile Uint32 SITR1;
    volatile Uint32 SITR2;
    volatile Uint32 SITR3;
    volatile Uint8 RSVD12[372];
    volatile Uint32 DSR1;
    volatile Uint32 DSR2;
    volatile Uint8 RSVD13[504];
    volatile Uint32 HINLR1;
    volatile Uint32 HINLR2;
    volatile Uint8 RSVD14[1016];
    volatile Uint32 HIER;
    volatile Uint8 RSVD15[252];
    volatile Uint32 HIPVR1;
    volatile Uint32 HIPVR2;
} CSL_AintcRegs;

CSL_SyscfgRegs* syscfg;
CSL_AintcRegs* aintcreg;
sharedCpuVars* sharvar;
int fd1,fd2,fd3;
void *map_base1, *map_base2, *map_base3;

volatile Bool dspIsBusy;
volatile Bool remainIDLE;

typedef volatile void (*ISRpointer);
ISRpointer sysISRtbl[NUM_AINTC_EVENTID] = {NULL};

unsigned int spsr asm("spsr");
unsigned int cpsr __asm("cpsr");

void sudomode(void)
{
    cpsr |= 0x13;
}


void _enable_IRQ(void)
{
    cpsr |= 0x13;
}

void _disable_IRQ(void)
{
    cpsr |= 0x73;
}

void SYSCFG_chip1_isr (void)
{

    while(syscfg->CHIPSIG != 0x02);
	// DSP Function Finished
	dspIsBusy = FALSE;
	
	// Clear SYSCFG CHIP1 Interrupt Flag
	syscfg->CHIPSIG_CLR = 0x0f;
	
	// Acknowledge SYSCFG CHIP1 Interrupt
    aintcreg->SICR = 29;
}/* SYSCFG_chip1_isr */

static void commandDSP (void)
{
	// Wait for DSP to be free
	while(dspIsBusy);
	// Update variable to reflect DSP status (This variable is only updated
	// by the ARM...done before sending DSP command to avoid errors)
	dspIsBusy = TRUE;
	
	// Notify DSP to perform function
    syscfg->CHIPSIG = 0x04;
	
    SYSCFG_chip1_isr();
	// Wait for DSP to be free
	while(dspIsBusy);
}/* commandDSP */

/*-----------------------------------------------------------------------------
 *
 * 							Interrupt Functions
 * 
 *---------------------------------------------------------------------------*/


int init_OMAPL138(void){
    
    // Open Permissions to SYSCFG Registers
    syscfg->KICK0R = KICK0_KEY;
    syscfg->KICK1R = KICK1_KEY;
   
    // Clear all SYSCFG interrupts
    syscfg->CHIPSIG_CLR = 0x1f;

    // Clear shared memory
    sharvar->HEARTBEAT=FALSE;
    sharvar->RES1 = FALSE;
    sharvar->DSP_FUNC1=FALSE;
    sharvar->RES2 = FALSE;
    sharvar->DSP_FUNC2=FALSE;
    sharvar->RES3 = FALSE;
    sharvar->DSP_FUNC3=FALSE;
    sharvar->RES4 = FALSE;
    sharvar->DSP_FUNC4=FALSE;

}

int setup_ARM_INTC(){

    // Reset AINTC
    aintcreg->ECR1 = 0XF0000000;
    aintcreg->SECR1 = 0xF0000000;

    // Assign SYSCFG Chip1 ISR to SYSCFG Chip1 System Interrupt
    sysISRtbl[29] = &SYSCFG_chip1_isr;

	// Assign the ISR Table Address to VBR
	aintcreg->VBR = (unsigned int)sysISRtbl;

    // Declare ISR Size (Function Pointer = 4 bytes)
	aintcreg->VSR = 0;

    // Map CHIPSIG1 Interrupts to Channel 2
	aintcreg->CMR7= 0x200;

    // Enable CHIPSIG1 Interrupts
    aintcreg->EISR = 29;

    // Enable IRQ Interrupts
	aintcreg->HIEISR = 1;
	
	// Enable Interrupts
	aintcreg->GER   =   1;

}

static void ARM2DSP_integration_ARMexample (void)
{
    //#if 1
	printf("Example:\tARM2DSP_integration_armL138\n"
		   "Scope:\t\tThe ARM CPU commands the DSP to perform miscellaneous\n"
		   "\t\tdummy functions to illustrate ARM to DSP integration.\n"
		   "NOTE:\t\tPlease load ARM2DSP_integration_dspL138.out to the\n"
		   "\t\tDSP CPU if not already completed.\n"
		   "Begin...\n");

    //syscfg->CHIPSIG =   0x08;
#if 1
	// Test for DSP awake
	//while(sharvar->HEARTBEAT == FALSE)
	//{
		int counter = 20000000;
		syscfg->CHIPSIG =   0x08;
		while((sharvar->HEARTBEAT == FALSE) && (counter > 0))
			counter--;
		if(counter == 0)
			printf("\tPlease load ARM2DSP_integration_dspL138.out "
			"to the DSP CPU.\n");
	//}
    //#endif
#endif
	// DSP waiting for ARM command
	dspIsBusy = FALSE;
   
    // Intrinsic Function to Enable Interrupts
	//_enable_IRQ();
	printf("\tCommanding DSP to perform Function 1...\n");
	sharvar->DSP_FUNC1 = TRUE;
    
	commandDSP();
	
	printf("\tCommanding DSP to perform Functions 2 & 4...\n");
	sharvar->DSP_FUNC2 = TRUE;
    sharvar->DSP_FUNC3 = TRUE;

    commandDSP();
	


	printf("\tCommanding DSP to exit...\n");
	syscfg->CHIPSIG =   0x08;
    
	// Intrinsic Function to Disable Interrupts
	//_disable_IRQ();
	
	printf("End of example!\n\n");
}/* ARM2DSP_integration_ARMexample */




int main(void)
{
    memorymap1();
    memorymap2();
    memorymap3();
    
	// Initialize OMAPL138 EVM (Unlock SYSCFG Registers)
	init_OMAPL138();
	
	// Map system interrupts to the ARM interrupt controller
	setup_ARM_INTC();
	
	// Run Example
	ARM2DSP_integration_ARMexample();
   
    memoryunmap1(fd1);
    memoryunmap2(fd2);
    memoryunmap3(fd3);
}

int memorymap1(){
  
    void *virt_addr;
    off_t target;
   
    if((fd1 = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
    printf("/dev/mem opened.\n"); 
    fflush(stdout);

    target = 0x01C14000;
    /* Map one page */
    map_base1 = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd1, target & ~MAP_MASK);
    if(map_base1 == (void *) -1) FATAL;
    fflush(stdout);
    virt_addr = map_base1 + (target & MAP_MASK);

    syscfg = (CSL_SyscfgRegs*)virt_addr;
    

    printf("REVID %x \n",syscfg->REVID);
    
}

int memorymap2(){
  
    void *virt_addr;
    off_t target;
    int fd1;
   
    if((fd2 = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
    printf("/dev/mem opened.\n"); 
    fflush(stdout);

    target = 0x8001FC00;

    map_base2 = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, target & ~MAP_MASK);
    if(map_base2 == (void *) -1) FATAL;
    fflush(stdout);

    virt_addr = map_base2 + (target & MAP_MASK);
    sharvar = (sharedCpuVars*)virt_addr;

#if 0
    sharvar->HEARTBEAT = 0x01;
    sharvar->RES1       = 0;
    sharvar->DSP_FUNC1 = 0x01;
    sharvar->RES2       = 0;
    sharvar->DSP_FUNC4 = 0x01;
    sharvar->RES3       = 0;
    sharvar->DSP_FUNC3 = 0x01;
    sharvar->RES4       = 0;
    sharvar->DSP_FUNC2 = 0x01;
#endif
}

int memorymap3(){
  
    void *virt_addr;
    off_t target;
    int fd2;
   
    if((fd2 = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
    printf("/dev/mem opened.\n"); 
    fflush(stdout);

    target = 0xFFFEE000;
    map_base3 = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, target & ~MAP_MASK);
    if(map_base3 == (void *) -1) FATAL;
    fflush(stdout);

    virt_addr = map_base3 + (target & MAP_MASK);

    aintcreg = (CSL_AintcRegs*)virt_addr;
    printf("REVID = %x \n",aintcreg->REVID);
}

int memoryunmap1( int fd1){
   if(munmap(map_base1, MAP_SIZE) == -1) FATAL;
    close(fd1);
}
int memoryunmap2( int fd1){
    if(munmap(map_base2, MAP_SIZE) == -1) FATAL;
    close(fd2);
}
int memoryunmap3( int fd4){
    if(munmap(map_base3, MAP_SIZE) == -1) FATAL;
    close(fd3);
}