2025-12-17 15:55:25 +08:00

162 lines
5.5 KiB
C

/*
* Kneron Power Base driver
*
* Copyright (C) 2019 Kneron, Inc. All rights reserved.
*
*/
#include "kdrv_power.h"
#include "kdrv_scu.h"
#include "kdrv_scu_ext.h"
#include "kdrv_system.h"
#include "kdrv_clock.h" // for kdrv_delay_us()
#include "kdrv_ddr.h"
//#include "kmdw_console.h"
/************************************************************************
* Power Register Releated Macros
************************************************************************/
#define POWER_DOMAIN_WORKING_NONE 0x00000000
#define POWER_DOMAIN_WORKING_DEFAULT 0x00000001
#define POWER_DOMAIN_WORKING_NPU 0x00000002
#define POWER_DOMAIN_WORKING_DDR 0x00000004
#define POWER_DOMAIN_WORKING_ALL (POWER_DOMAIN_WORKING_DEFAULT | POWER_DOMAIN_WORKING_NPU | POWER_DOMAIN_WORKING_DDR)
#define POWER_DOMAIN_SOFTOFF_DEFAULT 0x00000010
#define POWER_DOMAIN_SOFTOFF_NPU 0x00000020
#define POWER_DOMAIN_SOFTOFF_DDR 0x00000040
#define POWER_DOMAIN_SOFTOFF_MASK (POWER_DOMAIN_SOFTOFF_DEFAULT | \
POWER_DOMAIN_SOFTOFF_NPU | \
POWER_DOMAIN_SOFTOFF_DDR)
#define PWR_CTRL_SOFTOFF_MASK (SCU_REG_PWR_CTRL_PWRUP_UPDATE | \
SCU_REG_PWR_CTRL_PWRUP_CTRL_MASK | \
SCU_REG_PWR_CTRL_PWRDN_CTRL_MASK)
#define PWR_CTRL_SOFTOFF_DEEP_RETENTION (SCU_REG_PWR_CTRL_PWRUP_UPDATE | \
SCU_REG_PWR_CTRL_PWRUP_CTRL_DOMAIN_DDRCK | \
SCU_REG_PWR_CTRL_PWRUP_CTRL_DOMAIN_DEFAULT | \
SCU_REG_PWR_CTRL_PWRDN_CTRL_DOMAIN_DDRCK)
#define PWR_CTRL_SOFTOFF_RTC_MODE (SCU_REG_PWR_CTRL_PWRUP_UPDATE | \
SCU_REG_PWR_CTRL_PWRUP_CTRL_DOMAIN_DEFAULT)
kdrv_power_mode_t __power_mgr_mode = POWER_MODE_RTC;
/************************************************************************
* Private API
************************************************************************/
static void _power_mgr_ops_fcs()
{
masked_outw(SCU_REG_PWR_MOD,
SCU_REG_PWR_MOD_SELFR_CMD_OFF | //scu will NOT issue the self-refresh command to DDR/SDR (in FCS)
SCU_REG_PWR_MOD_FCS_PLL_RSTn | //Keep PLL active in FCS
SCU_REG_PWR_MOD_FCS, //enter FCS
SCU_REG_PWR_MOD_SELFR_CMD_OFF | SCU_REG_PWR_MOD_FCS_PLL2_RSTn |
SCU_REG_PWR_MOD_FCS_DLL_RSTn | SCU_REG_PWR_MOD_FCS_PLL_RSTn |
SCU_REG_PWR_MOD_FCS | SCU_REG_PWR_MOD_BUS_SPEED);
}
/************************************************************************
* Public API
************************************************************************/
void kdrv_power_sw_reset(void)
{
//err_msg("Set watchdog reset\n");
outw(WDT_FTWDT010_PA_BASE+0x0C, 0);
outw(WDT_FTWDT010_PA_BASE+0x04, 1000);
outw(WDT_FTWDT010_PA_BASE+0x0C, 0x03); // system reset
outw(WDT_FTWDT010_PA_BASE+0x08, 0x5AB9);
__WFI();
}
kdrv_status_t kdrv_power_set_domain(kdrv_power_domain_t domain, int enable)
{
uint32_t val, mask, vcc_ready, misc_pwr, wait_state;
switch (domain) {
case POWER_DOMAIN_DDRCK:
mask = SCU_REG_PWR_CTRL_PWRUP_CTRL_DOMAIN_DDRCK;
vcc_ready = SCU_REG_PWR_VCCSTS_PWR_READY_DOMAIN_DDRCK;
misc_pwr = SCU_EXTREG_MISC_PWR_RESET_RELEASE_DOMAIN_DDRCK;
break;
case POWER_DOMAIN_NPU:
mask = SCU_REG_PWR_CTRL_PWRUP_CTRL_DOMAIN_NPU;
vcc_ready = SCU_REG_PWR_VCCSTS_PWR_READY_DOMAIN_NPU;
misc_pwr = SCU_EXTREG_MISC_PWR_RESET_RELEASE_DOMAIN_NPU;
break;
case POWER_DOMAIN_DEFAULT:
mask = SCU_REG_PWR_CTRL_PWRUP_CTRL_DOMAIN_DEFAULT;
vcc_ready = SCU_REG_PWR_VCCSTS_PWR_READY_DOMAIN_DEFAULT;
misc_pwr = SCU_EXTREG_MISC_PWR_RESET_RELEASE_DOMAIN_DEFAULT;
break;
default:
return KDRV_STATUS_INVALID_PARAM;
}
val = enable? mask : 0;
val |= SCU_REG_PWR_CTRL_PWRUP_UPDATE;
mask |= SCU_REG_PWR_CTRL_PWRUP_UPDATE;
masked_outw(SCU_REG_PWR_CTRL, val, mask);
kdrv_delay_us(500);
/* Wait for VCC change */
wait_state = enable? vcc_ready : 0;
do {
val = inw(SCU_REG_PWR_VCCSTS);
} while((val & vcc_ready) != wait_state);
/* Wait for power reset change */
wait_state = enable? misc_pwr : 0;
do {
val = inw(SCU_EXTREG_MISC);
} while((val & misc_pwr) != wait_state);
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_power_softoff(kdrv_power_mode_t mode)
{
uint32_t val;
switch (mode) {
case POWER_MODE_DEEP_RETENTION:
val = PWR_CTRL_SOFTOFF_DEEP_RETENTION;
break;
case POWER_MODE_RTC:
val = PWR_CTRL_SOFTOFF_RTC_MODE;
break;
default:
return KDRV_STATUS_INVALID_PARAM;
}
masked_outw(SCU_REG_PWR_CTRL, val, PWR_CTRL_SOFTOFF_MASK);
SCU_REG_PWR_MOD_SET_SOFTOFF(1);
return KDRV_STATUS_OK;
}
kdrv_status_t kdrv_power_ops(kdrv_power_ops_t ops)
{
switch (ops) {
case POWER_OPS_FCS:
_power_mgr_ops_fcs();
break;
case POWER_OPS_CHANGE_BUS_SPEED:
break;
case POWER_OPS_PLL_UPDATE:
break;
case POWER_OPS_SLEEPING:
//stop cpu
//stop ddr
//send self-refresh command to ddr
//wait ack
break;
default:
return KDRV_STATUS_INVALID_PARAM;
}
return KDRV_STATUS_OK;
}