/*
 * Copyright (C) 2017-2020 Alibaba Group Holding Limited
 */


/******************************************************************************
 * @file     system.c
 * @brief    CSI Device System Source File
 * @version  V1.0
 * @date     7. April 2020
 ******************************************************************************/

#include <soc.h>
#include <csi_core.h>
#include <csi_config.h>
#include <drv/io.h>
#include <drv/irq.h>
#include <drv/dma.h>
#include <drv/tick.h>
#include <drv/etb.h>
#include <drv/spiflash.h>

csi_dma_t g_dma;
#ifdef CONFIG_XIP
static csi_spiflash_t g_spiflash;
#endif
extern uint32_t g_top_irqstack;
void section_data_copy(void);
void section_ram_code_copy(void);
void section_bss_clear(void);

static void cache_init(void)
{
#ifdef CONFIG_XIP
    csi_cache_set_range(0U, 0x18000000U, (uint32_t)CACHE_CRCR_8M, 1U);
    csi_icache_enable();
    csi_dcache_enable();
#else
    csi_cache_set_range(0U, 0x20000000U, (uint32_t)CACHE_CRCR_128K, 1U);
    csi_icache_enable();
#endif
}

static void section_init(void)
{
#ifdef CONFIG_XIP
    section_data_copy();
    section_ram_code_copy();
#endif

    section_bss_clear();
}

static void vic_init(void)
{
    /* Clear active and pending IRQ, and disable IRQ */
    VIC->IABR[0] = 0x0U;
    VIC->ICPR[0] = 0xFFFFFFFFU;
    VIC->ICER[0] = 0xFFFFFFFFU;
}

static void interrupt_init(void)
{
    vic_init();

#ifdef CONFIG_KERNEL_NONE
    __enable_excp_irq();
#else
#if defined(CONFIG_SUPPORT_TSPEND)
    __set_Int_SP((uint32_t)&g_top_irqstack);
    __set_CHR(__get_CHR() | CHR_ISE_Msk);
    VIC->TSPR = 0xFF;
#endif
#endif
}

static void sys_dma_init(void)
{
    /* dmac, global register DMACCFG : the global DMAC enable bit only can be operated in security wolrd. */
    csi_dma_init(&g_dma, 0);
}

#ifdef CONFIG_XIP
static void sys_spiflash_init(void)
{
    csi_spiflash_qspi_init(&g_spiflash, 0);
    csi_spiflash_config_data_line(&g_spiflash, SPIFLASH_DATA_4_LINES);
	csi_spiflash_frequence(&g_spiflash, 70000000U);
}
#endif


void s_delay(uint32_t tick)
{
	while(tick--)
		__NOP();
}
/*
 * 在原有1.2V电压的基础上提升0.05V
 * 返回值：是否有调整 true,false
 *    0(1V)  1(1.05V)  2(1.1V)
 *    3(1.15V)  4(1.2v)  5(1.25V)
 *    6(1.3V)   7(1.35V)
 */
bool app_pmu_increase_voltage(void)
{
	uint32_t  reg_val,temp;
	bool flag ;

	flag = true;
	reg_val = (uint32_t)(((wj_pmu_reg_t *)PMU_REG_BASE)->PMU_TRIM);
	temp = reg_val & 0x7000;
	reg_val &= 0xffff8fff;
	temp >>= 12;
	// 出厂时对这个寄存器有校准到1.2V
	// 在出厂校准电压的基础上提高一档，约提高0.05V(每加一提高0.05V)
	temp += 2;
	if(temp > 7)
	{	// 寄存器的最高值是7,即理论值1.35V
		temp = 7;
		flag = false;
	}
	temp <<= 12;
	temp &= 0x7000;
	(((wj_pmu_reg_t *)PMU_REG_BASE)->PMU_TRIM) = reg_val | temp;
	return flag;
}
 

 /*
 * 在原有1.2V电压的基础上降低0.05V
 */
bool app_pmu_reduce_voltage(void)
{
	uint32_t  reg_val,temp;
	bool flag ;

	flag = true;
	reg_val = (((wj_pmu_reg_t *)PMU_REG_BASE)->PMU_TRIM);
	temp = reg_val & 0x7000;
	reg_val &= 0xffff8fff;
	temp >>= 12;
	// 出厂时对这个寄存器有校准到1.2V
	// 在出厂校准电压的基础上提高一档，约提高0.05V(每加一提高0.05V)	
	if(temp > 0)
	{	// 寄存器的最低值是0,即理论值1.00V 。
		temp --;
	}else{
		flag = false;
	}	
	temp <<= 12;
	temp &= 0x7000;
	(((wj_pmu_reg_t *)PMU_REG_BASE)->PMU_TRIM) = reg_val | temp;
	return flag;
}

/**
  * @brief  initialize the system
  * @param  None
  * @return None
  */
__attribute__((weak)) void SystemInit(void)
{
	uint32_t  reg_val;
	reg_val = *(volatile uint32_t *)(0x600300A4U); 
	reg_val &= 0xfffffff8;
	(*(volatile uint32_t *) (0x600300A4U)) = (uint32_t)(reg_val|0x07);   //QSPIDRV STRENTH b010 = 12mA

    cache_init();

    section_init();

    interrupt_init();

//	uint32_t  reg_val,temp;
//	reg_val = (volatile uint32_t)(((wj_pmu_reg_t *)PMU_REG_BASE)->PMU_TRIM);
//	temp = 7<<12;//reg_val & 0x7000;
//	temp &= 0x7000;
//	reg_val &= 0xffff8fff;
//	(((wj_pmu_reg_t *)PMU_REG_BASE)->PMU_TRIM) = (uint32_t)(reg_val|temp);
	
	bool f_trim;
	f_trim = app_pmu_increase_voltage();		// 变频前提升电压
	s_delay(5000);						// 提升电压后等待电压稳定
	soc_set_sys_freq(CPU_258_048MHZ);//CPU_196_608MHZ CPU_245_76MHZ CPU_258_048MHZ CPU_270_336MHZ 
	if(f_trim){
		app_pmu_reduce_voltage();				// 变频前若提高电压，变频后把电压减低到原先值
	}
	
    csi_etb_init();

    /* Init DMA controller */
    sys_dma_init();

    csi_tick_init();

#ifdef CONFIG_XIP
    sys_spiflash_init();
#endif

}
