#include <soc.h>
#include "k_api.h"
#include "cpu_pwr_config.h"

//#if RHINO_CONFIG_CPU_PWR_MGMT

#include "cpu_pwr_hal_lib.h"
#include "pwr_debug.h"

#if RHINO_CONFIG_CPU_TICKLESS
#include "cpu_tickless.h"
#endif /*RHINO_CONFIG_CPU_TICKLESS*/

#ifdef CONFIG_TEE_CA
#include "drv/tee.h"
#endif

/* forward declarations */

extern cpu_pwr_t   *p_cpu_pwr_root_node;

#if RHINO_CONFIG_CPU_TICKLESS
extern one_shot_timer_t tim_one_shot;  /* wakeup source for C1 */
#endif /* RHINO_CONFIG_CPU_TICKLESS */

static cpu_pwr_t cpu_pwr_node_package_0;
static cpu_pwr_t cpu_pwr_node_core_0;
static kstat_t board_cpu_c_state_set
(
    uint32_t cpuCState,
    int   master
)
{
    switch (cpuCState) {
        case CPU_CSTATE_C0:

            //printf("enter C0\n");
            if (master) {
            }

            break;

        case CPU_CSTATE_C1:

            /*
             * put CPU into C1 state
             * to put CPU into C1 state.
             */
            //printf("enter C1\n");
#ifdef CONFIG_CHIP_CH2201
            *(volatile unsigned int *)(0xe000e1c0) = 0xffffffff; // reload wakeup_IRQ
            //*(volatile unsigned int *)(0xe000e280) = 0xffffffff; // clear pend IRQ
            csi_vic_set_wakeup_irq(RTC_IRQn);
            csi_vic_set_wakeup_irq(UART2_IRQn);
            csi_vic_set_wakeup_irq(UART1_IRQn);
            csi_vic_set_wakeup_irq(UART0_IRQn);
            csi_vic_set_wakeup_irq(CORET_IRQn);
            csi_vic_set_wakeup_irq(GPIOA_IRQn);
            csi_vic_set_wakeup_irq(GPIOB_IRQn);
            csi_vic_set_wakeup_irq(TIMA0_IRQn);

#ifdef CONFIG_TEE_CA
            csi_tee_enter_lpm(0, 0, TEE_LPM_MODE_WAIT);
#else
            __WFI();
#endif
#endif
            break;

        default:

            PWR_DBG(DBG_ERR, "invalid C state: C%d\n", cpuCState);
            break;
    }

    return RHINO_SUCCESS;
}

kstat_t board_cpu_pwr_topo_create(void)
{
    cpu_pwr_t    *pCpuNode    = NULL;
    cpu_pwr_t    *pParentL1   = NULL; /* parent of level 1 */
    cpu_pwr_t    *pParentL2   = NULL; /* parent of level 2 */
    kstat_t       retVal      = RHINO_SUCCESS;
    uint32_t      cpuIndex    = 0; /* 0 for UP */

    if (p_cpu_pwr_root_node == NULL) {
        return RHINO_PWR_MGMT_ERR;
    }

    pParentL1 = p_cpu_pwr_root_node;

    pCpuNode = &cpu_pwr_node_package_0;
    retVal = cpu_pwr_node_init_static(CPU_PWR_TOPO_LEVEL_1, "package", 0, pCpuNode);

    if (retVal != RHINO_SUCCESS) {
        return RHINO_PWR_MGMT_ERR;
    }

    /* add this node as a child of p_cpu_pwr_root_node */

    cpu_pwr_child_add(pParentL1, pCpuNode);
    pParentL2 = pCpuNode;

    pCpuNode = &cpu_pwr_node_core_0;
    retVal = cpu_pwr_node_init_static(CPU_PWR_TOPO_LEVEL_2, "core", 0, pCpuNode);

    if (retVal != RHINO_SUCCESS) {
        return RHINO_PWR_MGMT_ERR;
    }

    cpu_pwr_child_add(pParentL2, pCpuNode);

    /* record this node as leaf node in the topology */

    retVal = cpu_pwr_leaf_node_record(pCpuNode, cpuIndex);

    if (retVal == RHINO_PWR_MGMT_ERR) {
        return RHINO_PWR_MGMT_ERR;
    }

    retVal = cpu_pwr_c_method_set_by_level(CPU_PWR_TOPO_LEVEL_2,
                                           board_cpu_c_state_set);

    if (retVal == RHINO_PWR_MGMT_ERR) {
        return RHINO_PWR_MGMT_ERR;
    }

    retVal = cpu_pwr_c_state_capability_set_by_level(CPU_PWR_TOPO_LEVEL_2,
             CPU_STATE_BIT(CPU_CSTATE_C0)
             | CPU_STATE_BIT(CPU_CSTATE_C1)
                                                    );

    if (retVal == RHINO_PWR_MGMT_ERR) {
        return RHINO_PWR_MGMT_ERR;
    }


    cpu_pwr_c_state_latency_save(cpuIndex, CPU_CSTATE_C0, 0);
    cpu_pwr_c_state_latency_save(cpuIndex, CPU_CSTATE_C1, 0);

    tickless_one_shot_timer_save(CPU_CSTATE_C1, &tim_one_shot);

#if RHINO_CONFIG_CPU_TICKLESS

    tickless_c_states_add(CPU_STATE_BIT(CPU_CSTATE_C0)
                          | CPU_STATE_BIT(CPU_CSTATE_C1)
                         );

#endif /* RHINO_CONFIG_CPU_TICKLESS */

    return retVal;
}

//#endif /* RHINO_CONFIG_CPU_PWR_MGMT */
