#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "t1001.h"
#include "t1001_rtc.h"
#include "t1001_uart.h"
#include "omw_gpio.h"
#include "t1001_sleep_2g4.h"
#include "omw_timer.h"
#include "omw_flash.h"


#ifdef OMW_EN_DEEP_SLEEP
#define T1001_SLEEP_MAX_ADDR_NR_EXT    (sizeof(addr_list) / sizeof(uint32_t))

static uint32_t * g_save_buf;

#ifdef OMW_SAVE_UART0_REGS
static uint32_t * uart0_save_buf;
#endif
#ifdef OMW_SAVE_UART1_REGS
static uint32_t * uart1_save_buf;
#endif

uint32_t sleep_wakeup_reason;
uint32_t Timer_load_Count;	//timer计数保护

static uint32_t addr_list[] =
{
    /////////////////////////////////////////////// REGS///////////////////////////////////
    /* Device regs */
    #ifdef OMW_SAVE_UART1_REGS
    (uint32_t)&CLIC->CLICINT[UART1_IRQn],
    #endif
	(uint32_t)&CLIC->CLICINT[UART0_IRQn],
	(uint32_t)&CLIC->CLICINT[TIMER0_IRQn],

   /* RF regs */
	0x42001070, 0x4200005C, 0x420000CC,
//	0x42001004, 0x42001020, 0x42001024,
	
    /* GPIO regs */
    0x40010200, 0x40010204, 0x40010208, 0x4001020C, 0x40010210, 0x40010214, 0x40010300, 0x40010304,
    0x40010010, 0x40010030, 0x40010040, 0x40010170, 0x40010180, 0x40010190, 0x400101A0, 0x40010140,

    /* SPIS regs */

    /* TIMER0 regs */
	0x41008008,0x410080b0,
	0x40000024,0x40000030,0x40000034,0x42002000,
};

#if defined(OMW_SAVE_UART0_REGS) || defined(OMW_SAVE_UART1_REGS)
#include "t1001_uart.h"

#define IER_DLL 5
#define IER_DLF (sizeof(uart_addr_idx_list) - 1)

uint8_t uart_addr_idx_list[] =
{
    OMW_UART_LCR, OMW_UART_LCR_EXT,  OMW_UART_FCR,  OMW_UART_MCR,  OMW_UART_IER,
    OMW_UART_DLL, OMW_UART_DLH, OMW_UART_DLF,
};

void wait_uart_not_busy(uint32_t * uart_base_addr);

static void t1001_sleep_save_uart_reg_info(uint32_t * uart, uint32_t * save_buf)
{
    volatile uint32_t * uart_reg_base = (volatile uint32_t *)uart;

    for (int i = 0; i < sizeof(uart_addr_idx_list); i++)
    {
        if (i == IER_DLL)
        {
            wait_uart_not_busy(uart);

            uart_reg_base[OMW_UART_LCR] |= 0x80; //LCR_DLAB
        }

        save_buf[i] = uart_reg_base[uart_addr_idx_list[i]];
    }
}

void t1001_sleep_restore_uart_reg_info(uint32_t * uart, uint32_t * save_buf)
{
    volatile uint32_t * uart_reg_base = (volatile uint32_t *)uart;

    for (int i = 0; i < sizeof(uart_addr_idx_list); i++)
    {
        if (i == IER_DLL)
        {
            wait_uart_not_busy(uart);

            uart_reg_base[OMW_UART_LCR] |= 0x80; //LCR_DLAB
        }

        uart_reg_base[uart_addr_idx_list[i]] = save_buf[i];

        if (i == IER_DLF)
        {
            uart_reg_base[OMW_UART_LCR] &= (~0x80); //LCR_DLAB
        }
    }
}
#endif

static void hc_Timer_sleep_save_reg()
{
	Timer_load_Count = *(volatile uint32_t *)(0x41008000);	//计数寄存器保存
	omw_timer_en(TIMER0,DISABLE);
	omw_timer_it_en(TIMER0,DISABLE);
	omw_timer_it_clr();
}

static void hc_Timer_sleep_restore_reg()
{
	*(volatile uint32_t *)(0x41008000) = Timer_load_Count;
	omw_timer_it_clr();
	omw_timer_en(TIMER0,ENABLE);
	omw_timer_it_en(TIMER0,ENABLE);
}

static void t1001_sleep_save_reg_info_ext()
{
    for (uint8_t i = 0; i < T1001_SLEEP_MAX_ADDR_NR_EXT; i++)
    {
        g_save_buf[i] = *(uint32_t *)addr_list[i];
    }

#ifdef OMW_SAVE_UART0_REGS
    //maybe need to de-init uart gpio
    t1001_sleep_save_uart_reg_info(OMW_UART0, uart0_save_buf);
#endif

#ifdef OMW_SAVE_UART1_REGS
    //maybe need to de-init uart gpio
    t1001_sleep_save_uart_reg_info(OMW_UART1, uart1_save_buf);
#endif
	hc_Timer_sleep_save_reg();
}

static void t1001_sleep_restore_reg_info_ext()
{
    #ifdef OMW_SAVE_UART0_REGS
    t1001_sleep_restore_uart_reg_info(OMW_UART0, uart0_save_buf);
    #endif

    #ifdef OMW_SAVE_UART1_REGS
    t1001_sleep_restore_uart_reg_info(OMW_UART1, uart1_save_buf);
    #endif

    for (uint8_t i = 0; i < T1001_SLEEP_MAX_ADDR_NR_EXT; i++)
    {
        *(uint32_t *)addr_list[i] = g_save_buf[i];
    }
	
	hc_Timer_sleep_restore_reg();
}

__RAM_CODE_SECTION
static void opt_init_ext(void)
{	
	void (*otp_init_old)(void) = (void *)0x00000102;
	otp_init_old();
	//flash power on
	flash_release_from_sleep_and_read_device_id();		//flash唤醒指令发送
}

#ifdef CONFIG_OTP_PROGRAM
void (*otp_init)(void) = opt_init_ext;	//OTP区域供电使能API与Flash唤醒指令发送
#endif

#ifdef CONFIG_FLASH_PROGRAM
// Description: set flash power GPIO state, from output '1' to '0'
// NOTE:
//   1) if more than one GPIO, invoke this function more than one times
__RAM_CODE_SECTION
void flash_power_off(int p){
    #if (CONFIG_FLASH_PROGRAM)
    int t;
    t = GPIO_INOUT->GPIO_O;
    t = t & (~(1<<p));
    GPIO_INOUT->GPIO_O = t;
    #endif
}

__RAM_CODE_SECTION
void qspi_regs_restore()	//唤醒时，flash通讯脚配置
{
    #if (CONFIG_FLASH_PROGRAM)
	#ifndef SOP16_1820FPG		
	REG_WRT(0x40010208, QSPI_FLASH_FUNC_REG1_VAL);
    REG_WRT(0x4001020C, QSPI_FLASH_FUNC_REG2_VAL);	//10,12,14,15
	#else
	REG_WRT(0x40010204, QSPI_FLASH_FUNC_REG1_VAL);
    REG_WRT(0x40010208, QSPI_FLASH_FUNC_REG2_VAL);	//4,6,8,9
	#endif	
	REG_WRT(0x40010300, QSPI_REMAP_REG_VAL);
    #endif
}
#endif

void T1001_ChipSleepCriticalWork(void);

#define MAX_GPIO_NR  24
uint32_t   unused_gpio_mask_when_sleep;

void t1001_cfg_wakeup_gpio(uint32_t gpio_mask, uint8_t is_n_wakeup)
{
    unused_gpio_mask_when_sleep &= ~gpio_mask;

    for (int i = 0; i < MAX_GPIO_NR; i++)
    {
        if ((gpio_mask >> i) & 0x1)
        {
            uint32_t func_val = is_n_wakeup ? 0x20 : 0x40;
            //TODO: if has remap, need to cfg remap regs
            omw_gpio_set_func(i, func_val);
        }
    }

    /* Setup the Wakeup Source */
    if (!is_n_wakeup)
    {
        AON_CTRL->WAKEUP_CTRL0 = gpio_mask;
    }
    else
    {
        AON_CTRL->WAKEUP_CTRL1 = gpio_mask;
    }
}

__RAM_CODE_SECTION
void T1001_ChipSleepCriticalWork_ext(void)
{
	//flash power off	
	flash_deep_power_down();	//flash休眠指令发送
	
	T1001_ChipSleepCriticalWork();	//原休眠底层函数
}

static uint8_t T1001_InternalSleep(uint32_t gpioWakeBitMask, uint32_t gpionWakeBitMask)
{
    uint32_t  reg_save_buf[T1001_SLEEP_MAX_ADDR_NR_EXT];

    g_save_buf = reg_save_buf;

    unused_gpio_mask_when_sleep = OMW_WHEN_SLEEP_GPIO_MASK;

    #ifdef OMW_SAVE_UART0_REGS
    uint32_t uart0_save_buf_lc[sizeof(uart_addr_idx_list)];
    uart0_save_buf = uart0_save_buf_lc;
    #endif

    #ifdef OMW_SAVE_UART1_REGS
    uint32_t uart1_save_buf_lc[sizeof(uart_addr_idx_list)];
    uart1_save_buf = uart1_save_buf_lc;
    #endif

    t1001_sleep_save_reg_info_ext();	//休眠保护函数
	
	if (gpioWakeBitMask || gpionWakeBitMask)
    {
        t1001_cfg_wakeup_gpio(gpioWakeBitMask, 0);
        t1001_cfg_wakeup_gpio(gpionWakeBitMask, 1);
    }		//休眠唤醒GPIO宏配置

    // Clear sleep flag.
    AON_CTRL->CPU_RST_CLR = 0x3ff;
    AON_CTRL->WAKEUP_CLEAR = 0x1000000;

    T1001_ChipSleepCriticalWork_ext();	//休眠底层函数，Flash休眠

    __disable_irq();

    //gpio hold has been released
    t1001_sleep_restore_reg_info_ext();

    // save wakeup info, avoid error in avtive, must clear here.
    sleep_wakeup_reason = AON_CTRL->CPU_RST_RCD;

    // Clear sleep flag.
    AON_CTRL->CPU_RST_CLR = 0x3ff;

    __enable_irq();

    return 1;
}

void force_sleep_wakeup_check()
{

}

uint32_t omw_sleep_clr_wkup_rec()
{
    uint32_t  w_rec = AON_CTRL->WAKEUP_RECORD;

    if (w_rec)
    {
        AON_CTRL->WAKEUP_CLEAR = w_rec;
        for (volatile int i = 0; i < 500; i++);
        AON_CTRL->WAKEUP_CLEAR = 0;
    }

    return w_rec;
}

__RAM_CODE_SECTION
void gpio_regs_restore_before_rel_gpio_hold()
{//the gpio regs need to be restored before gpio hold released, set here

}

#ifdef CONFIG_FLASH_PROGRAM
extern uint8_t  gpio_vdd_pin1;
extern uint8_t  gpio_vdd_pin2;
extern uint8_t  has_flash;
#endif

#ifdef CONFIG_OTP_PROGRAM
extern uint8_t has_otp;
#endif

uint32_t omw_sleep_goto_sleep()
{
    #ifdef CONFIG_FLASH_PROGRAM
    has_flash = CONFIG_FLASH_PROGRAM;
//    gpio_vdd_pin1 = OMW_FLASH_VDDIO_PIN1;
//    gpio_vdd_pin2 = OMW_FLASH_VDDIO_PIN2;
    #endif

    #ifdef CONFIG_OTP_PROGRAM
    has_otp = CONFIG_OTP_PROGRAM;
    #endif

    T1001_InternalSleep(OMW_GPIO_WAKEUP_MASK, OMW_GPIO_nWAKEUP_MASK);

    return AON_CTRL->WAKEUP_RECORD;
}

#endif
