396 lines
9.3 KiB
C
396 lines
9.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
#define pr_fmt(fmt) "[usrtch]"fmt
|
|
|
|
#include <linux/slab.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <mt-plat/fpsgo_common.h>
|
|
|
|
#include "tchbst.h"
|
|
#include "fstb.h"
|
|
#include "mtk_perfmgr_internal.h"
|
|
|
|
static void notify_touch_up_timeout(struct work_struct *work);
|
|
static DECLARE_WORK(mt_touch_timeout_work, (void *) notify_touch_up_timeout);
|
|
|
|
static struct workqueue_struct *wq;
|
|
static struct mutex notify_lock;
|
|
static struct hrtimer hrt1;
|
|
|
|
static int usrtch_dbg;
|
|
static int touch_boost_value;
|
|
static int touch_boost_opp; /* boost freq of touch boost */
|
|
static int *cluster_opp;
|
|
static struct cpu_ctrl_data *target_freq, *reset_freq;
|
|
static int touch_boost_duration;
|
|
static long long active_time;
|
|
static int time_to_last_touch;
|
|
static int deboost_when_render;
|
|
static int usrtch_debug;
|
|
static int touch_event;/*touch down:1 */
|
|
static ktime_t last_touch_time;
|
|
|
|
void switch_usrtch(int enable)
|
|
{
|
|
mutex_lock(¬ify_lock);
|
|
usrtch_dbg = !enable;
|
|
mutex_unlock(¬ify_lock);
|
|
}
|
|
|
|
void switch_eas_boost(int boost_value)
|
|
{
|
|
touch_boost_value = boost_value;
|
|
}
|
|
|
|
void switch_init_opp(int boost_opp)
|
|
{
|
|
int i;
|
|
|
|
touch_boost_opp = boost_opp;
|
|
for (i = 0; i < perfmgr_clusters; i++)
|
|
target_freq[i].min =
|
|
mt_cpufreq_get_freq_by_idx(i, touch_boost_opp);
|
|
}
|
|
|
|
void switch_cluster_opp(int id, int boost_opp)
|
|
{
|
|
if (id < 0 || id >= perfmgr_clusters || boost_opp < -2)
|
|
return;
|
|
|
|
cluster_opp[id] = boost_opp;
|
|
|
|
if (boost_opp == -2) /* don't boost */
|
|
target_freq[id].min = -1;
|
|
else if (boost_opp == -1) /* use touch_boost_opp */
|
|
target_freq[id].min = mt_cpufreq_get_freq_by_idx(id, touch_boost_opp);
|
|
else /* use boost_opp */
|
|
target_freq[id].min = mt_cpufreq_get_freq_by_idx(id, boost_opp);
|
|
}
|
|
|
|
void switch_init_duration(int duration)
|
|
{
|
|
touch_boost_duration = duration;
|
|
}
|
|
|
|
void switch_active_time(int duration)
|
|
{
|
|
active_time = duration;
|
|
}
|
|
|
|
void switch_time_to_last_touch(int duration)
|
|
{
|
|
time_to_last_touch = duration;
|
|
}
|
|
|
|
void switch_deboost_when_render(int enable)
|
|
{
|
|
deboost_when_render = !!enable;
|
|
}
|
|
|
|
/*--------------------TIMER------------------------*/
|
|
static void enable_touch_boost_timer(void)
|
|
{
|
|
ktime_t ktime;
|
|
|
|
ktime = ktime_set(0, touch_boost_duration);
|
|
hrtimer_start(&hrt1, ktime, HRTIMER_MODE_REL);
|
|
if (usrtch_debug)
|
|
pr_debug("touch_boost_duration:\t %d\n", touch_boost_duration);
|
|
|
|
}
|
|
|
|
static void disable_touch_boost_timer(void)
|
|
{
|
|
hrtimer_cancel(&hrt1);
|
|
}
|
|
|
|
|
|
static enum hrtimer_restart mt_touch_timeout(struct hrtimer *timer)
|
|
{
|
|
if (wq)
|
|
queue_work(wq, &mt_touch_timeout_work);
|
|
|
|
return HRTIMER_NORESTART;
|
|
}
|
|
|
|
/*--------------------FRAME HINT OP------------------------*/
|
|
int notify_touch(int action)
|
|
{
|
|
int ret = 0;
|
|
int isact = 0;
|
|
ktime_t now, delta;
|
|
|
|
if (!deboost_when_render && action == 3)
|
|
return ret;
|
|
|
|
if (action != 3) {
|
|
now = ktime_get();
|
|
delta = ktime_sub(now, last_touch_time);
|
|
last_touch_time = now;
|
|
|
|
/* lock is mandatory*/
|
|
WARN_ON(!mutex_is_locked(¬ify_lock));
|
|
isact = is_fstb_active(active_time);
|
|
|
|
perfmgr_trace_count(isact, "isact");
|
|
|
|
if ((isact && ktime_to_ms(delta) < time_to_last_touch) ||
|
|
usrtch_dbg)
|
|
return ret;
|
|
}
|
|
|
|
/*action 1: touch down 2: touch up*/
|
|
/* -> 3: fpsgo active*/
|
|
if (action == 1) {
|
|
disable_touch_boost_timer();
|
|
enable_touch_boost_timer();
|
|
|
|
/* boost */
|
|
update_eas_uclamp_min(EAS_UCLAMP_KIR_TOUCH,
|
|
CGROUP_TA, touch_boost_value);
|
|
update_userlimit_cpu_freq(CPU_KIR_TOUCH,
|
|
perfmgr_clusters, target_freq);
|
|
if (usrtch_debug)
|
|
pr_debug("touch down\n");
|
|
perfmgr_trace_count(1, "touch");
|
|
touch_event = 1;
|
|
} else if (touch_event == 1 && action == 3) {
|
|
disable_touch_boost_timer();
|
|
update_eas_uclamp_min(EAS_UCLAMP_KIR_TOUCH, CGROUP_TA, 0);
|
|
update_userlimit_cpu_freq(CPU_KIR_TOUCH,
|
|
perfmgr_clusters, reset_freq);
|
|
perfmgr_trace_count(3, "touch");
|
|
touch_event = 2;
|
|
if (usrtch_debug)
|
|
pr_debug("touch timeout\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void notify_touch_up_timeout(struct work_struct *work)
|
|
{
|
|
mutex_lock(¬ify_lock);
|
|
|
|
update_eas_uclamp_min(EAS_UCLAMP_KIR_TOUCH, CGROUP_TA, 0);
|
|
update_userlimit_cpu_freq(CPU_KIR_TOUCH, perfmgr_clusters, reset_freq);
|
|
perfmgr_trace_count(0, "touch");
|
|
touch_event = 2;
|
|
if (usrtch_debug)
|
|
pr_debug("touch timeout\n");
|
|
|
|
mutex_unlock(¬ify_lock);
|
|
}
|
|
|
|
/*--------------------DEV OP------------------------*/
|
|
static ssize_t device_write(struct file *filp, const char *ubuf,
|
|
size_t cnt, loff_t *data)
|
|
{
|
|
char buf[32], cmd[32];
|
|
int arg1, arg2;
|
|
|
|
arg1 = 0;
|
|
arg2 = -1;
|
|
|
|
if (cnt >= sizeof(buf))
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(buf, ubuf, cnt))
|
|
return -EFAULT;
|
|
buf[cnt] = '\0';
|
|
|
|
if (sscanf(buf, "%31s %d %d", cmd, &arg1, &arg2) < 2)
|
|
return -EFAULT;
|
|
|
|
if (strncmp(cmd, "enable", 6) == 0)
|
|
switch_usrtch(arg1);
|
|
else if (strncmp(cmd, "eas_boost", 4) == 0)
|
|
switch_eas_boost(arg1);
|
|
else if (strncmp(cmd, "touch_opp", 9) == 0) {
|
|
if (arg1 >= 0 && arg1 <= 15)
|
|
switch_init_opp(arg1);
|
|
} else if (strncmp(cmd, "cluster_opp", 11) == 0) {
|
|
if (arg1 >= 0 && arg1 < perfmgr_clusters && arg2 >= -2 && arg2 <= 15)
|
|
switch_cluster_opp(arg1, arg2);
|
|
} else if (strncmp(cmd, "duration", 8) == 0) {
|
|
switch_init_duration(arg1);
|
|
} else if (strncmp(cmd, "active_time", 11) == 0) {
|
|
if (arg1 >= 0)
|
|
switch_active_time(arg1);
|
|
} else if (strncmp(cmd, "time_to_last_touch", 18) == 0) {
|
|
if (arg1 >= 0)
|
|
switch_time_to_last_touch(arg1);
|
|
} else if (strncmp(cmd, "deboost_when_render", 19) == 0) {
|
|
if (arg1 >= 0)
|
|
switch_deboost_when_render(arg1);
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
static int device_show(struct seq_file *m, void *v)
|
|
{
|
|
int i;
|
|
|
|
seq_puts(m, "-----------------------------------------------------\n");
|
|
seq_printf(m, "enable:\t%d\n", !usrtch_dbg);
|
|
seq_printf(m, "eas_boost:\t%d\n", touch_boost_value);
|
|
seq_printf(m, "touch_opp:\t%d\n", touch_boost_opp);
|
|
|
|
for (i = 0; i < perfmgr_clusters; i++)
|
|
seq_printf(m, "cluster_opp[%d]:\t%d\n",
|
|
i, cluster_opp[i]);
|
|
|
|
seq_printf(m, "duration(ns):\t%d\n", touch_boost_duration);
|
|
seq_printf(m, "active_time(us):\t%d\n", (int)active_time);
|
|
seq_printf(m, "time_to_last_touch(ms):\t%d\n", time_to_last_touch);
|
|
seq_printf(m, "deboost_when_render:\t%d\n", deboost_when_render);
|
|
seq_printf(m, "touch_event:\t%d\n", touch_event);
|
|
seq_puts(m, "-----------------------------------------------------\n");
|
|
return 0;
|
|
}
|
|
|
|
static int device_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, device_show, inode->i_private);
|
|
}
|
|
|
|
long usrtch_ioctl(unsigned int cmd, unsigned long arg)
|
|
{
|
|
ssize_t ret = 0;
|
|
|
|
mutex_lock(¬ify_lock);
|
|
|
|
switch (cmd) {
|
|
/*receive touch info*/
|
|
case FPSGO_TOUCH:
|
|
ret = notify_touch(arg);
|
|
break;
|
|
|
|
default:
|
|
pr_debug("non-game unknown cmd %u\n", cmd);
|
|
ret = -1;
|
|
goto ret_ioctl;
|
|
}
|
|
|
|
ret_ioctl:
|
|
mutex_unlock(¬ify_lock);
|
|
return ret >= 0 ? ret : 0;
|
|
}
|
|
|
|
static const struct file_operations Fops = {
|
|
.open = device_open,
|
|
.write = device_write,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
/*--------------------usrdebug OP------------------------*/
|
|
static ssize_t mt_usrdebug_write(struct file *filp, const char *ubuf,
|
|
size_t cnt, loff_t *data)
|
|
{
|
|
char buf[32];
|
|
int arg, ret, val;
|
|
|
|
arg = 0;
|
|
|
|
if (cnt >= sizeof(buf))
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(buf, ubuf, cnt))
|
|
return -EFAULT;
|
|
buf[cnt] = '\0';
|
|
ret = kstrtoint(buf, 10, &val);
|
|
|
|
if (ret < 0) {
|
|
pr_debug("ddr_write ret < 0\n");
|
|
return ret;
|
|
}
|
|
|
|
usrtch_debug = val;
|
|
return cnt;
|
|
}
|
|
|
|
static int mt_usrdebug_show(struct seq_file *m, void *v)
|
|
{
|
|
seq_printf(m, "usrdebug\t%d\n", usrtch_debug);
|
|
return 0;
|
|
}
|
|
|
|
static int mt_usrdebug_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, mt_usrdebug_show, inode->i_private);
|
|
}
|
|
static const struct file_operations fop = {
|
|
.open = mt_usrdebug_open,
|
|
.write = mt_usrdebug_write,
|
|
.read = seq_read,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
/*--------------------INIT------------------------*/
|
|
int init_utch(struct proc_dir_entry *parent)
|
|
{
|
|
struct proc_dir_entry *usrtch, *usrdebug, *usrtch_root;
|
|
int i;
|
|
int ret_val = 0;
|
|
|
|
pr_debug("Start to init usrtch driver\n");
|
|
|
|
/*create usr touch root procfs*/
|
|
usrtch_root = proc_mkdir("user", parent);
|
|
|
|
touch_boost_value = TOUCH_BOOST_EAS;
|
|
|
|
touch_event = 2;
|
|
touch_boost_opp = TOUCH_BOOST_OPP;
|
|
touch_boost_duration = TOUCH_TIMEOUT_NSEC;
|
|
active_time = TOUCH_FSTB_ACTIVE_US;
|
|
time_to_last_touch = TOUCH_TIME_TO_LAST_TOUCH_MS;
|
|
last_touch_time = ktime_get();
|
|
|
|
target_freq = kcalloc(perfmgr_clusters,
|
|
sizeof(struct cpu_ctrl_data), GFP_KERNEL);
|
|
reset_freq = kcalloc(perfmgr_clusters,
|
|
sizeof(struct cpu_ctrl_data), GFP_KERNEL);
|
|
cluster_opp = kcalloc(perfmgr_clusters,
|
|
sizeof(int), GFP_KERNEL);
|
|
|
|
for (i = 0; i < perfmgr_clusters; i++) {
|
|
target_freq[i].min =
|
|
mt_cpufreq_get_freq_by_idx(i, touch_boost_opp);
|
|
target_freq[i].max = reset_freq[i].min = reset_freq[i].max = -1;
|
|
cluster_opp[i] = -1; /* depend on touch_boost_opp */
|
|
}
|
|
mutex_init(¬ify_lock);
|
|
|
|
wq = create_singlethread_workqueue("mt_usrtch__work");
|
|
if (!wq) {
|
|
pr_debug("work create fail\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
hrtimer_init(&hrt1, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
|
hrt1.function = &mt_touch_timeout;
|
|
|
|
usrtch = proc_create("usrtch", 0664, usrtch_root, &Fops);
|
|
if (!usrtch) {
|
|
ret_val = -ENOMEM;
|
|
goto out_chrdev;
|
|
}
|
|
usrdebug = proc_create("usrdebug", 0664, usrtch_root, &fop);
|
|
if (!usrdebug) {
|
|
ret_val = -ENOMEM;
|
|
goto out_chrdev;
|
|
}
|
|
pr_debug("init usrtch driver done\n");
|
|
|
|
return 0;
|
|
|
|
out_chrdev:
|
|
destroy_workqueue(wq);
|
|
return ret_val;
|
|
}
|