GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
+30
View File
@@ -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
+55
View File
@@ -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
+632
View File
@@ -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);
}
+161
View File
@@ -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_WAKEUPgpio唤醒时),detail为唤醒gpio号,唤醒gpio号与xmedia_pm_attr中的唤醒gpio号对应
* 当type为PM_WKMODE_STARTUP detail无意义
* 当type为PM_WKMODE_BUTTONdetail无意义
* 当type为PM_WKMODE_RTCdetail无意义
*/
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
+119
View File
@@ -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;
}
+14
View File
@@ -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
+15
View File
@@ -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
+323
View File
@@ -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
+208
View File
@@ -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;
}
+10
View File
@@ -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