/*
* This program was created by AXELL CORPORATION.
* Copyright (C) 2017 AXELL CORPORATION, all rights reserved.
*/
#include "kernel.h"
#include "ffsys.h"
#include "sample_common.h"
#include "com.h"
#include "int/intmgr.h"
#include "vram/vrammgr.h"
#include "i2c/i2cmgr.h"
#include "timr/timrmgr.h"
#include "sys/sscprm.h"
#include "sys/spcprm.h"
#include "DDR_COM.h"
#include "DDR_AG903_FTUART010.h"
#ifdef  AG903_SAMPLE_USE_FS
#include "DDR_AG903_SD.h"
#include "DDR_AG903_CF.h"
#include "DDR_AG903_CF_cfg.h"
#include "DDR_AG903_DMA.h"
#endif/*AG903_SAMPLE_USE_FS*/

#include "register/AG903_bscreg.h"
#include "register/AG903_sdcreg.h"

/*************************************************************************************
 * 外部参照
 ************************************************************************************/
extern void ComTask(VP_INT exinf);
extern void _ddr_private_timer_init(UINT tick);
extern void _ddr_gic_init(void);

static void HELP_main(uint8_t param);
extern void CAP_main(uint8_t param);
extern void MTX_main(uint8_t param);
extern void MPS_main(uint8_t param);


/*************************************************************************************
		定数定義
 ************************************************************************************/
#define LIBENT_MAX  (0xFF)	/* libent登録最大数  */

#define AG903_BSC_STAT_IDLE		(0)
#define AG903_BSC_STAT_SLEEP	(1)
#define AG903_BSC_STAT_ACT		(6)
#define AG903_BSC_CMD_IDLE		(7)
#define AG903_BSC_POWERON_WAIT	(300000)
#define AG903_SDC_POWERON_WAIT	(10000)

static struct _lib_entry {

	uint32_t	libid;
	void		(*main)(uint8_t param);
	char		str[32];

}	libent[] = {
	{ 0x00, HELP_main,	"HELP" 	},
	{ 0x01, CAP_main,	"Capture"			},
	{ 0x02, MTX_main,	"Movie Texture"		},
	{ 0x03, MPS_main,	"Movie Player"		},

	{ 0xFF, NULL, 		"dummy"				},
};


/*************************************************************************************
		プロトタイプ定義
 ************************************************************************************/
void MainTask(VP_INT exinf);
static void hw_init(void);
static void fsif_init(void);
static void undefined_instruction_handler(UW *reg, UW psr);

/******************************************************************
        システム用メモリを確保
 ******************************************************************/

#ifdef __CC_ARM
int SYSMEM[0x0F0000/sizeof(int)] __attribute__ ((section ("SYSMEM"), zero_init));
#endif

#ifdef __IAR_SYSTEMS_ICC__
#pragma section = "SYSMEM"
int SYSMEM[AG903_SAMPLE_SYSMEM_SIZE/sizeof(int)] @ "SYSMEM";
#endif

#ifdef __GNUC__
int SYSMEM[AG903_SAMPLE_SYSMEM_SIZE/sizeof(int)] __attribute__((section(".sysmem")));
#endif

/******************************************************************
        スタック用メモリとプール用のメモリを確保
 ******************************************************************/

#ifdef __CC_ARM
int STKMEM[AG903_SAMPLE_STKMEM_SIZE/sizeof(int)] __attribute__ ((section ("STKMEM"), zero_init));
int MPLMEM[AG903_SAMPLE_MPLMEM_SIZE/sizeof(int)] __attribute__ ((section ("MPLMEM"), zero_init));
#endif

#ifdef __IAR_SYSTEMS_ICC__
#pragma section = "STKMEM"
int STKMEM[AG903_SAMPLE_STKMEM_SIZE/sizeof(int)] @ "STKMEM";

#pragma section = "MPLMEM"
int MPLMEM[AG903_SAMPLE_MPLMEM_SIZE/sizeof(int)] @ "MPLMEM";
#endif

#ifdef __GNUC__
int STKMEM[AG903_SAMPLE_STKMEM_SIZE/sizeof(int)] __attribute__((section(".stkmem")));
int MPLMEM[AG903_SAMPLE_MPLMEM_SIZE/sizeof(int)] __attribute__((section(".mplmem")));
#endif

/******************************************************************
        ヒープ不使用を宣言
 ******************************************************************/
#ifdef __CC_ARM
#pragma import(__use_no_heap)
#endif


/******************************************************************
        resource
 ******************************************************************/
const T_CTSK ctsk_main = {TA_HLNG|TA_ACT|TA_FPU, (VP_INT)0, (FP)MainTask, 8, 0x1000, 0, "MainTask"};	/* MainTask */
const T_CTSK ctsk_com  = {TA_HLNG|TA_ACT, (VP_INT)0, (FP)ComTask, 3, 0x1000, 0, "ComTask"};				/* ComTask */
const T_DEXC dexc_vfp  = {TA_NULL, (FP)undefined_instruction_handler};


/*************************************************************************************
		変数定義
 ************************************************************************************/
volatile static ID MainTaskID;
volatile static ID ComTaskID;
volatile static uint8_t MainLibentNum=0;
volatile static int8_t  MainCurrentLibid=0;
volatile static int32_t	ErrorCode = 0;
const char wakeup_str[] = "\r\n[ Usecase Sample Program ]\r\n";	/* 起動Message */

/*******************************
      OSの初期化ルーチン
*******************************/
void initpr(void)
{
    def_exc(EXC_UDF, (T_DEXC *)&dexc_vfp);

    _ddr_private_timer_init(AG903_SAMPLE_TICK);
    _ddr_ag903_uart_init(AG903_SAMPLE_DID_UART0, &REG_UART0);

    MainTaskID = acre_tsk((T_CTSK *)&ctsk_main);
    ComTaskID = acre_tsk((T_CTSK *)&ctsk_com);
}

/*******************************
      main処理
 *******************************/
#if defined(__IAR_SYSTEMS_ICC__)
int main(void)
#elif defined(__GNUC__)
int main(int argc, const char* argv[])
#endif
{
    T_CSYS csys;

    /* ダミーアクセス */

    SYSMEM[0] = 0;
    STKMEM[0] = 0;
    MPLMEM[0] = 0;

    /* ハードウェアの初期化の残り */
    hw_init();
    _ddr_gic_init();

    /* システムの生成と起動 */
    csys.tskpri_max		= AG903_SAMPLE_TSKPRI_MAX;
    csys.tskid_max		= AG903_SAMPLE_TSKID_MAX;
    csys.semid_max		= AG903_SAMPLE_SEMID_MAX;
    csys.flgid_max		= AG903_SAMPLE_FLGID_MAX;
    csys.dtqid_max		= AG903_SAMPLE_DTQID_MAX;
    csys.mbxid_max		= AG903_SAMPLE_MBXID_MAX;
    csys.mtxid_max		= AG903_SAMPLE_MTXID_MAX;
    csys.mbfid_max		= AG903_SAMPLE_MBFID_MAX;
    csys.porid_max		= AG903_SAMPLE_PORID_MAX;
    csys.mpfid_max		= AG903_SAMPLE_MPFID_MAX;
    csys.mplid_max		= AG903_SAMPLE_MPLID_MAX;
    csys.almid_max		= AG903_SAMPLE_ALMID_MAX;
    csys.cycid_max		= AG903_SAMPLE_CYCID_MAX;
    csys.isrid_max		= AG903_SAMPLE_ISRID_MAX;
    csys.devid_max		= AG903_SAMPLE_DEVID_MAX;
    csys.tick			= AG903_SAMPLE_TICK;
    csys.ssb_num		= AG903_SAMPLE_SSB_NUM;
    csys.sysmem_top		= (VP)&SYSMEM[0];
    csys.sysmem_end		= (VP)((ADDR)&SYSMEM[0]+sizeof(SYSMEM));
    csys.stkmem_top		= (VP)&STKMEM[0];
    csys.stkmem_end		= (VP)((ADDR)&STKMEM[0]+sizeof(STKMEM));
    csys.mplmem_top		= (VP)&MPLMEM[0];
    csys.mplmem_end		= (VP)((ADDR)&MPLMEM[0]+sizeof(MPLMEM));
    csys.sysidl			= SYSTEM_IDLE;
    csys.inistk			= STACK_ID_INIT;
    csys.trace			= TRACE_DISABLE;
    csys.agent			= AGENT_DISABLE;
    return (int)start_uC3(&csys, initpr);
}

/******************************************************************
        異常割り込み処理
            割込みハンドラの定義も割込みサービスルーチンの生成も
            されていないのに割込みを受け付けた場合に到達
 ******************************************************************/
void int_abort(void)
{
    for(;;);
}

/***********************************
      未定義命令例外ハンドラ
 ***********************************/
static void undefined_instruction_handler(UW *reg, UW psr)
{
    ER ercd;
    ercd = _kernel_enavfp(reg, psr);
    if (ercd != E_OK) {
        int_abort();
    }
}

/***********************************
      Initializing hardware
 ***********************************/
static void hw_init(void)
{
	uint32_t u32State;
	uint8_t u8PWR, u8VDD;

	/* CF非活性化 */
	u32State = AG903_BSC->CFPMSTAT & AG903_BSC_CFPMSTAT_STAT_MSK;
	switch(u32State){
	case AG903_BSC_STAT_IDLE:
	case AG903_BSC_STAT_SLEEP:
		break;
	default:
		AG903_BSC->CFPMCMD =
			(AG903_BSC_CMD_IDLE << AG903_BSC_CFPMCMD_CMD_POS) |
			(1 << AG903_BSC_CFPMCMD_ACT_POS) |
			(1 << AG903_BSC_CFPMCMD_SLP_POS);

		/* IDLEまで待機. */
		do{
			u32State = AG903_BSC->CFPMSTAT & AG903_BSC_CFPMSTAT_STAT_MSK;
		}while(u32State != AG903_BSC_STAT_IDLE);

		/* 300msウェイト(非活性 > 活性区画待機). */
		sys_delayus(AG903_BSC_POWERON_WAIT);
		break;
	}

	/* SD Power OFF */
	AG903_SDC->Clock_control = 0;
	u8VDD = AG903_SDC->Power_Control_Register;
	u8PWR = (u8VDD & AG903_SDC_Power_Control_Register_SD_Bus_Power_MSK) >>
		AG903_SDC_Power_Control_Register_SD_Bus_Power_POS;
	if(u8PWR != 0){
		AG903_SDC->Power_Control_Register = 0;
		/* 10msウェイト(Power OFF > ON区画待機). */
		sys_delayus(AG903_SDC_POWERON_WAIT);
	}

	Board_SetPotrFunc();	/* 端子機能設定 */

	/* clock enable */
	AG903_SPCPrmSetAhbClkCtrl(0xFFFFFFFF);			/* all enable */
	AG903_SPCPrmSetApbClkCtrl(0xFFFFFFFF);			/* all enable */
	AG903_SPCPrmSetAxiClkCtrl1(0xFFFFFFFF);			/* all enable */
	AG903_SPCPrmSetAxiClkCtrl2(0xFFFFFFFF);			/* all enable */
	AG903_SPCPrmSetApbSdmcClkCtrl(0xFF, 0xFFFFFF);	/* all enable */
	AG903_SPCPrmSetMiscClkCtrl(0xFFFFFFFF);			/* all enable */

	AG903_SPCPrmClkSel clksel;
	clksel.cp1  = AG903_SPC_CP1_CLKSRC_PLL3;	/* キャプチャ用ドットクロック1 */
	clksel.cp0  = AG903_SPC_CP0_CLKSRC_DVOCLK;	/* キャプチャ用ドットクロック2 */
	clksel.lvds = AG903_SPC_LVDS_CLKSRC_DSP1;	/* LVDSトランスミッタCH0 */
	clksel.dt1  = AG903_SPC_DT1_CLKSRC_PLL2;	/* 表示用ドットクロック1 */
	clksel.dt0  = AG903_SPC_DT0_CLKSRC_PLL1;	/* 表示用ドットクロック0 */
	clksel.hda  = AG903_SPC_HDA_CLKSRC_XOUT;	/* HD-Audio用クロック */
	AG903_SPCPrmSetClkSrc(&clksel);

	AG903_SSCPrmDspSetup dspset;
	dspset.vsync0 = AG903_SSC_PINDIR_OUTPUT;	/* CMOS表示出力0のVSYNC端子 */
	dspset.field0 = AG903_SSC_PINDIR_OUTPUT;	/* CMOS表示出力0のFIELD端子 */
	dspset.dot0   = AG903_SSC_PINDIR_OUTPUT;	/* CMOS表示出力0のドットクロック端子 */
	dspset.vsync1 = AG903_SSC_PINDIR_OUTPUT;	/* CMOS表示出力1のVSYNC端子 */
	dspset.field1 = AG903_SSC_PINDIR_OUTPUT;	/* CMOS表示出力1のFIELD端子 */
	dspset.dot1   = AG903_SSC_PINDIR_OUTPUT;	/* CMOS表示出力1のドットクロック端子 */
	AG903_SSCPrmSetDspPinDir(&dspset);

}

/*******************************
      Main Task
 *******************************/
void MainTask(VP_INT exinf)
{
	struct _lib_entry *ent;
	uint32_t	loop;
	char		input[4];
	uint8_t  	libid=0;

	/* Manager初期化 */
	AG903_VRAMMgrInit(AG903_SAMPLE_VRAM_ADDR, AG903_SAMPLE_VRAM_SIZE);
	AG903_INTMgrInit();
	AG903_TIMRMgrInit();
	AG903_I2CMgrInit(AG903_FPGA_I2C_CH);

	/* FS I/F初期化 */
	fsif_init();

    while(1) {								/* ComTask起動待ち */
		if(true == ComCheckInit()) {
			break;
		}
	}
	COM_PutStr((char*)wakeup_str);		/* 起動文字出力 */

	HELP_main(0);

    while(1) {
		COM_PutStr(" input LibraryNo.");
		COM_GetNum_Wait(input, 4);	/* 4 = 2桁入力+CRLF */

		libid  = (ASCtoBIN(input[0])*0x10);
		libid += ASCtoBIN(input[1]);

		ent = (struct _lib_entry *)&libent;
		for(loop=0; loop<MainLibentNum; loop++) {
			if((libid == ent->libid) && (NULL != ent->main)) {
				sys_print(0, " -- %s Sample Start --\r\n", ent->str);
				MainCurrentLibid = libid;
				ent->main(0);		/* サンプル実行 */
				MainCurrentLibid = 0;
				sys_print(0, " -- %s Sample End --\r\n", ent->str);
			}
			ent++;
		}
	}
}

/***********************************
      Initializing  FS I/F
 ***********************************/
static void fsif_init(void)
{

	int32_t				hdl;
	AG903_VRAMMgrMpfPrm	mpf;

	mpf.mpfatr = AG903_OSW_ATRPRI;
	mpf.blkcnt = 1;
	mpf.blksz  = 0x1000;				/* DMA転送用ワークバッファ		*/
	mpf.mpf    = (void *)AG903_SAMPLE_SD_WORKMEM;	/* ベースアドレス 	*/
	mpf.memtype = AG903_VRAM_NORMAL_CACHE_OFF;		/* キャッシュなし	*/
	hdl = AG903_VRAMMgrCreateMpf(&mpf);	/* メモリプール確保				*/
	(void)AG903_VRAMMgrFmalloc(hdl);	/* メモリ確保					*/

	sd_ini(0);							/* SDドライバ初期化		*/

	Board_SetCfInterface();				/* CF I/F設定			*/
	cf_ini(0);							/* CFドライバ初期化		*/
	dma_ini();							/* DMAドライバ初期化 	*/
	REG_BSC.CFC_PWR_MTRG = 0x01;		/* CF Idle→非活性化 	*/

	ffs_ini();							/* FS初期化			*/

	return;
}

/*******************************
      HELPメニュー出力
 *******************************/
void HELP_main(uint8_t param)
{
	uint32_t			loop;
	struct _lib_entry	*ent;

	ent = (struct _lib_entry *)&libent;
	MainLibentNum = 0;

	for(loop=0; loop<LIBENT_MAX; loop++) {	/* メニュー出力 */
		if(NULL == ent->main) {
			break;
		}
		sys_print(0,  " %02X:%s\r\n", (unsigned int)ent->libid, ent->str);
		MainLibentNum++;
		ent++;
	}

	return;
}


