/* | |
* Copyright (C) 2024, ASR Microelectronics(Shanghai) LTD. Co. | |
* All rights reserved. | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License version 2 and | |
* only version 2 as published by the Free Software Foundation. | |
* | |
*/ | |
#include <linux/init.h> | |
#include <linux/module.h> | |
#include <linux/platform_device.h> | |
#include <linux/fs.h> | |
#include <linux/string.h> | |
#include <linux/of.h> | |
#include <linux/slab.h> | |
#include <linux/of_address.h> | |
#include <linux/arm-smccc.h> | |
#include <linux/tee_drv.h> | |
#include <linux/asr_tee_sip.h> | |
/* Power Management */ | |
#define ASR_CPU_POWER_DOWN (0x84000001) | |
#define ASR_SYSTEM_POWER_DOWN (0x8400000e) | |
#ifdef CONFIG_CPU_ASR1901 | |
#define ASR_CPU_POWER_ON (0x84000003) | |
#define ASR_CACHE_DISABLE (0x84000015) | |
#endif | |
#define ASR_SIP_MFPR_UDR_CFG_ADD (0x82000001) | |
#define ASR_SIP_WAKEUP_STATE_SET (0x82000002) | |
#define ASR_SIP_MFPR_UDR_CFG_INIT (0x82000003) | |
#define ASR_SIP_SOC_REG_WRITE (0x82000004) | |
#define ASR_SIP_SOC_REG_READ (0x82000005) | |
#define ASR_SIP_REG_CIU (1) | |
#define ASR_SIP_REG_GEU (2) | |
#define ASR_SIP_WAKE_STATUS_INIT (0x82000006) | |
#define ASR_SIP_GPIO_EDGE_CFG (0x82000007) | |
#define ASR_SIP_IRQ_WAKEUP_SET (0x82000008) | |
#ifndef CONFIG_CPU_ASR1901 | |
int asr_tee_cpu_power_down(unsigned int cpu, unsigned long entry_point) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_CPU_POWER_DOWN, cpu, entry_point, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
int asr_tee_system_suspend(unsigned long entry_point) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SYSTEM_POWER_DOWN, entry_point, 0, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
return 0; | |
} | |
#else | |
int asr_tee_cpu_power_on(unsigned int cpu, unsigned int cluster, | |
unsigned int entry_point) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_CPU_POWER_ON, cpu, entry_point, cluster, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
int asr_tee_cpu_power_down(u32 state, unsigned long entry_point) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_CPU_POWER_DOWN, state, entry_point, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
int asr_tee_cluster_power_down(u32 state, unsigned long entry_point) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SYSTEM_POWER_DOWN, entry_point, state, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
int asr_tee_cache_disable(int last_man, int lpm_state) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_CACHE_DISABLE, last_man, lpm_state, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
#endif | |
unsigned int asr_ciu_read(unsigned int offset) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_SOC_REG_READ, ASR_SIP_REG_CIU, offset, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
void asr_ciu_write(unsigned int offset, unsigned int val) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_SOC_REG_WRITE, ASR_SIP_REG_CIU, offset, val, 0, 0, 0, 0, &res); | |
return; | |
} | |
unsigned long asr_mfpr_udr_cfg_add(unsigned long offset, unsigned long value) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_MFPR_UDR_CFG_ADD, offset, value, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
unsigned long asr_mfpr_udr_cfg_init(unsigned long num) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_MFPR_UDR_CFG_INIT, num, 0, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
unsigned long asr_wakeup_state_set(unsigned long state) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_WAKEUP_STATE_SET, state, 0, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
unsigned long asr_wake_status_init(unsigned long status_addr) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_WAKE_STATUS_INIT, (unsigned int)status_addr, 0, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
unsigned long asr_gpio_edge_detect_add(unsigned long gpio) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_GPIO_EDGE_CFG, 0/*add*/, gpio, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
unsigned long asr_gpio_edge_detect_remove(unsigned long gpio) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_GPIO_EDGE_CFG, 1/*remove*/, gpio, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
unsigned long asr_gpio_edge_detect_disable(unsigned long gpio) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_GPIO_EDGE_CFG, 2/*disable*/, gpio, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
unsigned long asr_gpio_edge_detect_enable(unsigned long gpio) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_GPIO_EDGE_CFG, 3/*enable*/, gpio, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |
unsigned long asr_irq_wake_set(unsigned long irq, unsigned long on) | |
{ | |
struct arm_smccc_res res; | |
arm_smccc_smc(ASR_SIP_IRQ_WAKEUP_SET, irq, on, 0, 0, 0, 0, 0, &res); | |
return res.a0; | |
} | |