GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
ifneq ($(srctree),)
|
||||
KERNEL_DIR := $(srctree)
|
||||
SDK_DIR := $(shell cd $(KERNEL_DIR)/../../.. && /bin/pwd)
|
||||
else
|
||||
SDK_DIR := $(shell cd $(CURDIR)/../../../.. && /bin/pwd)
|
||||
endif
|
||||
|
||||
include $(SDK_DIR)/build/base.mk
|
||||
include $(SDK_DIR)/build/version.mk
|
||||
|
||||
MOD_NAME := xm_pm
|
||||
|
||||
SRCS := pmoc_init.c
|
||||
SRCS += temperature.c
|
||||
SRCS += drv_svb.c
|
||||
SRCS += drv_pmc.c
|
||||
|
||||
SDK_KER_CFLAGS += -I$(GMP_DIR)/include
|
||||
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/osal/include
|
||||
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/common/include
|
||||
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/common/task
|
||||
SDK_KER_CFLAGS += -I$(GMP_DIR)/drv/include
|
||||
SDK_KER_CFLAGS += -I$(GMP_DIR)/usr/include
|
||||
SDK_KER_CFLAGS += -I$(GMP_DIR)/usr/common/include
|
||||
|
||||
$(info SDK_KER_CFLAGS=$(SDK_KER_CFLAGS))
|
||||
$(info SRCS=$(SRCS))
|
||||
$(info SDK_DIR=$(SDK_DIR))
|
||||
|
||||
include $(SDK_DIR)/build/sdk_ko_rules.mk
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef H_DRV_PM_DDR_H
|
||||
#define H_DRV_PM_DDR_H
|
||||
|
||||
#define HASH_SIZE_PER_BYTE 32
|
||||
#define DDR_CALIB_SIZE 832
|
||||
struct lpds_param {
|
||||
uint8_t lpds_hash[HASH_SIZE_PER_BYTE];
|
||||
uint8_t ddr_hash[HASH_SIZE_PER_BYTE];
|
||||
uint32_t data_start;
|
||||
uint32_t data_size;
|
||||
uint32_t hash_flag;
|
||||
uint32_t str_flag;
|
||||
uint32_t resume_addr;
|
||||
uint32_t resume_addr_backup;
|
||||
uint8_t reserve0[24];
|
||||
uint8_t scrambling_key[16];
|
||||
uint8_t ddr_calib[DDR_CALIB_SIZE];
|
||||
uint32_t ddr_size;
|
||||
uint32_t hpm_state;
|
||||
uint32_t power_state;
|
||||
uint8_t reserve1[20];
|
||||
uint32_t ddr_suspend_crc;
|
||||
uint32_t ddr_resume_crc;
|
||||
};
|
||||
|
||||
struct ddr_calib_data {
|
||||
uint32_t calib_data_saved;
|
||||
|
||||
uint32_t gate_dqs0_result;
|
||||
uint32_t gate_dqs1_result;
|
||||
|
||||
uint32_t rx_dqs0_result;
|
||||
uint32_t rx_dqsb0_result;
|
||||
uint32_t rx_dqs1_result;
|
||||
uint32_t rx_dqsb1_result;
|
||||
|
||||
uint32_t rx_dm0_result;
|
||||
uint32_t rx_dm1_result;
|
||||
|
||||
uint32_t rx_dq_result[16];
|
||||
|
||||
uint32_t tx_dqs0_result;
|
||||
uint32_t tx_dqsb0_result;
|
||||
uint32_t tx_dqs1_result;
|
||||
uint32_t tx_dqsb1_result;
|
||||
|
||||
uint32_t tx_dm0_result;
|
||||
uint32_t tx_dm1_result;
|
||||
|
||||
uint32_t tx_dq_result[16];
|
||||
};
|
||||
|
||||
int pm_ddr_param_get(struct lpds_param *p_lpds_param);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,632 @@
|
||||
#include "pmoc_comm.h"
|
||||
#include "drv_pmc.h"
|
||||
#include <linux/rtc.h>
|
||||
#include "xmedia_errcode.h"
|
||||
#include "mmz.h"
|
||||
|
||||
extern int lotus_rtc_aov_read_time(struct device *dev, struct rtc_time *time, unsigned char *ms_count);
|
||||
extern int lotus_rtc_aov_set_alarm_time(struct device *dev, unsigned int alarm_time, unsigned char alarm_enable);
|
||||
extern int pm_set_aux_src(void __iomem *aux_src, unsigned long size);
|
||||
extern int lotus_rtc_aov_get_resume_time(struct device *dev, struct rtc_time *time, unsigned char *ms_count);
|
||||
extern int lotus_rtc_aov_get_suspend_time(struct device *dev, struct rtc_time *time, unsigned char *ms);
|
||||
extern int lotus_rtc_aov_get_current_time(struct device *dev, struct rtc_time *time, unsigned char *ms);
|
||||
|
||||
static xmedia_void *virt_pwr_base_addr = XMEDIA_NULL;
|
||||
#ifdef CONFIG_PM
|
||||
static xmedia_void *virt_aux_store_addr = XMEDIA_NULL;
|
||||
#endif
|
||||
struct mutex pmc_mutex;
|
||||
|
||||
xmedia_s32 lotus_pmc_init(xmedia_void)
|
||||
{
|
||||
virt_pwr_base_addr = osal_ioremap(PWR_BASE_ADDR, 0x40);
|
||||
if (virt_pwr_base_addr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "lotus_pmc_init ioremap err!\n");
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
mutex_init(&pmc_mutex);
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
xmedia_s32 lotus_pmc_set_aux(struct aux_mem *aux)
|
||||
{
|
||||
#ifdef CONFIG_PM
|
||||
if (virt_aux_store_addr != XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "%s aux is exist!\n", __func__);
|
||||
return XMEDIA_ERRCODE_EXIST;
|
||||
}
|
||||
|
||||
virt_aux_store_addr = mmz_map(aux->phy_addr, aux->size, 0);
|
||||
if (virt_aux_store_addr == NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "%s addr 0x%llx mmap error!\n", __func__, aux->phy_addr);
|
||||
return XMEDIA_ERRCODE_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
pm_set_aux_src(virt_aux_store_addr, aux->size);
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
#else
|
||||
return XMEDIA_ERRCODE_NOT_SUPPORT;
|
||||
#endif
|
||||
}
|
||||
|
||||
xmedia_void lotus_pmc_deinit(xmedia_void)
|
||||
{
|
||||
if (virt_pwr_base_addr != XMEDIA_NULL) {
|
||||
osal_iounmap(virt_pwr_base_addr);
|
||||
virt_pwr_base_addr = XMEDIA_NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
if (virt_aux_store_addr != XMEDIA_NULL) {
|
||||
mmz_unmap(virt_aux_store_addr);
|
||||
pm_set_aux_src(0, 0);
|
||||
virt_aux_store_addr = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
xmedia_s32 lotus_get_wakeup_type(lotus_pmc_wakeup_type *type)
|
||||
{
|
||||
xmedia_u32 status;
|
||||
xmedia_s32 ret = XMEDIA_SUCCESS;
|
||||
|
||||
if (virt_pwr_base_addr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "pmc not init err!\n");
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (type == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_wakeup_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_NULL_PTR;
|
||||
}
|
||||
|
||||
status = osal_readl(virt_pwr_base_addr + PMR_STATUS_OFFSET);
|
||||
status &= PWR_STATUS_WAKEUP_SOURCE;
|
||||
status >>= 2;
|
||||
switch (status) {
|
||||
case 1:
|
||||
*type = PMC_SRC_WAKEUP;
|
||||
break;
|
||||
case 4:
|
||||
*type = PMC_SRC_STARTUP;
|
||||
break;
|
||||
case 8:
|
||||
*type = PMC_SRC_BUTTON;
|
||||
break;
|
||||
case 16:
|
||||
*type = PMC_SRC_RTC;
|
||||
break;
|
||||
default:
|
||||
*type = PMC_SRC_MAX;
|
||||
ret = XMEDIA_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef PM_WAKEUP1_SUPPORT
|
||||
xmedia_s32 lotus_pm_get_wakeup_info(lotus_pm_wakeup_info *info)
|
||||
{
|
||||
xmedia_s32 ret = XMEDIA_SUCCESS;
|
||||
xmedia_u32 status;
|
||||
xmedia_u32 wakeup0_crtl, wakeup1_crtl;
|
||||
|
||||
ret = lotus_get_wakeup_type(&info->type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (info->type == PMC_SRC_WAKEUP) {
|
||||
|
||||
wakeup0_crtl = osal_readl(virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
wakeup1_crtl = osal_readl(virt_pwr_base_addr + PWR_WAKEUP1_CRTL_OFFSET);
|
||||
|
||||
/* wakeup0 and wakeup1 is both enable */
|
||||
if (((wakeup0_crtl & PWR_WAKEUPN_IOSHARE) == 0) && ((wakeup1_crtl & PWR_WAKEUPN_IOSHARE) == 0)) {
|
||||
status = osal_readl(virt_pwr_base_addr + PWR_STATUS_BACKUP_OFFSET);
|
||||
|
||||
if (status & WAKEUP_STATUS_GPIO0_MASK)
|
||||
info->detail = 0;
|
||||
else if (status & WAKEUP_STATUS_GPIO1_MASK)
|
||||
info->detail = 1;
|
||||
else {
|
||||
info->detail = 0;
|
||||
PM_TRACE(MODULE_DBG_ERR, "wakeup int happened, but do not find gpio wakeup status!\n");
|
||||
ret = XMEDIA_FAILURE;
|
||||
}
|
||||
|
||||
/* wakeup1 is only enabled */
|
||||
} else if ((wakeup1_crtl & PWR_WAKEUPN_IOSHARE) == 0) {
|
||||
info->detail = 1;
|
||||
} else if ((wakeup0_crtl & PWR_WAKEUPN_IOSHARE) == 0) {
|
||||
info->detail = 0;
|
||||
} else {
|
||||
info->detail = 0;
|
||||
PM_TRACE(MODULE_DBG_ERR, "wakeup int happened, but do not find gpio wakeup config!\n");
|
||||
ret = XMEDIA_ERRCODE_NOT_CONFIG;
|
||||
}
|
||||
} else {
|
||||
info->detail = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static xmedia_s32 lotus_config_wakeup_gpio(lotus_pmc_all_attr *attr)
|
||||
{
|
||||
xmedia_u32 value;
|
||||
|
||||
if (attr->wakeup_attr.wakeup_enable && attr->wakeup_ext_attr_arry[0].wakeup_enable) {
|
||||
if (attr->wakeup_attr.wakeup_polarity != PMC_PWR_HIGH_LEVEL || attr->wakeup_ext_attr_arry[0].wakeup_polarity != PMC_PWR_HIGH_LEVEL)
|
||||
return XMEDIA_ERRCODE_NOT_SUPPORT;
|
||||
}
|
||||
|
||||
if (!attr->wakeup_attr.wakeup_enable) {
|
||||
value = osal_readl(virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
value |= PWR_WAKEUPN_IOSHARE;
|
||||
osal_writel(value, virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
|
||||
} else if (attr->wakeup_attr.wakeup_polarity == PMC_PWR_HIGH_LEVEL ||
|
||||
attr->wakeup_attr.wakeup_polarity == PMC_PWR_RISING_EDGE) {
|
||||
value = osal_readl(virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
|
||||
value &= ~PWR_WAKEUPN_IOSHARE;
|
||||
/* pull down */
|
||||
value |= PWR_WAKEUP_PD;
|
||||
/* do not pull up */
|
||||
value &= ~PWR_WAKEUP_PU;
|
||||
|
||||
/* driver strength level2 */
|
||||
value &= ~PWR_WAKEUP_DS_MASK;
|
||||
value |= PWR_WAKEUP_DS_2;
|
||||
osal_writel(value, virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
} else {
|
||||
value = osal_readl(virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
|
||||
value &= ~PWR_WAKEUPN_IOSHARE;
|
||||
/* do not pull down */
|
||||
value &= ~PWR_WAKEUP_PD;
|
||||
/* pull up */
|
||||
value |= PWR_WAKEUP_PU;
|
||||
|
||||
/* driver strength level2 */
|
||||
value &= ~PWR_WAKEUP_DS_MASK;
|
||||
value |= PWR_WAKEUP_DS_2;
|
||||
osal_writel(value, virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
}
|
||||
|
||||
if (!attr->wakeup_ext_attr_arry[0].wakeup_enable) {
|
||||
value = osal_readl(virt_pwr_base_addr + PWR_WAKEUP1_CRTL_OFFSET);
|
||||
value |= PWR_WAKEUPN_IOSHARE;
|
||||
osal_writel(value, virt_pwr_base_addr + PWR_WAKEUP1_CRTL_OFFSET);
|
||||
|
||||
} else if (attr->wakeup_ext_attr_arry[0].wakeup_polarity == PMC_PWR_HIGH_LEVEL ||
|
||||
attr->wakeup_ext_attr_arry[0].wakeup_polarity == PMC_PWR_RISING_EDGE) {
|
||||
value = osal_readl(virt_pwr_base_addr + PWR_WAKEUP1_CRTL_OFFSET);
|
||||
|
||||
value &= ~PWR_WAKEUPN_IOSHARE;
|
||||
/* pull down */
|
||||
value |= PWR_WAKEUP_PD;
|
||||
/* do not pull up */
|
||||
value &= ~PWR_WAKEUP_PU;
|
||||
|
||||
/* driver strength level2 */
|
||||
value &= ~PWR_WAKEUP_DS_MASK;
|
||||
value |= PWR_WAKEUP_DS_2;
|
||||
osal_writel(value, virt_pwr_base_addr + PWR_WAKEUP1_CRTL_OFFSET);
|
||||
} else {
|
||||
value = osal_readl(virt_pwr_base_addr + PWR_WAKEUP1_CRTL_OFFSET);
|
||||
|
||||
value &= ~PWR_WAKEUPN_IOSHARE;
|
||||
/* do not pull down */
|
||||
value &= ~PWR_WAKEUP_PD;
|
||||
/* pull up */
|
||||
value |= PWR_WAKEUP_PU;
|
||||
|
||||
/* driver strength level2 */
|
||||
value &= ~PWR_WAKEUP_DS_MASK;
|
||||
value |= PWR_WAKEUP_DS_2;
|
||||
osal_writel(value, virt_pwr_base_addr + PWR_WAKEUP1_CRTL_OFFSET);
|
||||
}
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
#else
|
||||
static xmedia_s32 lotus_config_wakeup_gpio(lotus_pmc_all_attr *attr)
|
||||
{
|
||||
xmedia_u32 value;
|
||||
|
||||
if (!attr->wakeup_attr.wakeup_enable) {
|
||||
value = osal_readl(virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
value |= PWR_WAKEUPN_IOSHARE;
|
||||
osal_writel(value, virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
|
||||
} else if (attr->wakeup_attr.wakeup_polarity == PMC_PWR_HIGH_LEVEL ||
|
||||
attr->wakeup_attr.wakeup_polarity == PMC_PWR_RISING_EDGE) {
|
||||
value = osal_readl(virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
|
||||
value &= ~PWR_WAKEUPN_IOSHARE;
|
||||
/* pull down */
|
||||
value |= PWR_WAKEUP_PD;
|
||||
/* do not pull up */
|
||||
value &= ~PWR_WAKEUP_PU;
|
||||
|
||||
/* driver strength level2 */
|
||||
value &= ~PWR_WAKEUP_DS_MASK;
|
||||
value |= PWR_WAKEUP_DS_2;
|
||||
osal_writel(value, virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
} else {
|
||||
value = osal_readl(virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
|
||||
value &= ~PWR_WAKEUPN_IOSHARE;
|
||||
/* do not pull down */
|
||||
value &= ~PWR_WAKEUP_PD;
|
||||
/* pull up */
|
||||
value |= PWR_WAKEUP_PU;
|
||||
|
||||
/* driver strength level2 */
|
||||
value &= ~PWR_WAKEUP_DS_MASK;
|
||||
value |= PWR_WAKEUP_DS_2;
|
||||
osal_writel(value, virt_pwr_base_addr + PWR_WAKEUP_CRTL_OFFSET);
|
||||
}
|
||||
|
||||
value = osal_readl(virt_pwr_base_addr + PWR_WAKEUP1_CRTL_OFFSET);
|
||||
value |= PWR_WAKEUPN_IOSHARE;
|
||||
osal_writel(value, virt_pwr_base_addr + PWR_WAKEUP1_CRTL_OFFSET);
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
xmedia_s32 lotus_set_all_attr(lotus_pmc_all_attr *attr)
|
||||
{
|
||||
|
||||
xmedia_s32 ret = XMEDIA_SUCCESS;
|
||||
|
||||
if (virt_pwr_base_addr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "pmc not init err!\n");
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (attr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_wakeup_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_NULL_PTR;
|
||||
}
|
||||
|
||||
ret = lotus_config_wakeup_gpio(attr);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef PM_WAKEUP1_SUPPORT
|
||||
if ((!attr->wakeup_attr.wakeup_enable) && attr->wakeup_ext_attr_arry[0].wakeup_enable)
|
||||
ret = lotus_set_wakeup_attr(&(attr->wakeup_ext_attr_arry[0]));
|
||||
else
|
||||
ret = lotus_set_wakeup_attr(&(attr->wakeup_attr));
|
||||
#else
|
||||
ret = lotus_set_wakeup_attr(&(attr->wakeup_attr));
|
||||
#endif
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
ret = lotus_set_button_attr(&(attr->button_attr));
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
ret = lotus_set_rtc_attr(&(attr->rtc_attr));
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
xmedia_s32 lotus_get_all_attr(lotus_pmc_all_attr *attr)
|
||||
{
|
||||
xmedia_s32 ret = XMEDIA_SUCCESS;
|
||||
|
||||
if (virt_pwr_base_addr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "pmc not init err!\n");
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (attr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_wakeup_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_NULL_PTR;
|
||||
}
|
||||
|
||||
attr->startup_enable = 1;
|
||||
attr->button_enable = 1;
|
||||
|
||||
ret = lotus_get_wakeup_attr(&(attr->wakeup_attr));
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
ret = lotus_get_button_attr(&(attr->button_attr));
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
ret = lotus_get_rtc_attr(&(attr->rtc_attr));
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
xmedia_s32 lotus_set_wakeup_attr(lotus_pmc_wakeup_attr *attr)
|
||||
{
|
||||
xmedia_u32 status;
|
||||
|
||||
if (virt_pwr_base_addr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_Wakeup_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (attr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_Wakeup_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_NULL_PTR;
|
||||
}
|
||||
|
||||
mutex_lock(&pmc_mutex);
|
||||
status = osal_readl(virt_pwr_base_addr + PWR_CTRL0_OFFSET);
|
||||
status &= ~PWR_POWER_UNMASK;
|
||||
if (attr->wakeup_enable == 1) {
|
||||
osal_writel(status & ~PWR_WAKEUP_MASK, (virt_pwr_base_addr + PWR_CTRL0_OFFSET));
|
||||
} else {
|
||||
osal_writel(status | PWR_WAKEUP_MASK, (virt_pwr_base_addr + PWR_CTRL0_OFFSET));
|
||||
}
|
||||
|
||||
if (attr->wakeup_polarity < PMC_PWR_MAX) {
|
||||
status = osal_readl(virt_pwr_base_addr + PWR_CTRL0_OFFSET);
|
||||
status &= ~PWR_WAKEUP_POLARITY;
|
||||
status |= (attr->wakeup_polarity << 3);
|
||||
osal_writel(status, (virt_pwr_base_addr + PWR_CTRL0_OFFSET));
|
||||
} else {
|
||||
mutex_unlock(&pmc_mutex);
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_Wakeup_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_INVALID_PARAM;
|
||||
}
|
||||
|
||||
mutex_unlock(&pmc_mutex);
|
||||
PM_TRACE(MODULE_DBG_INFO, "set_wakeup_attr success!\n");
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
xmedia_s32 lotus_get_wakeup_attr(lotus_pmc_wakeup_attr *attr)
|
||||
{
|
||||
xmedia_u32 status;
|
||||
|
||||
if (virt_pwr_base_addr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "pmc not init err!\n");
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (attr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "get_wakeup_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_NULL_PTR;
|
||||
}
|
||||
|
||||
status = osal_readl(virt_pwr_base_addr + PWR_CTRL0_OFFSET);
|
||||
status &=~ PWR_POWER_UNMASK;
|
||||
|
||||
attr->wakeup_enable = !((status & PWR_WAKEUP_MASK) >> 6);
|
||||
attr->wakeup_polarity = (status & PWR_WAKEUP_POLARITY) >> 3;
|
||||
|
||||
PM_TRACE(MODULE_DBG_INFO, "get_wakeup_attr success!\n");
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
xmedia_s32 lotus_set_button_attr(lotus_pmc_button_attr *attr)
|
||||
{
|
||||
xmedia_u32 status;
|
||||
|
||||
if (virt_pwr_base_addr ==XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_button_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (attr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_button_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_NULL_PTR;
|
||||
}
|
||||
|
||||
mutex_lock(&pmc_mutex);
|
||||
status = osal_readl(virt_pwr_base_addr + PWR_CTRL0_OFFSET);
|
||||
status &=~ PWR_POWER_UNMASK;
|
||||
if (attr->button_adj_enable == 1) {
|
||||
osal_writel(status &~ PWR_BUTTON_ADJ_MASK, (virt_pwr_base_addr + PWR_CTRL0_OFFSET));
|
||||
if (attr->button_adj_time <= PWR_BUTTON_ADJ_TIME_MAX) {
|
||||
status = osal_readl(virt_pwr_base_addr + PWR_CTRL0_OFFSET);
|
||||
status &=~ PWR_POWER_UNMASK;
|
||||
status &=~ PWR_BUTTON_ADJ_TIME_MASK;
|
||||
status |= (attr->button_adj_time << PWR_BUTTON_ADJ_TIME_SHIFT);
|
||||
osal_writel(status, (virt_pwr_base_addr + PWR_CTRL0_OFFSET));
|
||||
} else {
|
||||
mutex_unlock(&pmc_mutex);
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_button_adjust_time parameter err!\n");
|
||||
return XMEDIA_ERRCODE_INVALID_PARAM;
|
||||
}
|
||||
} else {
|
||||
osal_writel(status | PWR_BUTTON_ADJ_MASK, (virt_pwr_base_addr + PWR_CTRL0_OFFSET));
|
||||
}
|
||||
|
||||
mutex_unlock(&pmc_mutex);
|
||||
PM_TRACE(MODULE_DBG_INFO, "set_button_adjust_time success!\n");
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
xmedia_s32 lotus_get_button_attr(lotus_pmc_button_attr *attr)
|
||||
{
|
||||
xmedia_u32 status;
|
||||
|
||||
if (virt_pwr_base_addr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "pmc not init err!\n");
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (attr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "get_button_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_NULL_PTR;
|
||||
}
|
||||
|
||||
status = osal_readl(virt_pwr_base_addr + PWR_CTRL0_OFFSET);
|
||||
status &=~ PWR_POWER_UNMASK;
|
||||
|
||||
attr->button_adj_enable = !((status & PWR_BUTTON_ADJ_MASK) >> PWR_BUTTON_ADJ_MASK_SHIFT);
|
||||
attr->button_adj_time = (status & PWR_BUTTON_ADJ_TIME_MASK) >> PWR_BUTTON_ADJ_TIME_SHIFT;
|
||||
|
||||
PM_TRACE(MODULE_DBG_INFO, "get_button_adjust_time success!\n");
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
xmedia_s32 lotus_set_rtc_attr(lotus_pmc_rtc_attr *attr)
|
||||
{
|
||||
xmedia_u32 status;
|
||||
struct rtc_device *dev;
|
||||
struct rtc_wkalrm alarm = {0};
|
||||
xmedia_u32 ret;
|
||||
|
||||
if (virt_pwr_base_addr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "pmc not init err!\n");
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (attr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_wakeup_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_NULL_PTR;
|
||||
}
|
||||
|
||||
status = osal_readl(virt_pwr_base_addr + PWR_CTRL0_OFFSET);
|
||||
status &=~ PWR_POWER_UNMASK;
|
||||
|
||||
if (attr->rtc_enable == 1) {
|
||||
osal_writel(status & ~PWR_RTC_MASK, (virt_pwr_base_addr + PWR_CTRL0_OFFSET));
|
||||
|
||||
dev = rtc_class_open("rtc0");
|
||||
if (dev == XMEDIA_NULL) {
|
||||
goto rtc_failure;
|
||||
}
|
||||
ret = rtc_read_alarm(dev, &alarm);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
goto rtc_failure;
|
||||
}
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "rtc_read_alarm start: %d-%d-%d-%d-%d-%d, %d-%d-%d\n", alarm.time.tm_year, \
|
||||
alarm.time.tm_mon, alarm.time.tm_mday, alarm.time.tm_hour, alarm.time.tm_min, alarm.time.tm_sec, alarm.time.tm_year, alarm.time.tm_yday, alarm.time.tm_isdst);
|
||||
|
||||
lotus_rtc_aov_set_alarm_time(dev->dev.parent, attr->rtc_timeout, 1);
|
||||
rtc_class_close(dev);
|
||||
} else {
|
||||
osal_writel(status | PWR_RTC_MASK, (virt_pwr_base_addr + PWR_CTRL0_OFFSET));
|
||||
}
|
||||
PM_TRACE(MODULE_DBG_INFO, "set_rtc_attr success!\n");
|
||||
return XMEDIA_SUCCESS;
|
||||
|
||||
rtc_failure:
|
||||
PM_TRACE(MODULE_DBG_ERR, "set rtc timeout failure!\n");
|
||||
return XMEDIA_FAILURE;
|
||||
}
|
||||
|
||||
xmedia_s32 lotus_get_rtc_attr(lotus_pmc_rtc_attr *attr)
|
||||
{
|
||||
xmedia_u32 status;
|
||||
|
||||
if (virt_pwr_base_addr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "pmc not init err!\n");
|
||||
return XMEDIA_ERRCODE_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
if (attr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "set_wakeup_attr parameter err!\n");
|
||||
return XMEDIA_ERRCODE_NULL_PTR;
|
||||
}
|
||||
|
||||
status = osal_readl(virt_pwr_base_addr + PWR_CTRL0_OFFSET);
|
||||
status &=~ PWR_POWER_UNMASK;
|
||||
|
||||
attr->rtc_enable = !((status & PWR_RTC_MASK) >> 5);;
|
||||
|
||||
attr->rtc_timeout = 0;
|
||||
|
||||
PM_TRACE(MODULE_DBG_INFO, "get_rtc_attr success!\n");
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
xmedia_s32 lotus_pm_get_rtc_info(lotus_pm_rtc_info *info)
|
||||
{
|
||||
struct rtc_device *dev;
|
||||
struct rtc_time linuxTime = {0};
|
||||
unsigned char ms_count;
|
||||
int ret = XMEDIA_SUCCESS;
|
||||
time64_t seconds = 0;
|
||||
|
||||
dev = rtc_class_open("rtc0");
|
||||
if (dev == XMEDIA_NULL) {
|
||||
return XMEDIA_ERRCODE_OPEN_FAILED;
|
||||
}
|
||||
|
||||
ret = lotus_rtc_aov_get_resume_time(dev->dev.parent, &linuxTime, &ms_count);
|
||||
if (ret != 0) {
|
||||
PM_TRACE(MODULE_DBG_INFO, "rtc get resume time fail: 0x%X\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
seconds = rtc_tm_to_time64(&linuxTime);
|
||||
|
||||
info->rtc_delta_time = seconds * 1000 + ms_count * 10;
|
||||
|
||||
PM_TRACE(MODULE_DBG_INFO, "get rtc resume time: %d-%d-%d %d:%d:%d.%d \n", linuxTime.tm_year, linuxTime.tm_mon, linuxTime.tm_mday, linuxTime.tm_hour, linuxTime.tm_min, linuxTime.tm_sec, ms_count * 10);
|
||||
|
||||
ret = lotus_rtc_aov_get_suspend_time(dev->dev.parent, &linuxTime, &ms_count);
|
||||
if (ret != 0) {
|
||||
PM_TRACE(MODULE_DBG_INFO, "rtc get resume time fail: 0x%X\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
seconds = rtc_tm_to_time64(&linuxTime);
|
||||
|
||||
info->rtc_last_suspend_time = seconds * 1000 + ms_count * 10;
|
||||
|
||||
PM_TRACE(MODULE_DBG_INFO, "get rtc suspend time: %d-%d-%d %d:%d:%d.%d \n", linuxTime.tm_year, linuxTime.tm_mon, linuxTime.tm_mday, linuxTime.tm_hour, linuxTime.tm_min, linuxTime.tm_sec, ms_count * 10);
|
||||
|
||||
ret = lotus_rtc_aov_get_current_time(dev->dev.parent, &linuxTime, &ms_count);
|
||||
|
||||
if (ret != 0) {
|
||||
PM_TRACE(MODULE_DBG_INFO, "rtc get resume time fail: 0x%X\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
seconds = rtc_tm_to_time64(&linuxTime);
|
||||
|
||||
info->rtc_current_time = seconds * 1000 + ms_count * 10;
|
||||
|
||||
PM_TRACE(MODULE_DBG_INFO, "get rtc current time: %d-%d-%d %d:%d:%d.%d \n", linuxTime.tm_year, linuxTime.tm_mon, linuxTime.tm_mday, linuxTime.tm_hour, linuxTime.tm_min, linuxTime.tm_sec, ms_count * 10);
|
||||
out:
|
||||
if (dev)
|
||||
rtc_class_close(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
xmedia_void lotus_get_rtc_timer(xmedia_void)
|
||||
{
|
||||
struct rtc_device *dev;
|
||||
struct rtc_time linuxTime = {0};
|
||||
unsigned char ms_count;
|
||||
|
||||
dev = rtc_class_open("rtc0");
|
||||
if (dev == XMEDIA_NULL) {
|
||||
return;
|
||||
}
|
||||
lotus_rtc_aov_read_time(dev->dev.parent, &linuxTime, &ms_count);
|
||||
rtc_class_close(dev);
|
||||
osal_printk("get rtc timer:%d:%d:%d \n", linuxTime.tm_min, linuxTime.tm_sec, ms_count);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
#ifndef __DRV_PM_PMC_H__
|
||||
#define __DRV_PM_PMC_H__
|
||||
|
||||
#include "xmedia_type.h"
|
||||
|
||||
//#define PM_WAKEUP1_SUPPORT
|
||||
|
||||
#define WAKEUP_EXT_GPIO_NUM 1
|
||||
|
||||
#define PWR_BASE_ADDR 0x120f0000
|
||||
#define PMR_STATUS_OFFSET 0x4
|
||||
#define PWR_STATUS_WAKEUP_SOURCE GENMASK(6, 2)
|
||||
#define PWR_PD_SEL_OFFSET 0x8
|
||||
#define PWR_CTRL0_OFFSET 0x10
|
||||
#define PWR_POWER_UNMASK (BIT(1) | BIT(0))
|
||||
#define PWR_WAKEUP_POLARITY (BIT(3) | BIT(4))
|
||||
#define PWR_RTC_MASK BIT(5)
|
||||
#define PWR_WAKEUP_MASK BIT(6)
|
||||
#define PWR_STARTUP_MASK BIT(16)
|
||||
#define PWR_BUTTON_ADJ_MASK BIT(28)
|
||||
#define PWR_BUTTON_ADJ_MASK_SHIFT 28
|
||||
#define PWR_BUTTON_ADJ_TIME_MASK GENMASK(27,20)
|
||||
#define PWR_BUTTON_ADJ_TIME_SHIFT 20
|
||||
#define PWR_CTRL1_OFFSET 0x14
|
||||
#define PWM_BUTTON_CTRL_OFFSET 0x18
|
||||
#define PWR_STARTUP_CRTL_OFFSET 0x20
|
||||
#define PWR_RSTN_CRTL_OFFSET 0x24
|
||||
#define PWR_SEQ_CRTL_OFFSET 0x28
|
||||
#define PWR_WAKEUP_CRTL_OFFSET 0x30
|
||||
#define PWR_WAKEUPN_IOSHARE BIT(8)
|
||||
#define PWR_WAKEUP_PD BIT(3)
|
||||
#define PWR_WAKEUP_PU BIT(2)
|
||||
#define PWR_WAKEUP_DS_MASK (0x3)
|
||||
#define PWR_WAKEUP_DS_1 0x0
|
||||
#define PWR_WAKEUP_DS_2 0x1
|
||||
#define PWR_WAKEUP_DS_3 0x2
|
||||
#define PWR_WAKEUP_DS_4 0x3
|
||||
#define PWR_EN_CRTL_OFFSET 0x34
|
||||
#define PWR_WAKEUP1_CRTL_OFFSET 0x38
|
||||
|
||||
#define PWR_BUTTON_ADJ_TIME_MAX 255 //<=25.5s
|
||||
|
||||
/*
|
||||
* 0x120f0050 在待机的时候保存linux唤醒入口地址,
|
||||
* 跳转内核之前保存唤醒状态,
|
||||
* 刚进入aux读取PMR_STATUS_OFFSET到aux的中保存
|
||||
*/
|
||||
#define PWR_STATUS_BACKUP_OFFSET 0x50
|
||||
#define WAKEUP_STATUS_GPIO0_MASK 0x100
|
||||
#define WAKEUP_STATUS_GPIO1_MASK 0x400
|
||||
|
||||
typedef enum {
|
||||
PMC_SRC_WAKEUP = 0,
|
||||
PMC_SRC_STARTUP,
|
||||
PMC_SRC_BUTTON,
|
||||
PMC_SRC_RTC,
|
||||
PMC_SRC_MAX,
|
||||
} lotus_pmc_wakeup_type;
|
||||
|
||||
#ifdef PM_WAKEUP1_SUPPORT
|
||||
/*
|
||||
* 当type为PM_WKMODE_WAKEUP(gpio唤醒时),detail为唤醒gpio号,唤醒gpio号与xmedia_pm_attr中的唤醒gpio号对应
|
||||
* 当type为PM_WKMODE_STARTUP, detail无意义
|
||||
* 当type为PM_WKMODE_BUTTON,detail无意义
|
||||
* 当type为PM_WKMODE_RTC,detail无意义
|
||||
*/
|
||||
typedef struct {
|
||||
lotus_pmc_wakeup_type type;
|
||||
xmedia_u32 detail;
|
||||
} lotus_pm_wakeup_info;
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
PMC_PWR_RISING_EDGE = 0,
|
||||
PMC_PWR_FALLING_EDGE,
|
||||
PMC_PWR_HIGH_LEVEL,
|
||||
PMC_PWR_LOW_LEVEL,
|
||||
PMC_PWR_MAX,
|
||||
} lotus_pmc_wakeup_polarity;
|
||||
|
||||
typedef struct {
|
||||
xmedia_bool rtc_enable; // 1:表示使能
|
||||
xmedia_u32 rtc_timeout; // 单位为10ms
|
||||
} lotus_pmc_rtc_attr;
|
||||
|
||||
typedef struct {
|
||||
xmedia_bool wakeup_enable; // 1:表示使能
|
||||
lotus_pmc_wakeup_polarity wakeup_polarity; //上升沿、下降沿、高电平和低电平触发
|
||||
} lotus_pmc_wakeup_attr;
|
||||
|
||||
typedef struct {
|
||||
xmedia_bool button_adj_enable; //1:表示使能
|
||||
xmedia_u32 button_adj_time; //button触发时间,精度100ms
|
||||
}lotus_pmc_button_attr;
|
||||
|
||||
/*
|
||||
* wakeup_attr: 对应唤醒gpio0的配置
|
||||
* wakeup_ext_attr_arry[0] 对应唤醒gpio1开始的其他唤醒gpio的配置
|
||||
* 如果唤醒gpio0和唤醒gpio1同时使用,只支持高电平唤醒,同时高电平持续时间必须大于xxms
|
||||
*/
|
||||
typedef struct {
|
||||
lotus_pmc_wakeup_attr wakeup_attr;
|
||||
xmedia_bool startup_enable;
|
||||
xmedia_bool button_enable;
|
||||
lotus_pmc_button_attr button_attr;
|
||||
lotus_pmc_rtc_attr rtc_attr;
|
||||
#ifdef PM_WAKEUP1_SUPPORT
|
||||
lotus_pmc_wakeup_attr wakeup_ext_attr_arry[WAKEUP_EXT_GPIO_NUM];
|
||||
#endif
|
||||
} lotus_pmc_all_attr;
|
||||
|
||||
typedef struct {
|
||||
xmedia_u64 rtc_delta_time; // 单位为1ms
|
||||
xmedia_u64 rtc_current_time;
|
||||
xmedia_u64 rtc_last_suspend_time;
|
||||
} lotus_pm_rtc_info;
|
||||
|
||||
typedef enum {
|
||||
CMD_PM_INIT = 0,
|
||||
CMD_PM_DEINIT,
|
||||
CMD_PM_SET_ALL_ATTR,
|
||||
CMD_PM_GET_ALL_ATTR,
|
||||
CMD_PM_GET_RTC_ATTR,
|
||||
CMD_PM_SET_RTC_ATTR,
|
||||
CMD_PM_GET_WK_ATTR,
|
||||
CMD_PM_SET_WK_ATTR,
|
||||
CMD_PM_GET_WK_SOURCE,
|
||||
CMD_PM_SET_AUX,
|
||||
CMD_PM_GET_DDR_PARAM,
|
||||
CMD_PM_GET_RTC_INFO,
|
||||
#ifdef PM_WAKEUP1_SUPPORT
|
||||
CMD_PM_GET_WK_INFO,
|
||||
#endif
|
||||
CMD_PM_GET_RTC_TIMER,
|
||||
CMD_PM_END = 0xFFFF,
|
||||
} pm_ioctl_cmd;
|
||||
|
||||
struct aux_mem {
|
||||
xmedia_u64 phy_addr;
|
||||
xmedia_u32 size;
|
||||
};
|
||||
|
||||
xmedia_s32 lotus_pmc_init(xmedia_void);
|
||||
xmedia_void lotus_pmc_deinit(xmedia_void);
|
||||
xmedia_s32 lotus_get_wakeup_type(lotus_pmc_wakeup_type *type);
|
||||
#ifdef PM_WAKEUP1_SUPPORT
|
||||
xmedia_s32 lotus_pm_get_wakeup_info(lotus_pm_wakeup_info *info);
|
||||
#endif
|
||||
xmedia_s32 lotus_set_all_attr(lotus_pmc_all_attr *attr);
|
||||
xmedia_s32 lotus_get_all_attr(lotus_pmc_all_attr *attr);
|
||||
xmedia_s32 lotus_set_wakeup_attr(lotus_pmc_wakeup_attr *attr);
|
||||
xmedia_s32 lotus_get_wakeup_attr(lotus_pmc_wakeup_attr *attr);
|
||||
xmedia_s32 lotus_set_button_attr(lotus_pmc_button_attr *attr);
|
||||
xmedia_s32 lotus_get_button_attr(lotus_pmc_button_attr *attr);
|
||||
xmedia_s32 lotus_set_rtc_attr(lotus_pmc_rtc_attr *attr);
|
||||
xmedia_s32 lotus_get_rtc_attr(lotus_pmc_rtc_attr *attr);
|
||||
xmedia_void lotus_get_rtc_timer(xmedia_void);
|
||||
xmedia_s32 lotus_pmc_set_aux(struct aux_mem *aux);
|
||||
xmedia_s32 lotus_pm_get_rtc_info(lotus_pm_rtc_info *info);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "pmoc_comm.h"
|
||||
|
||||
#define duty_formula(val) ((unsigned int)((1099 - (val)) * 460) >> 10)
|
||||
|
||||
#define SVB_PWM_CTRL0 0x12028300
|
||||
#define SVB_PWM_CTRL1 0x04
|
||||
#define SVB_VER_REG 0x12020168
|
||||
#define HPM_ADDR 0x1202015c
|
||||
|
||||
static xmedia_void *g_svb_pwm = XMEDIA_NULL;
|
||||
static xmedia_void *g_svb_ver_addr = XMEDIA_NULL;
|
||||
static xmedia_void *g_chip_hpm = XMEDIA_NULL;
|
||||
static xmedia_s32 g_core_volt = 0;
|
||||
static xmedia_s32 g_temp_volt = 0;
|
||||
|
||||
bool is_svb_enabled(void)
|
||||
{
|
||||
xmedia_u32 svb_disable = (osal_readl(g_svb_ver_addr) >> 4) & 0x1;
|
||||
|
||||
if (svb_disable) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
xmedia_u32 get_core_volt(xmedia_void)
|
||||
{
|
||||
return (g_core_volt + g_temp_volt);
|
||||
}
|
||||
|
||||
xmedia_u32 get_chip_hpm(xmedia_void)
|
||||
{
|
||||
return ((osal_readl(g_chip_hpm) >> 16) & 0x1FF);
|
||||
}
|
||||
|
||||
static xmedia_s32 get_volt_to_svb(xmedia_void)
|
||||
{
|
||||
return (osal_readl(g_chip_hpm) & 0xffff);
|
||||
}
|
||||
|
||||
static xmedia_void set_core_pwm(xmedia_s32 volt)
|
||||
{
|
||||
xmedia_u32 duty;
|
||||
|
||||
/* svb_pwm volt code */
|
||||
duty = duty_formula(volt);
|
||||
|
||||
duty = ((duty << 16) & 0xFFFF0000) | 0x0c70;
|
||||
osal_writel(duty, g_svb_pwm);
|
||||
osal_writel(osal_readl(g_svb_pwm + SVB_PWM_CTRL1) | 0x1, g_svb_pwm + SVB_PWM_CTRL1);
|
||||
osal_writel(osal_readl(g_svb_pwm) | 0x1, g_svb_pwm);
|
||||
}
|
||||
|
||||
xmedia_void set_core_comp(xmedia_s32 volt)
|
||||
{
|
||||
g_temp_volt = volt;
|
||||
}
|
||||
|
||||
xmedia_void svb_control_apply(xmedia_void)
|
||||
{
|
||||
xmedia_s32 volt;
|
||||
|
||||
volt = g_core_volt + g_temp_volt;
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "volt = %d s_volt = %d temp_volt = %d\n", volt, g_core_volt, g_temp_volt);
|
||||
if (is_svb_enabled()) {
|
||||
set_core_pwm(volt);
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "svb pwm ctrl0 = 0x%x, ctrl1 = 0x%x\n", osal_readl(g_svb_pwm), osal_readl(g_svb_pwm + SVB_PWM_CTRL1));
|
||||
}
|
||||
}
|
||||
|
||||
xmedia_s32 drv_svb_init(xmedia_void)
|
||||
{
|
||||
g_svb_pwm = (void *)osal_ioremap(SVB_PWM_CTRL0, 0x8);
|
||||
if (g_svb_pwm == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "remap pwm reg fail\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
g_svb_ver_addr = (void *)osal_ioremap(SVB_VER_REG, 0x4);
|
||||
if (g_svb_ver_addr == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "remap svb ver fail\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
g_chip_hpm = (void *)osal_ioremap(HPM_ADDR, 0x4);
|
||||
if (g_chip_hpm == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "remap hpm reg fail\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
g_core_volt = get_volt_to_svb();
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
|
||||
err3:
|
||||
osal_iounmap(g_svb_ver_addr);
|
||||
g_svb_ver_addr = XMEDIA_NULL;
|
||||
err2:
|
||||
osal_iounmap(g_svb_pwm);
|
||||
g_svb_pwm = XMEDIA_NULL;
|
||||
err1:
|
||||
return XMEDIA_FAILURE;
|
||||
}
|
||||
|
||||
xmedia_void drv_svb_deinit(xmedia_void)
|
||||
{
|
||||
osal_iounmap(g_chip_hpm);
|
||||
g_chip_hpm = XMEDIA_NULL;
|
||||
|
||||
osal_iounmap(g_svb_ver_addr);
|
||||
g_svb_ver_addr = XMEDIA_NULL;
|
||||
|
||||
osal_iounmap(g_svb_pwm);
|
||||
g_svb_pwm = XMEDIA_NULL;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef __DRV_PM_SVB_H__
|
||||
#define __DRV_PM_SVB_H__
|
||||
|
||||
#include "xmedia_type.h"
|
||||
|
||||
xmedia_void set_core_comp(xmedia_s32 volt);
|
||||
xmedia_void svb_control_apply(xmedia_void);
|
||||
xmedia_s32 drv_svb_init(xmedia_void);
|
||||
xmedia_void drv_svb_deinit(xmedia_void);
|
||||
xmedia_u32 get_chip_hpm(xmedia_void);
|
||||
xmedia_u32 get_core_volt(xmedia_void);
|
||||
bool is_svb_enabled(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef __DRV_PM_COMM_H__
|
||||
#define __DRV_PM_COMM_H__
|
||||
|
||||
#include <linux/lotus/soc_chip.h>
|
||||
#include "common.h"
|
||||
#include "xmedia_debug.h"
|
||||
#include "xmedia_type.h"
|
||||
#include "osal.h"
|
||||
|
||||
#define PM_TRACE(level, fmt, ...) \
|
||||
do { \
|
||||
MODULE_TRACE(level, MOD_ID_PM, "[Func]:%s [Line]:%d [Info]:" fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,323 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/freezer.h>
|
||||
#include "drv_dev_defines.h"
|
||||
#include "version.h"
|
||||
#include "pmoc_comm.h"
|
||||
#include "temperature.h"
|
||||
#include "drv_svb.h"
|
||||
#include "drv_pmc.h"
|
||||
#include "drv_pm_ddr.h"
|
||||
#include "xmedia_errcode.h"
|
||||
|
||||
#define DEFAULT_THREAD_TIME 100
|
||||
|
||||
#define XMEDIA_PM_INIT _IO('n', CMD_PM_INIT)
|
||||
#define XMEDIA_PM_DEINIT _IO('n', CMD_PM_DEINIT)
|
||||
#define XMEDIA_PM_GET_WAKEUP_SOURCE _IOWR('n', CMD_PM_GET_WK_SOURCE, lotus_pmc_wakeup_type)
|
||||
#define XMEDIA_PM_GET_ATTR _IOWR('n', CMD_PM_GET_ALL_ATTR, lotus_pmc_all_attr)
|
||||
#define XMEDIA_PM_SET_ATTR _IOWR('n', CMD_PM_SET_ALL_ATTR, lotus_pmc_all_attr)
|
||||
#define XMEDIA_PM_GET_RTC_ATTR _IOWR('n', CMD_PM_GET_RTC_ATTR, lotus_pmc_rtc_attr)
|
||||
#define XMEDIA_PM_SET_RTC_ATTR _IOWR('n', CMD_PM_SET_RTC_ATTR, lotus_pmc_rtc_attr)
|
||||
#define XMEDIA_PM_GET_WK_ATTR _IOWR('n', CMD_PM_GET_WK_ATTR, lotus_pmc_wakeup_attr)
|
||||
#define XMEDIA_PM_SET_WK_ATTR _IOWR('n', CMD_PM_SET_WK_ATTR, lotus_pmc_wakeup_attr)
|
||||
#define XMEDIA_PM_GET_RTC_TIMER _IO('n', CMD_PM_GET_RTC_TIMER)
|
||||
#define XMEDIA_PM_SET_AUX _IOWR('n', CMD_PM_SET_AUX, struct aux_mem)
|
||||
#define XMEDIA_PM_GET_DDR_PARAM _IOR('n', CMD_PM_GET_DDR_PARAM, struct lpds_param)
|
||||
#ifdef PM_WAKEUP1_SUPPORT
|
||||
#define XMEDIA_PM_GET_WK_INFO _IOWR('n', CMD_PM_GET_WK_INFO, lotus_pm_wakeup_info)
|
||||
#endif
|
||||
#define XMEDIA_PM_GET_RTC_INFO _IOR('n', CMD_PM_GET_RTC_INFO, lotus_pm_rtc_info)
|
||||
|
||||
static osal_dev_t *g_pm_dev = XMEDIA_NULL;
|
||||
|
||||
static osal_task_t *g_ctrl_thread = XMEDIA_NULL;
|
||||
|
||||
xmedia_bool g_pm_resume = false;
|
||||
|
||||
xmedia_s32 pm_ctrl_thread(xmedia_void *data)
|
||||
{
|
||||
xmedia_s32 ret;
|
||||
bool was_frozen;
|
||||
|
||||
set_freezable();
|
||||
|
||||
ret = drv_svb_init();
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "svb init fail\n");
|
||||
return XMEDIA_FAILURE;
|
||||
}
|
||||
|
||||
if (!is_svb_enabled())
|
||||
return XMEDIA_SUCCESS;
|
||||
|
||||
temp_init();
|
||||
|
||||
while (!kthread_freezable_should_stop(&was_frozen)) {
|
||||
if (was_frozen || g_pm_resume) {
|
||||
pr_info("T Ctrl Thread resumed after freeze\n");
|
||||
temp_init();
|
||||
g_pm_resume = false;
|
||||
}
|
||||
|
||||
freezable_schedule_timeout_interruptible(msecs_to_jiffies(DEFAULT_THREAD_TIME));
|
||||
|
||||
temp_control_thread();
|
||||
}
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
static int drv_pm_proc_show(struct osal_proc_dir_entry *s)
|
||||
{
|
||||
xmedia_char version_info[128] = {0};
|
||||
|
||||
VERSION_FORMAT(version_info, "Pm", "V1.0", "");
|
||||
osal_seq_printf(s, "\n%s\n", version_info);
|
||||
osal_seq_printf(s, "Temperature : %d\n", get_chip_temperature());
|
||||
osal_seq_printf(s, "CpuFreq(khz) : %d\n", get_cpu_freq() / 1000);
|
||||
osal_seq_printf(s, "HPM : %u\n", get_chip_hpm());
|
||||
osal_seq_printf(s, "CoreVolt(mv) : %u\n", get_core_volt());
|
||||
return 0;
|
||||
}
|
||||
|
||||
xmedia_s32 drv_pm_open(xmedia_void *private_data)
|
||||
{
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
xmedia_s32 drv_pm_close(xmedia_void *private_data)
|
||||
{
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
static long drv_pm_ioctl(unsigned int cmd, unsigned long arg, xmedia_void *private_data)
|
||||
{
|
||||
xmedia_s32 ret = XMEDIA_SUCCESS;
|
||||
lotus_pmc_wakeup_type *type;
|
||||
lotus_pmc_all_attr *param;
|
||||
lotus_pmc_rtc_attr *rtc_attr;
|
||||
lotus_pmc_wakeup_attr *wk_attr;
|
||||
struct aux_mem *aux;
|
||||
#ifdef PM_WAKEUP1_SUPPORT
|
||||
lotus_pm_wakeup_info *wakeup_info;
|
||||
#endif
|
||||
lotus_pm_rtc_info *rtc_info;
|
||||
|
||||
switch (cmd) {
|
||||
case XMEDIA_PM_INIT:
|
||||
ret = lotus_pmc_init();
|
||||
break;
|
||||
case XMEDIA_PM_DEINIT:
|
||||
lotus_pmc_deinit();
|
||||
break;
|
||||
case XMEDIA_PM_SET_ATTR:
|
||||
param = (lotus_pmc_all_attr *)arg;
|
||||
ret = lotus_set_all_attr(param);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "lotus_set_wakeup_source failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case XMEDIA_PM_GET_ATTR:
|
||||
param = (lotus_pmc_all_attr *)arg;
|
||||
ret = lotus_get_all_attr(param);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "lotus_get_wakeup_source failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case XMEDIA_PM_GET_RTC_ATTR:
|
||||
rtc_attr = (lotus_pmc_rtc_attr *)arg;
|
||||
ret = lotus_get_rtc_attr(rtc_attr);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "lotus_get_rtc_attr failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case XMEDIA_PM_SET_RTC_ATTR:
|
||||
rtc_attr = (lotus_pmc_rtc_attr *)arg;
|
||||
ret = lotus_set_rtc_attr(rtc_attr);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "lotus_set_rtc_attr failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case XMEDIA_PM_GET_WK_ATTR:
|
||||
wk_attr = (lotus_pmc_wakeup_attr *)arg;
|
||||
ret = lotus_get_wakeup_attr(wk_attr);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "lotus_set_wakeup_attr failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case XMEDIA_PM_SET_WK_ATTR:
|
||||
wk_attr = (lotus_pmc_wakeup_attr *)arg;
|
||||
ret = lotus_set_wakeup_attr(wk_attr);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "lotus_set_wakeup_attr failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case XMEDIA_PM_GET_WAKEUP_SOURCE:
|
||||
type = (lotus_pmc_wakeup_type *)arg;
|
||||
ret = lotus_get_wakeup_type(type);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "lotus_get_wakeup_type failed:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case XMEDIA_PM_GET_RTC_TIMER:
|
||||
lotus_get_rtc_timer();
|
||||
return XMEDIA_SUCCESS;
|
||||
case XMEDIA_PM_SET_AUX:
|
||||
aux = (struct aux_mem *)arg;
|
||||
ret = lotus_pmc_set_aux(aux);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "lotus_set_aux failed:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case XMEDIA_PM_GET_DDR_PARAM:
|
||||
#ifdef CONFIG_PM
|
||||
struct lpds_param *plpds_param;
|
||||
plpds_param = (struct lpds_param *)arg;
|
||||
ret = pm_ddr_param_get(plpds_param);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "get ddr param failed:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
#else
|
||||
return XMEDIA_ERRCODE_NOT_SUPPORT;
|
||||
#endif
|
||||
#ifdef PM_WAKEUP1_SUPPORT
|
||||
case XMEDIA_PM_GET_WK_INFO:
|
||||
wakeup_info = (lotus_pm_wakeup_info *)arg;
|
||||
ret = lotus_pm_get_wakeup_info(wakeup_info);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "get wakeup info failed:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case XMEDIA_PM_GET_RTC_INFO:
|
||||
rtc_info = (lotus_pm_rtc_info *)arg;
|
||||
ret = lotus_pm_get_rtc_info(rtc_info);
|
||||
if (ret != XMEDIA_SUCCESS) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "get rtc info failed:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
xmedia_s32 drv_pm_suspend(osal_dev_t *pdev)
|
||||
{
|
||||
osal_printk("pm suspend OK!\n");
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
xmedia_s32 drv_pm_resume(osal_dev_t *pdev)
|
||||
{
|
||||
g_pm_resume = true;
|
||||
osal_printk("pm resume OK!\n");
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
|
||||
static struct osal_fileops g_pm_fops = {
|
||||
.open = drv_pm_open,
|
||||
.unlocked_ioctl = drv_pm_ioctl,
|
||||
.release = drv_pm_close,
|
||||
};
|
||||
|
||||
struct osal_pmops g_pm_drv_ops = {
|
||||
.pm_suspend = drv_pm_suspend,
|
||||
.pm_resume = drv_pm_resume,
|
||||
};
|
||||
|
||||
xmedia_s32 pmoc_drv_modinit(xmedia_void)
|
||||
{
|
||||
osal_proc_entry_t *proc = XMEDIA_NULL;
|
||||
|
||||
g_pm_dev = osal_createdev(UMAP_DEVNAME_PM_BASE);
|
||||
if (g_pm_dev == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "pm create dev err!\n");
|
||||
goto out0;
|
||||
}
|
||||
|
||||
g_pm_dev->fops = &g_pm_fops;
|
||||
g_pm_dev->minor = UMAP_PM_MINOR_BASE;
|
||||
g_pm_dev->osal_pmops = &g_pm_drv_ops;
|
||||
|
||||
if (osal_registerdevice(g_pm_dev) < 0) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "regist pm device err!\n");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
g_ctrl_thread = osal_kthread_create(pm_ctrl_thread, XMEDIA_NULL, "lotus_pm_control");
|
||||
if (g_ctrl_thread == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "create pm control failed.\n");
|
||||
goto out2;
|
||||
}
|
||||
|
||||
/* create proc */
|
||||
proc = osal_create_proc_entry(MPP_MOD_PM, XMEDIA_NULL);
|
||||
if (proc == XMEDIA_NULL) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "MODULE_DBG_ERR, Create pm proc err!\n");
|
||||
goto out3;
|
||||
}
|
||||
proc->read = drv_pm_proc_show;
|
||||
proc->write = XMEDIA_NULL;
|
||||
|
||||
osal_printk("load xm_pm.ko OK!\n");
|
||||
return XMEDIA_SUCCESS;
|
||||
|
||||
out3:
|
||||
osal_kthread_destroy(g_ctrl_thread, 1);
|
||||
g_ctrl_thread = XMEDIA_NULL;
|
||||
out2:
|
||||
osal_deregisterdevice(g_pm_dev);
|
||||
out1:
|
||||
osal_destroydev(g_pm_dev);
|
||||
g_pm_dev = XMEDIA_NULL;
|
||||
out0:
|
||||
osal_printk("load xm_pm.ko err!\n");
|
||||
return XMEDIA_FAILURE;
|
||||
}
|
||||
|
||||
xmedia_void pmoc_drv_modexit(xmedia_void)
|
||||
{
|
||||
osal_remove_proc_entry(MPP_MOD_PM, XMEDIA_NULL);
|
||||
if (g_ctrl_thread && is_svb_enabled()) {
|
||||
osal_kthread_destroy(g_ctrl_thread, 1);
|
||||
g_ctrl_thread = XMEDIA_NULL;
|
||||
}
|
||||
drv_svb_deinit();
|
||||
osal_deregisterdevice(g_pm_dev);
|
||||
osal_destroydev(g_pm_dev);
|
||||
g_pm_dev = XMEDIA_NULL;
|
||||
|
||||
osal_printk("unload xm_pm.ko OK!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
|
||||
module_init(pmoc_drv_modinit);
|
||||
module_exit(pmoc_drv_modexit);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#else
|
||||
|
||||
int __init pmoc_driver_init(void)
|
||||
{
|
||||
return pmoc_drv_modinit();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,208 @@
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/fs.h>
|
||||
#include "pmoc_comm.h"
|
||||
#include "drv_svb.h"
|
||||
|
||||
#define SUPPORT_CORE_COMP
|
||||
|
||||
typedef enum {
|
||||
TEMP_STATUS_NORMAL,
|
||||
TEMP_STATUS_LOW,
|
||||
TEMP_STATUS_HIGH,
|
||||
TEMP_STATUS_MAX,
|
||||
} lotus_temp_status;
|
||||
|
||||
#define TEMPERATURE_VALUE_SVB_LOW 30
|
||||
#define TEMPERATURE_VALUE_QUIT_SVB_LOW 38
|
||||
#define TEMPERATURE_VALUE_QUIT_HIGH_POWER 88
|
||||
#define TEMPERATURE_VALUE_POWER_HIGH 90
|
||||
#define TEMPERATURE_VALUE_POWER_DOWN 120
|
||||
#define LOW_TEMP_VOLT_COMP 20
|
||||
#define TEMPERATURE_VALUE_MAX 200
|
||||
#define TEMPERATURE_VALUE_MIN (-100)
|
||||
|
||||
#define CPU_SCALING_MAX_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
|
||||
#define CPU_SCALING_MIN_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
|
||||
|
||||
#define DEFAULT_INIT_FREQ 1200000
|
||||
|
||||
static lotus_temp_status g_t_status = TEMP_STATUS_MAX;
|
||||
|
||||
xmedia_s32 write_cpufreq_node(const xmedia_char *node, xmedia_s32 value)
|
||||
{
|
||||
struct file *filep = XMEDIA_NULL;
|
||||
xmedia_char name[CPUFREQ_NAME_LEN] = { 0 };
|
||||
xmedia_u32 write_len;
|
||||
|
||||
snprintf(name, CPUFREQ_NAME_LEN, "%u\n", value);
|
||||
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "write_cpufreq_node value=%d\n", value);
|
||||
|
||||
filep = osal_klib_fopen(node, O_CREAT | O_RDWR, 0);
|
||||
if (IS_ERR(filep)) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "Failed to filp_open %s\n", node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
write_len = osal_klib_fwrite(name, sizeof(name), filep);
|
||||
if (write_len < 0) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "Failed to write to %s\n", node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
osal_klib_fclose(filep);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
xmedia_s32 read_cpufreq_node(const xmedia_char *node)
|
||||
{
|
||||
struct file *filep = XMEDIA_NULL;
|
||||
xmedia_char name[CPUFREQ_NAME_LEN] = { 0 };
|
||||
xmedia_u32 read_len;
|
||||
xmedia_s32 value = 0;
|
||||
xmedia_s32 ret;
|
||||
|
||||
filep = osal_klib_fopen(node, O_CREAT | O_RDWR, 0);
|
||||
if (IS_ERR(filep)) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "Failed to filp_open %s\n", node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
read_len = osal_klib_fread(name, sizeof(name), filep);
|
||||
if (read_len < 0) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "Failed to read from %s, read_len 0x%x\n", node, read_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = kstrtou32(name, 0, &value);
|
||||
if (ret < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "read_cpufreq_node value=%d\n", value);
|
||||
|
||||
osal_klib_fclose(filep);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static xmedia_void temp_enter_normal(xmedia_void)
|
||||
{
|
||||
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "Temperature: %d\n", get_chip_temperature());
|
||||
#ifdef SUPPORT_CORE_COMP
|
||||
set_core_comp(0);
|
||||
svb_control_apply();
|
||||
#endif
|
||||
}
|
||||
|
||||
static xmedia_void temp_quit_low(xmedia_void)
|
||||
{
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "Temperature: %d\n", get_chip_temperature());
|
||||
#ifdef SUPPORT_CORE_COMP
|
||||
set_core_comp(0);
|
||||
svb_control_apply();
|
||||
#endif
|
||||
}
|
||||
|
||||
static xmedia_void temp_enter_low(xmedia_void)
|
||||
{
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "Temperature: %d\n", get_chip_temperature());
|
||||
#ifdef SUPPORT_CORE_COMP
|
||||
set_core_comp(LOW_TEMP_VOLT_COMP);
|
||||
svb_control_apply();
|
||||
#endif
|
||||
}
|
||||
|
||||
static xmedia_void temp_quit_high(xmedia_void)
|
||||
{
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "Temperature: %d\n", get_chip_temperature());
|
||||
}
|
||||
|
||||
static xmedia_void temp_enter_high(xmedia_void)
|
||||
{
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "Temperature: %d\n", get_chip_temperature());
|
||||
}
|
||||
|
||||
static xmedia_void temp_power_down(xmedia_void)
|
||||
{
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "Temperature: %d\n", get_chip_temperature());
|
||||
}
|
||||
|
||||
xmedia_void temp_init(xmedia_void)
|
||||
{
|
||||
xmedia_s32 temp = get_chip_temperature();
|
||||
|
||||
if (temp <= TEMPERATURE_VALUE_SVB_LOW) {
|
||||
temp_enter_low();
|
||||
g_t_status = TEMP_STATUS_LOW;
|
||||
} else if (temp > TEMPERATURE_VALUE_SVB_LOW && temp <= TEMPERATURE_VALUE_POWER_HIGH) {
|
||||
temp_enter_normal();
|
||||
g_t_status = TEMP_STATUS_NORMAL;
|
||||
} else if (temp > TEMPERATURE_VALUE_POWER_HIGH && temp < TEMPERATURE_VALUE_POWER_DOWN) {
|
||||
temp_enter_normal(); // TODO: remove when temp_enter_high() supported
|
||||
temp_enter_high();
|
||||
g_t_status = TEMP_STATUS_HIGH;
|
||||
} else if (temp >= TEMPERATURE_VALUE_POWER_DOWN) {
|
||||
temp_enter_normal(); // TODO: remove when temp_power_down() supported
|
||||
temp_power_down();
|
||||
g_t_status = TEMP_STATUS_HIGH;
|
||||
} else {
|
||||
temp_enter_low();
|
||||
g_t_status = TEMP_STATUS_LOW;
|
||||
}
|
||||
|
||||
PM_TRACE(MODULE_DBG_DEBUG, "Temperature: %d, g_t_status: %d\n", temp, g_t_status);
|
||||
}
|
||||
|
||||
xmedia_s32 temp_control_thread(xmedia_void)
|
||||
{
|
||||
xmedia_s32 temp;
|
||||
|
||||
temp = get_chip_temperature();
|
||||
if ((temp <= TEMPERATURE_VALUE_MIN) || (temp >= TEMPERATURE_VALUE_MAX)) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "Invalid Temperature: %d\n", temp);
|
||||
return XMEDIA_FAILURE;
|
||||
}
|
||||
|
||||
switch (g_t_status) {
|
||||
case TEMP_STATUS_LOW:
|
||||
if (temp > TEMPERATURE_VALUE_POWER_HIGH) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "Abnormal rise in temperature: %d, g_t_status: %d\n", temp, g_t_status);
|
||||
} else if (temp > TEMPERATURE_VALUE_QUIT_SVB_LOW) {
|
||||
temp_quit_low();
|
||||
g_t_status = TEMP_STATUS_NORMAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TEMP_STATUS_NORMAL:
|
||||
if (temp < TEMPERATURE_VALUE_SVB_LOW) {
|
||||
temp_enter_low();
|
||||
g_t_status = TEMP_STATUS_LOW;
|
||||
} else if (temp > TEMPERATURE_VALUE_POWER_DOWN) {
|
||||
temp_power_down();
|
||||
g_t_status = TEMP_STATUS_NORMAL;
|
||||
} else if (temp > TEMPERATURE_VALUE_POWER_HIGH) {
|
||||
temp_enter_high();
|
||||
g_t_status = TEMP_STATUS_HIGH;
|
||||
}
|
||||
break;
|
||||
case TEMP_STATUS_HIGH:
|
||||
if (temp < TEMPERATURE_VALUE_SVB_LOW) {
|
||||
PM_TRACE(MODULE_DBG_ERR, "Abnormal fall in temperature: %d, g_t_status: %d\n", temp, g_t_status);
|
||||
} else if (temp < TEMPERATURE_VALUE_QUIT_HIGH_POWER) {
|
||||
temp_quit_high();
|
||||
g_t_status = TEMP_STATUS_NORMAL;
|
||||
} else if (temp > TEMPERATURE_VALUE_POWER_DOWN) {
|
||||
temp_power_down();
|
||||
g_t_status = TEMP_STATUS_NORMAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PM_TRACE(MODULE_DBG_ERR, "Invalid temperature status: %d, T=%d\n", g_t_status, temp);
|
||||
break;
|
||||
}
|
||||
|
||||
return XMEDIA_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef __DRV_PM_TEMPERATURE_H__
|
||||
#define __DRV_PM_TEMPERATURE_H__
|
||||
|
||||
#include "xmedia_type.h"
|
||||
|
||||
xmedia_void temp_init(xmedia_void);
|
||||
xmedia_s32 temp_control_thread(xmedia_void);
|
||||
xmedia_s32 read_cpufreq_node(const xmedia_char *node);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user