soc: rockchip: add virtual poweroff support

Change-Id: I79240fa936eee3e64eb74eb5d5cdc952c3b2ac9b
Signed-off-by: XiaoDong Huang <derrick.huang@rock-chips.com>
This commit is contained in:
XiaoDong Huang
2017-03-06 11:34:41 +08:00
committed by Huang, Tao
parent 3f217d60ae
commit 2dd82913d7
3 changed files with 110 additions and 0 deletions
+15
View File
@@ -18,6 +18,12 @@
#include <asm/smp_plat.h>
#include <uapi/linux/psci.h>
#ifdef CONFIG_64BIT
#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name
#else
#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name
#endif
#define SIZE_PAGE(n) ((n) << 12)
static struct arm_smccc_res __invoke_sip_fn_smc(unsigned long function_id,
@@ -59,6 +65,15 @@ int sip_smc_set_suspend_mode(u32 ctrl,
return res.a0;
}
int rk_psci_virtual_poweroff(void)
{
struct arm_smccc_res res;
res = __invoke_sip_fn_smc(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND),
0, 0, 0);
return res.a0;
}
static u64 ft_fiq_mem_phy;
static void __iomem *ft_fiq_mem_base;
static void (*psci_fiq_debugger_uart_irq_tf)(void *reg_base, u64 sp_el1);
+92
View File
@@ -16,6 +16,7 @@
#include <linux/regulator/machine.h>
#include <linux/rockchip/rockchip_sip.h>
#include <linux/suspend.h>
#include <dt-bindings/input/input.h>
#define PM_INVALID_GPIO 0xffff
@@ -24,6 +25,90 @@ static const struct of_device_id pm_match_table[] = {
{ },
};
#define MAX_PWRKEY_NUMS 20
#define MAX_NUM_KEYS 60
struct rkxx_remote_key_table {
int scancode;
int keycode;
};
static int parse_ir_pwrkeys(unsigned int *pwrkey, int size, int *nkey)
{
struct device_node *node;
struct device_node *child_node;
struct rkxx_remote_key_table key_table[MAX_NUM_KEYS];
int i;
int len = 0, nbuttons;
int num = 0;
u32 usercode, scancode;
for_each_node_by_name(node, "pwm") {
for_each_child_of_node(node, child_node) {
if (of_property_read_u32(child_node,
"rockchip,usercode",
&usercode))
break;
if (of_get_property(child_node,
"rockchip,key_table",
&len) == NULL ||
len <= 0)
break;
len = len < sizeof(key_table) ? len : sizeof(key_table);
len /= sizeof(u32);
if (of_property_read_u32_array(child_node,
"rockchip,key_table",
(u32 *)key_table,
len))
break;
nbuttons = len / 2;
for (i = 0; i < nbuttons && num < size; ++i) {
if (key_table[i].keycode == KEY_POWER) {
scancode = key_table[i].scancode;
pr_debug("usercode=%x, key=%x\n",
usercode, scancode);
pwrkey[num] = (usercode & 0xffff) << 16;
pwrkey[num] |= (scancode & 0xff) << 8;
++num;
}
}
}
}
*nkey = num;
return num ? 0 : -1;
}
static void rockchip_pm_virt_pwroff_prepare(void)
{
int error;
int i, nkey;
u32 power_key[MAX_PWRKEY_NUMS];
if ((parse_ir_pwrkeys(power_key, ARRAY_SIZE(power_key), &nkey))) {
pr_err("Parse ir powerkey code failed!\n");
return;
}
for (i = 0; i < nkey; ++i)
sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 1, power_key[i]);
regulator_suspend_prepare(PM_SUSPEND_MEM);
error = disable_nonboot_cpus();
if (error) {
pr_err("Disable nonboot cpus failed!\n");
return;
}
sip_smc_set_suspend_mode(VIRTUAL_POWEROFF, 0, 1);
rk_psci_virtual_poweroff();
}
static int __init pm_config_init(struct platform_device *pdev)
{
const struct of_device_id *match_id;
@@ -34,6 +119,7 @@ static int __init pm_config_init(struct platform_device *pdev)
int gpio_temp[10];
u32 sleep_debug_en = 0;
u32 apios_suspend = 0;
u32 virtual_poweroff_en = 0;
enum of_gpio_flags flags;
int i = 0;
int length;
@@ -103,6 +189,12 @@ static int __init pm_config_init(struct platform_device *pdev)
apios_suspend,
0);
if (!of_property_read_u32_array(node,
"rockchip,virtual-poweroff",
&virtual_poweroff_en, 1) &&
virtual_poweroff_en)
pm_power_off_prepare = rockchip_pm_virt_pwroff_prepare;
return 0;
}
+3
View File
@@ -70,12 +70,15 @@ typedef enum {
#define GPIO_POWER_CONFIG 0x04
#define SUSPEND_DEBUG_ENABLE 0x05
#define APIOS_SUSPEND_CONFIG 0x06
#define VIRTUAL_POWEROFF 0x07
/* struct arm_smccc_res: a0: error code; a1~a3: data */
/* SMC32 Calls */
int sip_smc_set_suspend_mode(u32 ctrl,
u32 config1,
u32 config2);
int rk_psci_virtual_poweroff(void);
struct arm_smccc_res sip_smc_get_call_count(void);
struct arm_smccc_res sip_smc_get_atf_version(void);
struct arm_smccc_res sip_smc_get_sip_version(void);