#include "ape_cnt.h"
#include "ape_csu.h"
#include "stc_timer.h"
#include "phy_para.h"
#include "ape_cpri_timer.h"
#include "ucp_drv_common.h"
#include "ucp_utility.h"
#include "ucp_printf.h"
#include "smartos.h"

extern void osp_timer_call_task();
extern void osp_timer_call_task_spe(uint8_t u8slot, uint8_t u8taskidx);
stStcTimerPara       gStcTimerPara;
extern stPhyScsPara* phyPara;
extern uint32_t		 gScsId;

void stc_timer_set_tmrpoint(stStcTimerPoint* pTmrPoint)
{
	stc_timer_ctwint_disable();

	gStcTimerPara.slotTddNumMax = do_read_volatile_short(&(phyPara[gScsId].slotNumOfTdd));
	__ucps2_synch(f_SMR);
	gStcTimerPara.slotPointNum = TDD_TMR_POINT_MAX / TDD_SLOT_NUM_MAX; // gStcTimerPara.slotTddNumMax;
	gStcTimerPara.R = STC_RT;
	gStcTimerPara.usR = STC_RT / 1000000;
	gStcTimerPara.ctwSetFinished = 0;
	gStcTimerPara.ctwStartFlag = 0;
	gStcTimerPara.tmrPointTotalNum = 0;
	memset(gStcTimerPara.tmrPointNum, 0, TDD_SLOT_NUM_MAX);
	memset(gStcTimerPara.tmrPoint, 0, sizeof(stStcTimerPoint)*TDD_SLOT_NUM_MAX);
	gStcTimerPara.curSlotNum = 0;
	gStcTimerPara.curSlotTmrPointId = 0;
	
	int32_t apeId = get_core_id();
	if (NULL == pTmrPoint)
	{
		UCP_PRINT_ERROR("pTmrPoint NULL! \r\n");
		return;
	}
    UCP_PRINT_LOG("stc timer set tmrpoint start. \r\n");

	int32_t idx = 0;
	for (int32_t i = 0; i < gStcTimerPara.slotTddNumMax; i++)
	{
		for (int32_t j = 0; j < gStcTimerPara.slotPointNum; j++)
		{
			idx = i*gStcTimerPara.slotPointNum+j;
			gStcTimerPara.tmrPoint[idx].pointVal = pTmrPoint[idx].pointVal*gStcTimerPara.usR;
			gStcTimerPara.tmrPoint[idx].lastFlag = pTmrPoint[idx].lastFlag;
			gStcTimerPara.tmrPointNum[i]++;
			gStcTimerPara.tmrPointTotalNum++;
#ifdef PALLADIUM_TEST
			debug_write((DBG_DDR_IDX_DRV_BASE+5120+(apeId<<10) + (idx<<1)), gStcTimerPara.tmrPoint[idx].pointVal); // 0x5000
			debug_write((DBG_DDR_IDX_DRV_BASE+5120+(apeId<<10) + ((idx<<1) + 1)), gStcTimerPara.tmrPoint[idx].lastFlag); // 0x5000
#endif
			if (1 == pTmrPoint[idx].lastFlag)
			{
				break;
			}
		}
	}
	if (0 < gStcTimerPara.tmrPointTotalNum)
	{
		gStcTimerPara.ctwSetFinished = 1;
	}
}

int32_t setCnt = 0;
void stc_timer_set_next_ctw(int32_t setFlag)
{
	setCnt++;
	int32_t apeId = get_core_id();
	if (1 == setFlag) // set in the slot int function
	{
		uint32_t addr = 0;
		if (apeId & 0x4)
		{
			addr = (uint32_t)(&LTBG1_TIME_BASE);
		}
		else
		{
			addr = (uint32_t)(&LTBG0_TIME_BASE);
		}
		gStcTimerPara.ctwVal = do_read_volatile(addr);
	}
	gStcTimerPara.curSlotTmrPointId++;
	int32_t slotNum = gStcTimerPara.curSlotNum;
	if (gStcTimerPara.curSlotTmrPointId >= gStcTimerPara.tmrPointNum[slotNum]) //gStcTimerPara.slotPointNum)
	{
		UCP_PRINT_ERROR("gStcTimerPara.curSlotTmrPointId: 0x%x error. \r\n", gStcTimerPara.curSlotTmrPointId);
	}
	int32_t idx = slotNum * gStcTimerPara.slotPointNum + gStcTimerPara.curSlotTmrPointId;
#if 0 //def PALLADIUM_TEST
	debug_write((DBG_DDR_IDX_DRV_BASE+384+(apeId<<6)+(setCnt&0x3F)), idx); // 0x600
	debug_write((DBG_DDR_IDX_DRV_BASE+256+(apeId<<6)+(setCnt&0x3F)), gStcTimerPara.tmrPoint[idx].lastFlag); // 0x400
#endif
	gStcTimerPara.ctwVal += gStcTimerPara.tmrPoint[idx].pointVal;
	if (gStcTimerPara.ctwVal >= STC_RT)
	{
		gStcTimerPara.ctwVal -= STC_RT;
	}
	
	do_write(((uint32_t*)(&CTW_REG_TIMER_0_0) + apeId), gStcTimerPara.ctwVal); // set ctw reg, clear ctw int
#if 0 //def PALLADIUM_TEST
	debug_write((DBG_DDR_IDX_DRV_BASE+1024 + (gStcTimerPara.ctwIntCnt&0x1FF) + (apeId << 9)), gStcTimerPara.ctwVal);		// 0x1000
//	debug_write((DBG_DDR_IDX_DRV_BASE+6144 + (setCnt&0x1FF) + (apeId << 9)), gStcTimerPara.ctwVal);		// 0x6000
#endif
}

void stc_timer_todint_init(void)
{
	int32_t apeId = get_core_id();

#ifndef GPS_PP1S_SYNC
	TOD_REG_IRQ_EN |= 0x1;		// set tod int enable
#endif

	uint32_t intNum = APC_STC_INTR8;
	// attach interrupt func
	int32_t ret = smart_irq_request(intNum, isr_stc_tod_int);
	if (0 != ret)
	{
		UCP_PRINT_ERROR("attach int num: 0x%x error. errno = 0x%x. \r\n", intNum, ret);
		debug_write(DBG_DDR_ERR_IDX(apeId, 8), ret);
	}
}

ddr_spinlock_t gSpinLockCtwInit;
void stc_timer_ctwint_init()
{
    int32_t apeId = get_core_id();
	int32_t ret = 0;
	//uint32_t errAddr = 0;

#if 1
	gSpinLockCtwInit.lock_addr = 0xB7FD1400;
	gSpinLockCtwInit.flag_addr = 0xB7FD1404;
    smart_ddr_spinlock_init(&gSpinLockCtwInit);
#else	
	gSpinLockCtwInit.lock_addr = DBG_DDR_SPIN_ADDR_BASE + LOCK_DDR_STC_CTW*DBG_DDR_SPIN_LEN; // 0xB7FD1400;
	gSpinLockCtwInit.flag_addr = DBG_DDR_SPIN_ADDR_BASE + LOCK_DDR_STC_CTW*DBG_DDR_SPIN_LEN + 0x4; // 0xB7FD1404;
	errAddr = DBG_DDR_SPIN_ADDR_BASE + LOCK_DDR_STC_CTW*DBG_DDR_SPIN_LEN + 0x40 + (apeId<<2);
	ret = smart_ddr_spinlock_init(&gSpinLockCtwInit);
    if (0 != ret)
	{
	    debug_write(errAddr, ret);
		return;
	}
#endif

    uint32_t intNum = APC_STC_INTR0 + apeId;
    // attach interrupt func
    smart_ddr_spinlock(&gSpinLockCtwInit);
    ret = smart_irq_request(intNum, isr_stc_timer_int);
	smart_ddr_spinunlock(&gSpinLockCtwInit);
    if (0 != ret)
    {
        UCP_PRINT_EMPTY("attach int num: 0x%x error. errno = 0x%x. \r\n", intNum, ret);
        debug_write(DBG_DDR_ERR_IDX(apeId, 9), ret);
    }
}

void stc_timer_ctwint_enable()
{
	int32_t apeId = get_core_id();

	do_write(((uint32_t*)(&CTW_REG_IRQ_0_0) + apeId), 0x1); // set ctw irq enable
}

void stc_timer_ctwint_disable()
{
	int32_t apeId = get_core_id();

	do_write(((uint32_t*)(&CTW_REG_IRQ_0_0) + apeId), 0x0); // set ctw irq disable
}

//uint32_t stcCnt = 0;
//UINT32 gApe0CtwIntCnt = 0;
void isr_stc_timer_int()
{
	int32_t apeId = get_core_id();
#if 0 //def PALLADIUM_TEST
	gApe0CtwIntCnt++;
	debug_write((DBG_DDR_IDX_DRV_BASE+63+apeId), gApe0CtwIntCnt); // 0xfc
#endif	
	stCoreInt* apeCoreIntInfo = (stCoreInt*)APE_INT_INFO_ADDR + APE_INT_MAXNUM*apeId;

	int32_t status = do_read_volatile(&CTW_REG_STATUS);
	__ucps2_synch(0);
	if (status & (1 << apeId))
	{
#if 0 //def PALLADIUM_TEST
		uint32_t addr = 0;
		if (apeId & 0x4)
		{
			addr = (uint32_t)(&LTBG1_TIME_BASE);
		}
		else
		{
			addr = (uint32_t)(&LTBG0_TIME_BASE);
		}
		debug_write(((DBG_DDR_IDX_DRV_BASE+2048) + (gStcTimerPara.ctwIntCnt&0x1FF) + (apeId<<9)), do_read_volatile(addr));	// 0x2000
#endif
		gStcTimerPara.ctwIntCnt++;
		int32_t idx = gStcTimerPara.curSlotNum * gStcTimerPara.slotPointNum + gStcTimerPara.curSlotTmrPointId;
		uint8_t pointIdx = gStcTimerPara.curSlotTmrPointId;
		if (1 != gStcTimerPara.tmrPoint[idx].lastFlag)
		{
#ifdef PALLADIUM_TEST
//			debug_write((DBG_DDR_IDX_DRV_BASE+192+(apeId<<6)+gStcTimerPara.curSlotNum), idx);			// 0x300
#endif
			stc_timer_set_next_ctw(0);
		}
		else
		{
#ifdef PALLADIUM_TEST
//			debug_write((DBG_DDR_IDX_DRV_BASE+224+(apeId<<6)+gStcTimerPara.curSlotNum), idx);			// 0x380
#endif
			stc_timer_ctwint_disable();
		}
        //debug_write(((DBG_DDR_IDX_DRV_BASE+10240) + ((gStcTimerPara.ctwIntCnt)&0x1FF) + (apeId<<9)), get_tx_nr_slot(1));         		// 0xa000
        debug_write(((DBG_DDR_IDX_DRV_BASE+11264) + (gStcTimerPara.ctwIntCnt&0x1FF) + (apeId<<9)), do_read_volatile(&LTBG_TIME_BASE));  // 0xb000
		osp_timer_call_task_spe(gStcTimerPara.curSlotNum, pointIdx);
        //debug_write(((DBG_DDR_IDX_DRV_BASE+12288) + (gStcTimerPara.ctwIntCnt&0x1FF) + (apeId<<9)), do_read_volatile(&LTBG_TIME_BASE));  // 0xc000
		
#ifdef PALLADIUM_TEST
//		if (1 < gStcTimerPara.ctwIntCnt)
		{
//			uint32_t period = GET_STC_CNT() - stcCnt;// GET_CNT_VAL(apeId)-stcCnt;// 
//			debug_write(((DBG_DDR_IDX_DRV_BASE+3072)+(gStcTimerPara.ctwIntCnt&0x1FF) + (apeId<<9)), period);				// 0x3000
		}
//		stcCnt = GET_STC_CNT();// GET_CNT_VAL(apeId); // 
		debug_write((DBG_DDR_IDX_DRV_BASE+101+(apeId<<1)), gStcTimerPara.ctwIntCnt);	// 0x194
		// write sm
		do_write(&(apeCoreIntInfo[APE_INT_STC].intNum), APE_INT_STC);
		do_write(&(apeCoreIntInfo[APE_INT_STC].intCnt), gStcTimerPara.ctwIntCnt);
		
		//debug_write(((DBG_DDR_IDX_DRV_BASE+6144) + (gStcTimerPara.ctwIntCnt&0x1FF) + (apeId<<9)), do_read_volatile(addr));	// 0x6000
#endif
		status = do_read_volatile(&CTW_REG_STATUS);
	}
}

//extern UINT8 waitTodInt;
//uint32_t gApe0TodIntCnt = 0;
void isr_stc_tod_int()
{
	int32_t apeId = get_core_id();
#ifdef PALLADIUM_TEST
	//gApe0TodIntCnt++;
	//debug_write((DBG_DDR_IDX_DRV_BASE+62), gApe0TodIntCnt);	// 0xf8
#endif	

	int32_t status = do_read_volatile(&TOD_REG_INT_STATUS);
	__ucps2_synch(0);
	if (status & 0x1)
	{
		do_write((&TOD_REG_INT_STATUS), 0x1);
#if 0 //def PALLADIUM_TEST
		uint32_t addr = 0;
		if (apeId & 0x4)
		{
			addr = (uint32_t)(&LTBG1_TIME_BASE);
		}
		else
		{
			addr = (uint32_t)(&LTBG0_TIME_BASE);
		}
		debug_write(((DBG_DDR_IDX_DRV_BASE+4096) + (gStcTimerPara.todIntCnt&0x3FF)), do_read_volatile(addr)); // 0x4000
#endif

#ifndef ENABLE_SFNCAL
		if (0 == gStcTimerPara.todIntCnt)
#else
		if (1 == do_read_volatile(ARM_LOCK_FLAG_ADDR))
#endif
		{
			do_write((uint32_t*)(&TOD_REG_RT_LO), 0);
			do_write((uint32_t*)(&TOD_REG_RT_HI), STC_RT);
 			do_write(STC_RT_ADDR, STC_RT);
		}

#ifdef PALLADIUM_TEST
		if (0 < gStcTimerPara.todIntCnt)
		{
			uint64_t temp = GET_CNT_VAL(apeId) + 0xFFFFFFFF;
			uint32_t period = temp - gStcTimerPara.todLastStcCnt;
			debug_write(((DBG_DDR_IDX_DRV_BASE+1088)+((gStcTimerPara.todIntCnt-1)&0x3F)), period);	// 0x1000
		}
		gStcTimerPara.todLastStcCnt = GET_CNT_VAL(apeId);
#endif
		gStcTimerPara.todIntCnt++;
#ifdef PALLADIUM_TEST
		debug_write((DBG_DDR_IDX_DRV_BASE+64), gStcTimerPara.todIntCnt); // 0x100
#endif
		status = do_read_volatile(&TOD_REG_INT_STATUS);
	}
}



