unplugged-kernel/drivers/misc/mediatek/base/power/spm/mt6765/mtk_sspm.c

233 lines
5.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/uaccess.h> /* copy_from/to_user() */
#include <linux/sched/clock.h>
#include <asm/arch_timer.h>
#include <sspm_ipi.h>
//#include <trace/events/mtk_events.h>
#include <mtk_sspm.h>
#include <mtk_spm_internal.h>
#define mtk_timer_src_count(...) arch_counter_get_cntvct(__VA_ARGS__)
#define SPM_D_LEN (8) /* # of cmd + arg0 + arg1 + ... */
int spm_to_sspm_command_async(u32 cmd, struct spm_data *spm_d)
{
unsigned int ret = 0;
switch (cmd) {
case SPM_DPIDLE_ENTER:
case SPM_DPIDLE_LEAVE:
case SPM_ENTER_SODI:
case SPM_LEAVE_SODI:
case SPM_ENTER_SODI3:
case SPM_LEAVE_SODI3:
spm_d->cmd = cmd;
ret = sspm_ipi_send_async(
IPI_ID_SPM_SUSPEND, IPI_OPT_DEFAUT, spm_d, SPM_D_LEN);
if (ret != 0)
printk_deferred("[name:spm&]#@# %s(%d) sspm_ipi_send_async(cmd:0x%x) ret %d\n",
__func__, __LINE__, cmd, ret);
break;
default:
printk_deferred("[name:spm&]#@# %s(%d) cmd(%d) wrong!!!\n",
__func__, __LINE__, cmd);
break;
}
return ret;
}
int spm_to_sspm_command_async_wait(u32 cmd)
{
int ack_data = 0;
unsigned int ret = 0;
switch (cmd) {
case SPM_DPIDLE_ENTER:
case SPM_DPIDLE_LEAVE:
case SPM_ENTER_SODI:
case SPM_LEAVE_SODI:
case SPM_ENTER_SODI3:
case SPM_LEAVE_SODI3:
ret = sspm_ipi_send_async_wait(
IPI_ID_SPM_SUSPEND, IPI_OPT_DEFAUT, &ack_data);
if (ret != 0) {
printk_deferred("[name:spm&]#@# %s(%d) sspm_ipi_send_async_wait(cmd:0x%x) ret %d\n",
__func__, __LINE__, cmd, ret);
} else if (ack_data < 0) {
ret = ack_data;
printk_deferred("[name:spm&]#@# %s(%d) cmd(%d) return %d\n",
__func__, __LINE__, cmd, ret);
}
break;
default:
printk_deferred("[name:spm&]#@# %s(%d) cmd(%d) wrong!!!\n",
__func__, __LINE__, cmd);
break;
}
return ret;
}
int spm_to_sspm_command(u32 cmd, struct spm_data *spm_d)
{
int ack_data = 0;
unsigned int ret = 0;
/* struct spm_data _spm_d; */
switch (cmd) {
case SPM_SUSPEND:
case SPM_RESUME:
case SPM_DPIDLE_ENTER:
case SPM_DPIDLE_LEAVE:
case SPM_ENTER_SODI:
case SPM_ENTER_SODI3:
case SPM_LEAVE_SODI:
case SPM_LEAVE_SODI3:
spm_d->cmd = cmd;
ret = sspm_ipi_send_sync(
IPI_ID_SPM_SUSPEND, IPI_OPT_POLLING, spm_d, SPM_D_LEN,
&ack_data, 1);
if (ret != 0) {
printk_deferred("[name:spm&]#@# %s(%d) cmd:0x%x ret %d\n",
__func__, __LINE__, cmd, ret);
} else if (ack_data < 0) {
ret = ack_data;
printk_deferred("[name:spm&]#@# %s(%d) cmd:0x%x ret %d\n",
__func__, __LINE__, cmd, ret);
}
break;
case SPM_VCORE_PWARP_CMD:
spm_d->cmd = cmd;
ret = sspm_ipi_send_sync(
IPI_ID_SPM_SUSPEND, IPI_OPT_POLLING, spm_d, SPM_D_LEN,
&ack_data, 1);
if (ret != 0) {
printk_deferred("[name:spm&]#@# %s(%d) cmd:0x%x ret %d\n",
__func__, __LINE__, cmd, ret);
} else if (ack_data < 0) {
ret = ack_data;
printk_deferred("[name:spm&]#@# %s(%d) cmd:0x%x ret %d\n",
__func__, __LINE__, cmd, ret);
}
break;
case SPM_SUSPEND_PREPARE:
case SPM_POST_SUSPEND:
spm_d->cmd = cmd;
ret = sspm_ipi_send_sync(
IPI_ID_SPM_SUSPEND, IPI_OPT_POLLING, spm_d, SPM_D_LEN,
&ack_data, 1);
if (ret != 0) {
printk_deferred("[name:spm&]#@# %s(%d) cmd:0x%x ret %d\n",
__func__, __LINE__, cmd, ret);
} else if (ack_data < 0) {
ret = ack_data;
printk_deferred("[name:spm&]#@# %s(%d) cmd:0x%x ret %d\n",
__func__, __LINE__, cmd, ret);
}
break;
case SPM_DPIDLE_PREPARE:
case SPM_POST_DPIDLE:
spm_d->cmd = cmd;
ret = sspm_ipi_send_sync(
IPI_ID_SPM_SUSPEND, IPI_OPT_POLLING, spm_d, SPM_D_LEN,
&ack_data, 1);
if (ret != 0) {
printk_deferred("[name:spm&]#@# %s(%d) cmd:0x%x ret %d\n",
__func__, __LINE__, cmd, ret);
} else if (ack_data < 0) {
ret = ack_data;
printk_deferred("[name:spm&]#@# %s(%d) cmd:0x%x ret %d\n",
__func__, __LINE__, cmd, ret);
}
break;
case SPM_SODI_PREPARE:
case SPM_POST_SODI:
case SPM_TWAM_ENABLE:
spm_d->cmd = cmd;
ret = sspm_ipi_send_sync(
IPI_ID_SPM_SUSPEND, IPI_OPT_POLLING, spm_d, SPM_D_LEN,
&ack_data, 1);
if (ret != 0) {
printk_deferred("[name:spm&]#@# %s(%d) cmd:0x%x ret %d\n",
__func__, __LINE__, cmd, ret);
} else if (ack_data < 0) {
ret = ack_data;
printk_deferred("[name:spm&]#@# %s(%d) cmd:0x%x ret %d\n",
__func__, __LINE__, cmd, ret);
}
break;
default:
printk_deferred("[name:spm&]#@# %s(%d) cmd(%d) wrong!!!\n",
__func__, __LINE__, cmd);
break;
}
return ret;
}
static atomic_t ipi_lock_cnt;
bool is_sspm_ipi_lock_spm(void)
{
int lock_cnt = -1;
bool ret = false;
lock_cnt = atomic_read(&ipi_lock_cnt);
ret = (lock_cnt == 0) ? false : true;
return ret;
}
void sspm_ipi_lock_spm_scenario(int start, int id, int opt, const char *name)
{
if (id == IPI_ID_SPM_SUSPEND)
return;
if (id < 0 || id >= IPI_ID_TOTAL)
return;
if (start)
atomic_inc(&ipi_lock_cnt);
else
atomic_dec(&ipi_lock_cnt);
/* FTRACE tag */
//trace_sspm_ipi(start, id, opt);
}
static void sspm_timesync_timestamp(unsigned long long src, unsigned int *ts_h,
unsigned int *ts_l)
{
*ts_l = (unsigned int)(src & 0x00000000FFFFFFFF);
*ts_h = (unsigned int)((src & 0xFFFFFFFF00000000) >> 32);
}
void sspm_timesync_ts_get(unsigned int *ts_h, unsigned int *ts_l)
{
unsigned long long ap_ts;
ap_ts = sched_clock();
sspm_timesync_timestamp(ap_ts, ts_h, ts_l);
}
void sspm_timesync_clk_get(unsigned int *clk_h, unsigned int *clk_l)
{
unsigned long long ap_clk;
ap_clk = mtk_timer_src_count();
sspm_timesync_timestamp(ap_clk, clk_h, clk_l);
}