kernel-brax3-ubuntu-touch/drivers/misc/mediatek/swpm/swpm_module.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

317 lines
7.6 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/syscalls.h>
#include <linux/timer.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#if IS_ENABLED(CONFIG_MTK_QOS_FRAMEWORK)
#include <mtk_qos_ipi.h>
#endif
#if IS_ENABLED(CONFIG_MTK_TINYSYS_SSPM_SUPPORT)
#include <sspm_reservedmem.h>
#include <sspm_reservedmem_define.h>
#endif
/* TODO: GPU fix */
/* #if IS_ENABLED(CONFIG_MTK_GPU_SWPM_SUPPORT) */
/* #include <mtk_gpu_power_sspm_ipi.h> */
/* #endif */
#include <swpm_module.h>
/****************************************************************************
* Global Variables
****************************************************************************/
/* DEFINE_MUTEX(swpm_mutex); */
struct mutex swpm_mutex = __MUTEX_INITIALIZER(swpm_mutex);
EXPORT_SYMBOL(swpm_mutex);
struct timer_list swpm_timer;
EXPORT_SYMBOL(swpm_timer);
struct workqueue_struct *swpm_common_wq;
EXPORT_SYMBOL(swpm_common_wq);
unsigned int swpm_log_interval_ms = DEFAULT_LOG_INTERVAL_MS;
EXPORT_SYMBOL(swpm_log_interval_ms);
/****************************************************************************
* Local Variables
****************************************************************************/
static struct swpm_manager swpm_m = {
.initialize = 0,
.plat_ready = 0,
.mem_ref_tbl = NULL,
.ref_tbl_size = 0,
};
static struct atomic_notifier_head swpm_notifier_list;
/***************************************************************************
* API
***************************************************************************/
int swpm_core_ops_register(struct swpm_core_internal_ops *ops)
{
if (!swpm_m.plat_ops && ops) {
swpm_m.plat_ops = ops;
swpm_m.plat_ready = (swpm_m.plat_ops->cmd) ? true : false;
} else
return -1;
return 0;
}
EXPORT_SYMBOL(swpm_core_ops_register);
void swpm_get_rec_addr(phys_addr_t *phys,
phys_addr_t *virt,
unsigned long long *size)
{
#if IS_ENABLED(CONFIG_MTK_TINYSYS_SSPM_SUPPORT)
/* get sspm reserved mem */
*phys = sspm_reserve_mem_get_phys(SWPM_MEM_ID);
*virt = sspm_reserve_mem_get_virt(SWPM_MEM_ID);
*size = sspm_reserve_mem_get_size(SWPM_MEM_ID);
pr_notice("phy_addr = 0x%llx, virt_addr=0x%llx, size = %llu\n",
(unsigned long long) *phys,
(unsigned long long) *virt,
*size);
#endif
}
EXPORT_SYMBOL(swpm_get_rec_addr);
int swpm_interface_manager_init(struct swpm_mem_ref_tbl *ref_tbl,
unsigned int tbl_size)
{
if (!ref_tbl)
return -1;
swpm_lock(&swpm_mutex);
swpm_m.initialize = true;
swpm_m.mem_ref_tbl = ref_tbl;
swpm_m.ref_tbl_size = tbl_size;
swpm_unlock(&swpm_mutex);
return 0;
}
EXPORT_SYMBOL(swpm_interface_manager_init);
int swpm_mem_addr_request(unsigned int id, phys_addr_t **ptr)
{
int ret = 0;
if (!swpm_m.initialize || !swpm_m.mem_ref_tbl) {
pr_notice("swpm not initialize\n");
ret = -1;
goto end;
} else if (id >= swpm_m.ref_tbl_size) {
pr_notice("swpm_type invalid\n");
ret = -2;
goto end;
} else if (!(swpm_m.mem_ref_tbl[id].valid)
|| !(swpm_m.mem_ref_tbl[id].virt)) {
ret = -3;
pr_notice("swpm_mem_ref id not initialize\n");
goto end;
}
swpm_lock(&swpm_mutex);
*ptr = (swpm_m.mem_ref_tbl[id].virt);
swpm_unlock(&swpm_mutex);
end:
return ret;
}
EXPORT_SYMBOL(swpm_mem_addr_request);
int swpm_pmu_enable(enum swpm_pmu_user id,
unsigned int enable)
{
unsigned int cmd_code;
if (!swpm_m.plat_ready) {
pr_notice("swpm platform init not ready\n");
return SWPM_INIT_ERR;
} else if (id >= NR_SWPM_PMU_USER)
return SWPM_ARGS_ERR;
cmd_code = (!!enable) | (id << SWPM_CODE_USER_BIT);
if (SWPM_OPS->cmd)
SWPM_OPS->cmd(SET_PMU, cmd_code);
return SWPM_SUCCESS;
}
EXPORT_SYMBOL(swpm_pmu_enable);
int swpm_reserve_mem_init(phys_addr_t *virt,
unsigned long long *size)
{
int i;
unsigned char *ptr;
if (!virt)
return -1;
/* clear reserve mem */
ptr = (unsigned char *)(uintptr_t)*virt;
for (i = 0; i < *size; i++)
ptr[i] = 0x0;
return 0;
}
EXPORT_SYMBOL(swpm_reserve_mem_init);
/* TODO:deprecated, compatible with old version */
void swpm_set_cmd(unsigned int type, unsigned int cnt)
{
swpm_lock(&swpm_mutex);
#if IS_ENABLED(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && \
IS_ENABLED(CONFIG_MTK_QOS_FRAMEWORK)
{
struct qos_ipi_data qos_d;
qos_d.cmd = QOS_IPI_SWPM_SET_UPDATE_CNT;
#if !IS_ENABLED(CONFIG_MTK_TINYSYS_SCMI)
qos_d.u.swpm_set_update_cnt.type = type;
qos_d.u.swpm_set_update_cnt.cnt = cnt;
#endif
qos_ipi_to_sspm_scmi_command(qos_d.cmd, type, cnt, 0,
QOS_IPI_SCMI_SET);
}
#endif
swpm_unlock(&swpm_mutex);
}
EXPORT_SYMBOL(swpm_set_cmd);
void swpm_set_only_cmd(unsigned int args_0,
unsigned int args_1,
unsigned int action,
unsigned int type)
{
unsigned int code;
swpm_lock(&swpm_mutex);
#if IS_ENABLED(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && \
IS_ENABLED(CONFIG_MTK_QOS_FRAMEWORK)
{
struct qos_ipi_data qos_d;
qos_d.cmd = QOS_IPI_SWPM_INIT;
code = (SWPM_CMD_MAGIC << SWPM_CMD_MAGIC_BIT)
| ((action & SWPM_CMD_ACTION_MASK) << SWPM_CMD_ACTION_BIT)
| ((type & SWPM_CMD_TYPE_MASK) << SWPM_CMD_TYPE_BIT);
#if !IS_ENABLED(CONFIG_MTK_TINYSYS_SCMI)
qos_d.u.swpm_init.dram_addr = args_0;
qos_d.u.swpm_init.dram_size = args_1;
qos_d.u.swpm_init.dram_ch_num = code;
#endif
qos_ipi_to_sspm_scmi_command(qos_d.cmd, args_0, args_1, code,
QOS_IPI_SCMI_SET);
}
#endif
swpm_unlock(&swpm_mutex);
}
EXPORT_SYMBOL(swpm_set_only_cmd);
unsigned int swpm_set_and_get_cmd(unsigned int args_0,
unsigned int args_1,
unsigned int action,
unsigned int type)
{
unsigned int ret = 0;
unsigned int code;
swpm_lock(&swpm_mutex);
#if IS_ENABLED(CONFIG_MTK_TINYSYS_SSPM_SUPPORT) && \
IS_ENABLED(CONFIG_MTK_QOS_FRAMEWORK)
if (type < NR_SWPM_CMD_TYPE) {
struct qos_ipi_data qos_d;
qos_d.cmd = QOS_IPI_SWPM_INIT;
code = (SWPM_CMD_MAGIC << SWPM_CMD_MAGIC_BIT)
| ((action & SWPM_CMD_ACTION_MASK) << SWPM_CMD_ACTION_BIT)
| ((type & SWPM_CMD_TYPE_MASK) << SWPM_CMD_TYPE_BIT);
#if !IS_ENABLED(CONFIG_MTK_TINYSYS_SCMI)
qos_d.u.swpm_init.dram_addr = args_0;
qos_d.u.swpm_init.dram_size = args_1;
qos_d.u.swpm_init.dram_ch_num = code;
#endif
qos_ipi_to_sspm_scmi_command(qos_d.cmd,
args_0, args_1, code,
QOS_IPI_SCMI_SET);
ret = qos_ipi_to_sspm_scmi_command(qos_d.cmd,
args_0, args_1, code,
QOS_IPI_SCMI_GET);
}
#endif
swpm_unlock(&swpm_mutex);
return ret;
}
EXPORT_SYMBOL(swpm_set_and_get_cmd);
int swpm_register_event_notifier(struct notifier_block *nb)
{
int err;
err = atomic_notifier_chain_register(&swpm_notifier_list, nb);
return err;
}
EXPORT_SYMBOL_GPL(swpm_register_event_notifier);
int swpm_unregister_event_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&swpm_notifier_list, nb);
}
EXPORT_SYMBOL_GPL(swpm_unregister_event_notifier);
int swpm_call_event_notifier(unsigned long val, void *v)
{
return atomic_notifier_call_chain(&swpm_notifier_list, val, v);
}
EXPORT_SYMBOL_GPL(swpm_call_event_notifier);
static int __init swpm_init(void)
{
int ret = 0;
swpm_common_wq = create_workqueue("swpm_common_wq");
ATOMIC_INIT_NOTIFIER_HEAD(&swpm_notifier_list);
return ret;
}
#ifdef MTK_SWPM_KERNEL_MODULE
static void __exit swpm_deinit(void)
{
flush_workqueue(swpm_common_wq);
destroy_workqueue(swpm_common_wq);
}
module_init(swpm_init);
module_exit(swpm_deinit);
#else
device_initcall_sync(swpm_init);
#endif
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("mtk swpm module");
MODULE_AUTHOR("MediaTek Inc.");