#include "ucps2-intrin.h"
#include "inter_vector.h"
#include "csu.h"
#include "pet_ctrl.h"
#include "ucp_sfr_c.h"
#include "ucp_js_ctrl.h"
#include "ucp_param.h"
#include "gs_que.h"
#include "error.h"

#include "alg.h"

#define DEBUG_OFF 0
#define bit_32  32
#define bit_64  64

#define APEID_ADDR   0x931FFF0
#define NULL ((void*)0)
#define INTR_NR	32
#define DBG_ON	1
#define MAX_IRQ_NUM  512
#define do_write(a,v)	__ucps2_store_ext_mem((void *)a, (uint32_t)v, f_W)
#define do_read(ptr)	__ucps2_load_ext_mem_v((char*)ptr, f_W)
#define IRQ_TRACPOINT_SIZE  0x92c




typedef struct{
    int reg_vec_count;
    int reg_vec_buf[INTR_NR];
    int irq_count[INTR_NR];
    irq_handler pfun[INTR_NR];

}vec_desc;


vec_desc inter_vec_val;
int val_cnt;
int irq_num_tatal_cnt;
uint32_t g_apeid;
uint32_t apcid_set[12] = {0,0,1,1,2,2,3,3,4,4,5,5};
uint32_t mask_array[16] = {0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60};
uint32_t  apcid_ad_val[] = {0,64,128,192};
uint32_t debug_enable = 0;
uint32_t debug_addr = 0;

uint32_t reg_cnt = 0;

uint32_t irq_check_cnt = 0;
uint32_t irq_clear_cnt = 0;
uint32_t cpuid_limit[12] = {1,0,1,0,1,0,1,0,1,0,1,0};
//irq_num_info info;
uint32_t g_mask;

irq_debug_t *debug_info;


uint32_t irq_cnt = 0;
uint32_t fun_cnt_s_c = 0;
uint32_t fun_cnt_e_c = 0;
uint32_t is_irq_context = 0;

uint32_t cpuid_times = 0;
int val_cnt;
uint32_t global_int_cnt[512] = {0};


void __ucps2_interrupt5();


/**************************************

******/

static int get_apcid()
{
    return apcid_set[g_apeid];
}

vec_desc *get_vec_desc()
{
    return &inter_vec_val;
}


#if DEBUG_OFF
#define irq_debug(add,b) (0)
#else
static void irq_debug(void * addr, uint32_t v)
{
    if(debug_enable == 1)
    {
        do_write(addr, v);
        __ucps2_synch(0);
    }
}
#endif

static uint32_t get_int_status_reg(uint32_t vector,int apcid)
{
    int mask_val;
    int bit_val;
    int load_val;
    mask_val = vector>>5;
    bit_val = (vector)&(bit_32 -1);
    if((apcid >= 0)&&(apcid < 4))
    {
        load_val =  do_read((SYSCFG_BASE_ADDR + 1248 + mask_array[mask_val] + apcid_ad_val[apcid]));
        return load_val;
    }
    else if(apcid == 4)
    {
        load_val =	do_read((PET_CTRL_BASE + 100*4 + mask_val*4 ));
        return load_val;
    }
    else if(apcid == 5)
    {
        load_val =	do_read((JECS_CTRL_BASE + 40*4 + mask_val*4 ));
        return load_val;
    }
    return 0;
}

static int irq_csu_clear_is_ok(int irq_num)
{
    if (0 ==(APC_CSU_ALLPENDEVENT0 & (1<<(irq_num & 31))))
    {
        return 1;
    }

    return 0;
}


void isr_entry()
{
    is_irq_context = 1;
    ++irq_cnt;
    vec_desc *vec_val = &inter_vec_val;
    unsigned int val;
    int k;
    int irq_num_bit;
    uint32_t sys_status;
    uint32_t bit_val = 0;
    g_mask = APC_CSU_INTMASKL;
    APC_CSU_INTMASKL = 0;
    __ucps2_synch(0);
    irq_debug(&(debug_info->irq_cnt), irq_cnt);
    irq_debug(&(debug_info->apc_csu_allpendevent0), APC_CSU_ALLPENDEVENT0);

//  val = APC_CSU_ALLPENDEVENT0 & APC_CSU_INTMASKL;
    val = APC_CSU_ALLPENDEVENT0 & g_mask;

    while (val != 0)
    {
        bit_val = find_lsb(val);
        for (k = 0; k < (vec_val->reg_vec_count); k++)
        {
            irq_num_bit = (vec_val->reg_vec_buf[k]) & (bit_32 - 1);
            sys_status = get_int_status_reg(vec_val->reg_vec_buf[k], apcid_set[g_apeid]);
            irq_debug(&(debug_info->irq_sys_status[vec_val->reg_vec_buf[k] >> 5]), sys_status);
            if ((bit_val == irq_num_bit) && (sys_status & (1 << irq_num_bit)))
            {
                if(vec_val->pfun[k] != NULL)
                {
                    fun_cnt_s_c++;
                    irq_debug(&(debug_info->fun_start_cnt_all), fun_cnt_s_c);
                    global_int_cnt[vec_val->reg_vec_buf[k]]++;
                    irq_debug(&(debug_info->fun_run_cnt[vec_val->reg_vec_buf[k]]),global_int_cnt[vec_val->reg_vec_buf[k]]);
                    irq_debug(&(debug_info->cur_irq_num),vec_val->reg_vec_buf[k]);
                    vec_val->pfun[k]();
                    __ucps2_synch(0);
                    APC_CSU_EVENTINTCLEAR = ((vec_val->reg_vec_buf[k]) & 31);
                    __ucps2_synch(0);
                    fun_cnt_e_c++;
                    irq_debug(&(debug_info->fun_end_cnt_all),fun_cnt_e_c);
                }
            }
        }
        val &= ~(1 << bit_val);
    }
    
    APC_CSU_INTMASKL = g_mask;
    __ucps2_synch(0);
    is_irq_context = 0;

}


/*****************************************************

***************************************************/

int smart_irq_init(int cpuid)
{
    int i;
    int32_t addr = (int32_t)__ucps2_interrupt5;
    if((cpuid < 0)||(cpuid > 11))
    {
        return -EINVAL;
    }
    g_apeid = cpuid;
    for(i = 0; i < 32;i++)
    {
        inter_vec_val.pfun[i] = NULL;
    }
    __ucps2_IntAddr(addr);
    __ucps2_IntEn(f_Enable);
    
    return 0;
}


int smart_get_cpuid()
{
    int apeid;
    if(cpuid_times != 0)
    {
        return g_apeid;
    }
    else
    {
        g_apeid = *(volatile unsigned int*)APEID_ADDR;
        __ucps2_synch(0);
        cpuid_times = 1;
    }
    
    return g_apeid;
}

/*

*/
int smart_irq_request(uint32_t vector, irq_handler func)
{
    int mask_val;
    int i= 0;
    int bit_val;
    int apcid;
    int load_val;
    int cpuid = g_apeid;	
    if(vector > FUN_IRQ_MAX_NUM - 1)
    {
        return -EINVAL;
    }
    if (is_irq_context)
    {
        return -EINVAL;
    }
    if((cpuid < 0)||(cpuid > 11))
    {
        return -EINVAL;
    }
    __ucps2_IntEn(f_Disable);
    for(i = 0; i < inter_vec_val.reg_vec_count;i++)
    {
        if(vector == inter_vec_val.reg_vec_buf[i])
        {
            return -EREREG;
        }
    }
    mask_val = vector>>5;
    bit_val = (vector)&(bit_32 -1);
    apcid = apcid_set[cpuid];

    if(apcid ==4)
    {
        load_val =  do_read((PET_CTRL_BASE + 280 + mask_val*4 ));
        load_val |= (1<<bit_val);
        do_write((PET_CTRL_BASE + 280 + mask_val*4 ),load_val);
        __ucps2_synch(0);
    }
    else if(apcid == 5)
    {
        load_val =  do_read((JECS_CTRL_BASE + 40 + mask_val*4 ));
        load_val |= (1<<bit_val);
        do_write((JECS_CTRL_BASE + 40 + mask_val*4 ),load_val);
        __ucps2_synch(0);
    }
    else
    {
        load_val =  do_read((SYSCFG_BASE_ADDR + 720 + mask_val*4 + apcid*bit_64));
        load_val |= (1<<bit_val);
        do_write((SYSCFG_BASE_ADDR + 720 + mask_val*4 + apcid*bit_64),load_val);
        __ucps2_synch(0);
    }
    __ucps2_synch(0);

    reg_cnt++;
    irq_debug(&(debug_info->irq_sys_mask[mask_val]), load_val);
    irq_debug(&(debug_info->reg_irq_val[reg_cnt]), vector);
    irq_debug(&(debug_info->reg_irq_cnt), reg_cnt);
    irq_debug(&(debug_info->reg_irq_cpu_id), cpuid);
    APC_CSU_INTMASKL |= (1 << bit_val);
    __ucps2_synch(0);
    inter_vec_val.reg_vec_buf[inter_vec_val.reg_vec_count] = vector;
    inter_vec_val.pfun[inter_vec_val.reg_vec_count] = func;
    inter_vec_val.reg_vec_count++;
    __ucps2_IntEn(f_Enable);
    
    return 0;

}


int smart_irq_enable(uint32_t vector)
{
    int mask_val;
    int bit_val;
    int apcid;
    int load_val;
    int cpuid = g_apeid;

    if(vector > FUN_IRQ_MAX_NUM - 1)
    {
        return -EINVAL;
    }
    mask_val = vector>>5;
    bit_val = (vector)&(bit_32 -1);
    apcid = apcid_set[cpuid];
    __ucps2_IntEn(f_Disable);
    if(apcid ==4)
    {
        load_val =  do_read((PET_CTRL_BASE + 280 + mask_val*4 ));
        load_val |= (1<<bit_val);
        do_write((PET_CTRL_BASE + 280 + mask_val*4 ),load_val);
        __ucps2_synch(0);
    }
    else if(apcid == 5)
    {
        load_val =  do_read((JECS_CTRL_BASE + 40 + mask_val*4 ));
        load_val |= (1<<bit_val);
        do_write((JECS_CTRL_BASE + 40 + mask_val*4 ),load_val);
        __ucps2_synch(0);
    }
    else
    {
        load_val =  do_read((SYSCFG_BASE_ADDR + 720 + mask_val*4 + apcid*bit_64));
        load_val |= (1<<bit_val);
        do_write((SYSCFG_BASE_ADDR + 720 + mask_val*4 + apcid*bit_64),load_val);
        __ucps2_synch(0);
    }
    __ucps2_IntEn(f_Enable);
    
    return 0;
}



int smart_irq_disable(uint32_t vector)
{
    int mask_val;
    int i= 0;
    int bit_val;
    int apcid;
    int load_val;
    int cpuid = g_apeid;

    if(vector > FUN_IRQ_MAX_NUM - 1)
    {
        return -EINVAL;
    }
    mask_val = vector>>5;
    bit_val = (vector)&(bit_32 -1);
    apcid = apcid_set[cpuid];
    __ucps2_IntEn(f_Disable);
    if(apcid ==4)
    {
        load_val =  do_read((PET_CTRL_BASE + 70*4 + mask_val*4 ));
        load_val &= ~(1<<bit_val);
        do_write((PET_CTRL_BASE + 70*4 + mask_val*4 ),load_val);
        __ucps2_synch(0);
    }
    else if(apcid == 5)
    {
        load_val =  do_read((JECS_CTRL_BASE + 10*4 + mask_val*4 ));
        load_val &= ~(1<<bit_val);
        do_write((JECS_CTRL_BASE + 10*4 + mask_val*4),load_val);
        __ucps2_synch(0);
    }
    else
    {
        load_val =  do_read((SYSCFG_BASE_ADDR + 180*4 + mask_val*4 + apcid*bit_64));
        load_val &= ~(1<<bit_val);
        do_write((SYSCFG_BASE_ADDR + 180*4 + mask_val*4 + apcid*bit_64),load_val);
        __ucps2_synch(0);
    }
    __ucps2_IntEn(f_Enable);
     return 0;
}


/******************************************************************************
******/

int smart_irq_debug_init(uint32_t debug_base_addr, uint32_t len_bytes)
{
    if (debug_base_addr <= 0x10000000)
    {
        return -1;
    }
    if (len_bytes < IRQ_TRACPOINT_SIZE)
    {
        return -2;
    }

    debug_enable = 1;
    debug_addr = debug_base_addr;

    debug_info = (irq_debug_t *)debug_addr;

    return 0;
}

uint32_t smart_irq_get_type_cnt(irq_cnt_type_t num_type)
{
    uint32_t val = 0;
    switch (num_type)
    {
        case all_irq:
            val = irq_cnt;
        break;

        case fun_s:
            val = fun_cnt_s_c;
        break;

        case fun_e:
            val =  fun_cnt_e_c;
        break;

        /*case clear_cnt_error:
            val =  irq_clear_cnt;
        break;

        case irq_check_error:
            val =  irq_check_cnt;
        break;*/

        default:
        break;
    }

    return val;
}

int smart_irq_get_run_cnt(uint32_t irqnum)
{
    int i;

    if (irqnum > (MAX_IRQ_NUM-1))
    {
        return -EINVAL;
    }

    return global_int_cnt[irqnum];
    
    return 0;

}




