#include "ape_mtimer.h"
#include "phy_para.h"
#include "ucp_printf.h"
#include "ape_cnt.h"
#include "ucp_utility.h"
#include "ucp_mtimer.h"
#include "stc_timer.h"
#include "mtimer_com.h"
//#ifdef INTEGRATED_BS
#include "ape_jesd_timer.h"
//#else
#include "ape_cpri_timer.h"
#include "ape_ecpri_timer.h"
//#endif

extern void osp_timer_call_task_spe(uint8_t u8slot, uint8_t u8taskidx);        /* 定时点任务从首位开始 */
//extern void osp_timer_restart(void);
extern void osp_timer_call_task();

extern stPhyScsPara*	phyPara;
extern stSfnPara		gCellSfnPara[2];
extern stStcTimerPara 	gStcTimerPara;

extern uint32_t			gScsId;
extern uint32_t			gMtimerId;

ddr_spinlock_t 	gSpinLockBuildCell;

int32_t gApeCalFlag = 0;
int32_t gApeCalCnt = 0;
void ape_mtimer_int_init(uint16_t nTimerId)
{
	uint8_t nBsType = get_protocol_sel(); 
	if (PROTOCOL_JESD == nBsType)
	{
		set_jesd_timer_ape_int(nTimerId);
	}
	else
	{
		if (MTIMER_CPRI_ID == nTimerId)
		{
			set_cpri_timer_ape_int();
		}
		else
		{
			set_ecpri_timer_ape_int();
		}
	}
}
void ape_mtimer_int_clear(uint16_t nTimerId)
{
	uint8_t nBsType = get_protocol_sel(); 
	if (PROTOCOL_JESD == nBsType)
	{
		clr_jesd_timer_ape_int(nTimerId);
	}
	else
	{
		if (MTIMER_CPRI_ID == nTimerId)
		{
			clr_cpri_timer_ape_int();
		}
		else
		{
			clr_ecpri_timer_ape_int();
		}
	}
}

void ape_mtimer_sync(int32_t nScsId)
{
	uint16_t apeId = get_core_id();
	//uint32_t errAddr = 0;
	//int32_t ret = 0;
	gScsId = nScsId;	// LTE_SCS_ID; // 
	uint16_t nTimerId = do_read_volatile_short(&(phyPara[nScsId].mtimerId));
	__ucps2_synch(f_SM);
	gMtimerId = nTimerId;
	if (-1 == mtimer_sfn_para_init(nTimerId, nScsId))
	{
		return;
	}
#if 1
	gSpinLockBuildCell.lock_addr = 0xB7FD1500;
	gSpinLockBuildCell.flag_addr = 0xB7FD1504;
    smart_ddr_spinlock_init(&gSpinLockBuildCell);
#else	
	gSpinLockBuildCell.lock_addr = DBG_DDR_SPIN_ADDR_BASE + LOCK_DDR_BUILD_CELL*DBG_DDR_SPIN_LEN; // 0xB7FD1420;
	gSpinLockBuildCell.flag_addr = DBG_DDR_SPIN_ADDR_BASE + LOCK_DDR_BUILD_CELL*DBG_DDR_SPIN_LEN + 0x4; // 0xB7FD1424;
	errAddr = DBG_DDR_SPIN_ADDR_BASE + LOCK_DDR_BUILD_CELL*DBG_DDR_SPIN_LEN + 0x40 + (apeId<<2);
	ret = smart_ddr_spinlock_init(&gSpinLockBuildCell);
	if (0 != ret)
	{
		debug_write(errAddr, ret);
		return;
	}
#endif
    smart_ddr_spinlock(&gSpinLockBuildCell);
	ape_mtimer_int_init(nTimerId);	// mtimer int attach	

	uint16_t runCore = do_read_volatile_short(&(phyPara[nScsId].runCoreId));
	__ucps2_synch(f_SM);
	runCore |= (1<<apeId);
	do_write_short((&(phyPara[nScsId].runCoreId)), runCore);
    smart_ddr_spinunlock(&gSpinLockBuildCell);
}

void ape_mtimer_unsync(int32_t nScsId)
{
	uint16_t apeId = get_core_id();
	uint16_t nTimerId = do_read_volatile_short(&(phyPara[nScsId].mtimerId));
	
	//gSpinLockBuildCell.lock_addr = 0xB7FD1440;
	//gSpinLockBuildCell.flag_addr = 0xB7FD1444;
    //smart_ddr_spin_lock_init(&gSpinLockBuildCell);

    smart_ddr_spinlock(&gSpinLockBuildCell);
	ape_mtimer_int_clear(nTimerId);	// mtimer int detach	

	uint16_t runCore = do_read_volatile_short(&(phyPara[nScsId].runCoreId));
	__ucps2_synch(f_SM);
	runCore &= (~(1<<apeId));
	do_write_short((&(phyPara[nScsId].runCoreId)), runCore);
    smart_ddr_spinunlock(&gSpinLockBuildCell);
}

int32_t mtimer_sfn_para_init(int32_t nTmrId, int32_t nScsId)
{
	if (((int32_t)MTIMER_CPRI_ID != nTmrId)&&((int32_t)MTIMER_ECPRI_ID != nTmrId))
	{
		UCP_PRINT_ERROR("ape mtimer sync failed. timer id = 0x%x. \r\n", nTmrId);
		return -1;
	}
	memset(&gCellSfnPara[nTmrId], 0, sizeof(stSfnPara));
	gCellSfnPara[nTmrId].scsId = nScsId;
	gCellSfnPara[nTmrId].slotPeriod = do_read_volatile_short(&(phyPara[nScsId].slotPeriod));	// 500; // 
	gCellSfnPara[nTmrId].tddSlotNum = do_read_volatile_short(&(phyPara[nScsId].slotNumOfTdd));	// 10;  // 
	gCellSfnPara[nTmrId].slotMaxNum = do_read_volatile_short(&(phyPara[nScsId].slotNumOfSfn));	// 20;  // 
	__ucps2_synch(f_SMR);
	gCellSfnPara[nTmrId].txSlotNum = 0; // gCellSfnPara[nTmrId].slotMaxNum - 1;
	gCellSfnPara[nTmrId].txSfnNum = 0; // 1023;
	gCellSfnPara[nTmrId].rxSlotNum = gCellSfnPara[nTmrId].slotMaxNum - 1;
	gCellSfnPara[nTmrId].rxSfnNum = 1023;

	return 0;
}

int32_t ape_cal_sfn(uint8_t nTmrId)
{
	int32_t apeId = get_core_id();
	int32_t scsId = 0;
	int32_t i = 0;
	if (1 == gCellSfnPara[nTmrId].ctcIntFlag)
	{
		for (i = 0; i < PHY_SCS_MAX_NUM; i++)
		{
			if (nTmrId == do_read_volatile_short(&(phyPara[i].mtimerId))) // 已建了第一个子载波小区
			{
				gCellSfnPara[nTmrId].scsId = i;
				scsId = i;
				break;
			}
		}
		if (PHY_SCS_MAX_NUM == i)
		{
			return -1;
		}
		
		gCellSfnPara[nTmrId].ctcIntFlag = 0;
		gCellSfnPara[nTmrId].txSfnNum = do_read_volatile(&(phyPara[scsId].txSfnNum));
		gCellSfnPara[nTmrId].rxSfnNum = do_read_volatile(&(phyPara[scsId].rxSfnNum));
		gCellSfnPara[nTmrId].txSlotNum = do_read_volatile(&(phyPara[scsId].txSlotNum));
		gCellSfnPara[nTmrId].rxSlotNum = do_read_volatile(&(phyPara[scsId].rxSlotNum));

		gCellSfnPara[nTmrId].txSlotIntCnt = 0;
		gCellSfnPara[nTmrId].rxSlotIntCnt = 0;

		gApeCalFlag = 1;
		gStcTimerPara.ctwStartFlag = 0;
		gApeCalCnt++;
#ifdef PALLADIUM_TEST
		debug_write((DBG_DDR_IDX_DRV_BASE+536+apeId), gApeCalCnt);	// 0x860
		debug_write((DBG_DDR_IDX_DRV_BASE+548+apeId), GET_STC_CNT());	// 0x890
		debug_write((DBG_DDR_IDX_DRV_BASE+560+apeId), gCellSfnPara[MTIMER_CPRI_ID].txSfnNum);	// 0x8c0
		debug_write((DBG_DDR_IDX_DRV_BASE+568+apeId), gCellSfnPara[MTIMER_CPRI_ID].rxSfnNum);	// 0x8e0
#endif
	}
	return 0;
}

void ape_slot_ctw_set(uint8_t nTmrId)
{
	int32_t apeId = get_core_id();
	stCoreInt* apeCoreIntInfo = (stCoreInt*)APE_INT_INFO_ADDR + APE_INT_MAXNUM*apeId;
	int32_t slotIdx = gCellSfnPara[nTmrId].txSlotNum % gCellSfnPara[nTmrId].tddSlotNum; // 10; // 
	if ((0 < gStcTimerPara.tmrPointTotalNum) && (0 == gCellSfnPara[nTmrId].txSlotNum) && (1==gApeCalFlag))
	{
		gStcTimerPara.ctwStartFlag = 1;
		gApeCalFlag = 0;
		gStcTimerPara.ctwIntCnt = 0;
		gStcTimerPara.apeSlotCallCnt = 0;
	}
	if ((0 < gStcTimerPara.tmrPointNum[slotIdx]) && (1 == gStcTimerPara.ctwStartFlag))
	{
		gStcTimerPara.curSlotNum = slotIdx;
		gStcTimerPara.curSlotTmrPointId = 0;
//		debug_write(((DBG_DDR_IDX_DRV_BASE+9216) + (gSfnPara.txSlotIntCnt&0x1FF) + (apeId << 9)), GET_STC_CNT());		// 0x9000 // 更新完时隙号
		int32_t pointIdx = gStcTimerPara.curSlotNum * gStcTimerPara.slotPointNum + 0;
		if (1 != gStcTimerPara.tmrPoint[pointIdx].lastFlag) // not the last point of this slot, set the next ctw point
		{
			stc_timer_set_next_ctw(1);
			stc_timer_ctwint_enable();
		}
		debug_write(((DBG_DDR_IDX_DRV_BASE+15360) + (gCellSfnPara[nTmrId].txSlotIntCnt&0x1FF) + (apeId << 9)), GET_STC_CNT());		// 0xd000 // 设置完下一个stc点

		//osp_timer_call_task();
		osp_timer_call_task_spe(gStcTimerPara.curSlotNum, 0); 	   /* 定时点任务从首位开始 */
		gStcTimerPara.apeSlotCallCnt++;
#ifdef PALLADIUM_TEST
		debug_write((DBG_DDR_IDX_DRV_BASE+100+(apeId<<1)), gStcTimerPara.apeSlotCallCnt);	// 0x190
#endif
		// write sm
		do_write(&(apeCoreIntInfo[APE_INT_STC_0US].intNum), APE_INT_STC_0US);
		do_write(&(apeCoreIntInfo[APE_INT_STC_0US].intCnt), gStcTimerPara.apeSlotCallCnt);
	}
}

uint32_t lastTxStcCnt = 0;
uint32_t nowTxStcCnt = 0;
uint32_t apeSlotErrCnt = 0;
uint32_t apeSlotInterMax = 0;
int32_t mtimer_ape_slot_callback(uint8_t nTmrId)
{
	uint32_t tmrBaseAddr = 0;
	uint8_t nBsType = get_protocol_sel(); 

	if (PROTOCOL_JESD == nBsType)
	{
		if (nTmrId >= MTIMER_INTEGRATED_MAX_NUM)
		{
			return -1;
		}
		tmrBaseAddr = JS_RX0_TMR_BASE + nTmrId * 0x1000;
	}
	else
	{
		if (MTIMER_CPRI_ID == nTmrId)
		{
			tmrBaseAddr = CPRI_TMR_BASE;
		}
		else if (MTIMER_ECPRI_ID == nTmrId)
		{
			tmrBaseAddr = ECPRI_TMR_BASE;
		}
		else
		{
			return -1;
		}
	}

	uint32_t tmrIntcFlag = 0;
	uint32_t tEventFlag = 0;
	int32_t apeId = get_core_id();
	int32_t eventId = MTMR_INT_APE0_SLOT + apeId;
	stCoreInt* apeCoreIntInfo = (stCoreInt*)APE_INT_INFO_ADDR + APE_INT_MAXNUM*apeId;

	tmrIntcFlag = do_read_volatile(tmrBaseAddr+MTMR_INTC_REG);
	//__ucps2_synch(0);
	if (tmrIntcFlag & (1 << eventId))  /* tmr int */
	{
		uint32_t flagAddr = tmrBaseAddr+MTMR_TINTF00_REG + 6*((MTMR_INT_APE0_SLOT+apeId)<<2);
		int32_t txSlotTmrId = MTMR_APE0_TXSLOT + (apeId << 1);
		int32_t rxSlotTmrId = MTMR_APE0_RXSLOT + (apeId << 1);
		tEventFlag = do_read_volatile(flagAddr);
		//__ucps2_synch(0);
		if (tEventFlag & ((1<<txSlotTmrId) | (1<<rxSlotTmrId)))
		{
			if (tEventFlag & (1<<txSlotTmrId)) // tx slot offset
			{
//				debug_write(((DBG_DDR_IDX_DRV_BASE+8192) + (gSfnPara.txSlotIntCnt&0x1FF) + (apeId << 9)), GET_STC_CNT());		// 0x8000 // 刚进时隙中断
				
				uint32_t crVal = (1<<txSlotTmrId);
				do_write((tmrBaseAddr+MTMR_TEVENT0_REG), crVal);
				do_write(flagAddr, crVal);
//uint32_t start = GET_STC_CNT();				
				// sfn calibration
				ape_cal_sfn(nTmrId);
				// update sfn and slot num
				gCellSfnPara[nTmrId].txSlotNum++;
				__ucps2_synch(0);
				if (gCellSfnPara[nTmrId].txSlotNum == gCellSfnPara[nTmrId].slotMaxNum)
				{
					gCellSfnPara[nTmrId].txSfnNum++;
					gCellSfnPara[nTmrId].txSfnNum &= 0x3FF;
					gCellSfnPara[nTmrId].txSlotNum = 0;
				}

				gCellSfnPara[nTmrId].txSlotTiming = GET_STC_CNT();
//				ucp_wdt0_feed(); // wdt0 feed

				do_write(SLOT_NUM_DEBUG_ADDR+((apeId<<2)<<2), gCellSfnPara[nTmrId].txSfnNum);
				do_write(SLOT_NUM_DEBUG_ADDR+((1+(apeId<<2))<<2), gCellSfnPara[nTmrId].txSlotNum);

				// about stc timer point
				ape_slot_ctw_set(nTmrId);
//				debug_write(((DBG_DDR_IDX_DRV_BASE+14336) + (gSfnPara.txSlotIntCnt&0x1FF) + (apeId << 9)), GET_STC_CNT());		// 0xe000 // 中断即将退出
#ifdef PALLADIUM_TEST
				if (8 > gCellSfnPara[nTmrId].txSlotIntCnt)
				{
					debug_write((DBG_DDR_IDX_DRV_BASE+576+(apeId<<3)+gCellSfnPara[nTmrId].txSlotIntCnt), (GET_STC_CNT())); // -gRfm0LastTxTiming)); // 0x900
				}
#endif
				gCellSfnPara[nTmrId].txSlotIntCnt++;
#if 0 //def PALLADIUM_TEST
				uint32_t irqAddr = DBG_DDR_IRQ_ADDR_BASE + apeId*DBG_DDR_IRQ_LEN + 0x98 + 4*(APC_CPRI_TMR_INTR0+MTMR_INT_APE0_SLOT+apeId); 
				debug_write((DBG_DDR_IDX_DRV_BASE+24+apeId), do_read_volatile(irqAddr));
#endif
				debug_write((DBG_DDR_IDX_DRV_BASE+84+(apeId<<1)), gCellSfnPara[nTmrId].txSlotIntCnt);	// 0x150
				// write sm
				do_write(&(apeCoreIntInfo[APE_INT_TX_SLOT].intNum), APE_INT_TX_SLOT);
				do_write(&(apeCoreIntInfo[APE_INT_TX_SLOT].intCnt), gCellSfnPara[nTmrId].txSlotIntCnt);
#if 0
				//debug_write(((DBG_DDR_IDX_DRV_BASE+448) + (gCellSfnPara[nTmrId].txSlotIntCnt&0x3F)), gCellSfnPara[nTmrId].txSlotIntCnt);		// 0x700
				//debug_write(((DBG_DDR_IDX_DRV_BASE+512) + (gCellSfnPara[nTmrId].txSlotIntCnt&0x3F)), get_tx_nr_slot(NR_SCS_30K)); 	// 0x800
				nowTxStcCnt = GET_STC_CNT();
				if ((nowTxStcCnt > lastTxStcCnt) && (2 < gCellSfnPara[nTmrId].txSlotIntCnt))
				{
					uint32_t cost = nowTxStcCnt - lastTxStcCnt;
					//debug_write(((DBG_DDR_IDX_DRV_BASE+576) + (gCellSfnPara[nTmrId].txSlotIntCnt&0x3F)), nowTxStcCnt);					// 0x900
					//debug_write(((DBG_DDR_IDX_DRV_BASE+640) + (gCellSfnPara[nTmrId].txSlotIntCnt&0x3F)), cost); 	// 0xa00
					if (((gCellSfnPara[nTmrId].slotPeriod*1000+5000) < cost) || ((gCellSfnPara[nTmrId].slotPeriod*1000-5000) > cost))
					{
						apeSlotErrCnt++;
						debug_write((DBG_DDR_IDX_DRV_BASE+92+(apeId<<1)), apeSlotErrCnt);	// 0x170
					}
					if (apeSlotInterMax < cost)
					{
						apeSlotInterMax = cost;
						debug_write((DBG_DDR_IDX_DRV_BASE+93+(apeId<<1)), apeSlotInterMax);	// 0x174
					}
				}
				lastTxStcCnt = nowTxStcCnt;
#endif
//debug_write((DBG_DDR_IDX_DRV_BASE+292+(apeId<<2)), (GET_STC_CNT()-start)); // 0x490
			}
			if (tEventFlag & (1<<rxSlotTmrId)) // rx slot offset
			{
				uint32_t crVal = ((1<<rxSlotTmrId));
				do_write(((tmrBaseAddr+MTMR_TEVENT0_REG)), crVal);
				do_write(flagAddr, crVal);
//uint32_t start = GET_STC_CNT();
				gCellSfnPara[nTmrId].rxSlotNum++;
				__ucps2_synch(0);
				if (gCellSfnPara[nTmrId].rxSlotNum == gCellSfnPara[nTmrId].slotMaxNum)
				{
					gCellSfnPara[nTmrId].rxSfnNum++;
					gCellSfnPara[nTmrId].rxSfnNum &= 0x3FF;
					gCellSfnPara[nTmrId].rxSlotNum = 0;
				}
				
				gCellSfnPara[nTmrId].rxSlotTiming = GET_STC_CNT();

				do_write(SLOT_NUM_DEBUG_ADDR+((2+(apeId<<2))<<2), gCellSfnPara[nTmrId].rxSfnNum);
				do_write(SLOT_NUM_DEBUG_ADDR+((3+(apeId<<2))<<2), gCellSfnPara[nTmrId].rxSlotNum);

#ifdef PALLADIUM_TEST
				if (8 > gCellSfnPara[nTmrId].rxSlotIntCnt)
				{
					debug_write((DBG_DDR_IDX_DRV_BASE+624+(apeId<<3)+gCellSfnPara[nTmrId].rxSlotIntCnt), (GET_STC_CNT())); // -gRfm0LastTxTiming)); // 0x900
				}
#endif
				gCellSfnPara[nTmrId].rxSlotIntCnt++;
#ifdef PALLADIUM_TEST
				debug_write((DBG_DDR_IDX_DRV_BASE+85+(apeId<<1)), gCellSfnPara[nTmrId].rxSlotIntCnt);	// 0x154
#endif
				// write sm
				do_write(&(apeCoreIntInfo[APE_INT_RX_SLOT].intNum), APE_INT_RX_SLOT);
				do_write(&(apeCoreIntInfo[APE_INT_RX_SLOT].intCnt), gCellSfnPara[nTmrId].rxSlotIntCnt);
				
//debug_write((DBG_DDR_IDX_DRV_BASE+293+(apeId<<2)), (GET_STC_CNT()-start)); // 0x494
			}
			tEventFlag = do_read_volatile(flagAddr);
		}
		do_write((tmrBaseAddr+MTMR_INTC_REG), (1 << eventId));			// clear int
	}

	return 0;
}

int32_t get_tx_nr_sfn(uint8_t scs)
{
	return gCellSfnPara[gMtimerId].txSfnNum;
}

int32_t get_tx_lte_sfn()
{
	return gCellSfnPara[gMtimerId].txSfnNum;
}

int32_t get_tx_nr_slot(uint8_t scs)
{
	return gCellSfnPara[gMtimerId].txSlotNum;
}

int32_t get_tx_lte_subframe()
{
	return gCellSfnPara[gMtimerId].txSlotNum;
}

int32_t get_rx_nr_sfn(uint8_t scs)
{
	return gCellSfnPara[gMtimerId].rxSfnNum;
}

int32_t get_rx_lte_sfn()
{
	return gCellSfnPara[gMtimerId].rxSfnNum;
}

int32_t get_rx_nr_slot(uint8_t scs)
{
	return gCellSfnPara[gMtimerId].rxSlotNum;
}

int32_t get_rx_lte_subframe()
{
	return gCellSfnPara[gMtimerId].rxSlotNum;
}

uint32_t get_tx_nr_slot_cycle()
{
	uint32_t txSlotTiming = (uint32_t)gCellSfnPara[gMtimerId].txSlotTiming;
	__ucps2_synch(0);
	int32_t offsetCycle = GET_STC_CNT() - txSlotTiming;
	if (0 > offsetCycle)
	{
		uint32_t limitVal = 1000000000;
		offsetCycle = (offsetCycle+limitVal)%limitVal;
	}

	return offsetCycle;
}

uint32_t get_tx_lte_subframe_cycle()
{
	uint32_t txSlotTiming = (uint32_t)gCellSfnPara[gMtimerId].txSlotTiming;
	__ucps2_synch(0);
	int32_t offsetCycle = GET_STC_CNT() - txSlotTiming;
	if (0 > offsetCycle)
	{
		uint32_t limitVal = 1000000000;
		offsetCycle = (offsetCycle+limitVal)%limitVal;
	}

	return offsetCycle;
}

uint32_t get_rx_nr_slot_cycle()
{
	uint32_t rxSlotTiming = (uint32_t)gCellSfnPara[gMtimerId].rxSlotTiming;
	__ucps2_synch(0);
	int32_t offsetCycle = GET_STC_CNT() - rxSlotTiming;
	if (0 > offsetCycle)
	{
		uint32_t limitVal = 1000000000;
		offsetCycle = (offsetCycle+limitVal)%limitVal;
	}

	return offsetCycle;
}

uint32_t get_rx_lte_subframe_cycle()
{
	uint32_t rxSlotTiming = (uint32_t)gCellSfnPara[gMtimerId].rxSlotTiming;
	__ucps2_synch(0);
	int32_t offsetCycle = GET_STC_CNT() - rxSlotTiming;
	if (0 > offsetCycle)
	{
		uint32_t limitVal = 1000000000;
		offsetCycle = (offsetCycle+limitVal)%limitVal;
	}

	return offsetCycle;
}

