254 lines
5.3 KiB
C
254 lines
5.3 KiB
C
|
#include <linux/input/input_booster.h>
|
||
|
#include <linux/device.h>
|
||
|
#include <linux/syscalls.h>
|
||
|
|
||
|
int current_hmp_boost = 0;
|
||
|
struct pm_qos_request lpm_bias_pm_qos_request;
|
||
|
|
||
|
static struct device *dev;
|
||
|
struct icc_path *path_touch_bw;
|
||
|
int register_ddr;
|
||
|
|
||
|
#define MHZ_TO_BPS(mhz, w) ((uint64_t)mhz * 1000 * 1000 * w)
|
||
|
#define MHZ_TO_KBPS(mhz, w) ((uint64_t)mhz * 1000 * w)
|
||
|
|
||
|
//Refer to "include/dt-bindings/interconnect/qcom,lahaina.h"
|
||
|
#define MASTER_APPSS_PROC 2
|
||
|
#define SLAVE_EBI1 512
|
||
|
|
||
|
void set_hmp(int level);
|
||
|
|
||
|
#ifndef CONFIG_CPU_FREQ_LIMIT
|
||
|
#define DVFS_TOUCH_ID 0
|
||
|
int set_freq_limit(unsigned long id, unsigned int freq)
|
||
|
{
|
||
|
pr_err("%s is not yet implemented\n", __func__);
|
||
|
return 0;
|
||
|
}
|
||
|
#else
|
||
|
/* TEMP: for KPI */
|
||
|
#define DVFS_TOUCH_ID 1
|
||
|
#endif
|
||
|
|
||
|
#if defined(CONFIG_ARCH_LAHAINA)
|
||
|
#define NUM_BUS_TABLE 14
|
||
|
#define BUS_W 4 /* SM8350 DDR Voting('w' for DDR is 4) */
|
||
|
|
||
|
int ab_ib_bus_vectors[NUM_BUS_TABLE][2] = {
|
||
|
//{ab, ib}
|
||
|
{0, 0}, /* 0 */
|
||
|
{0, 200}, /* 1 */
|
||
|
{0, 451}, /* 2 */
|
||
|
{0, 547}, /* 3 */
|
||
|
{0, 681}, /* 4 */
|
||
|
{0, 768}, /* 5 */
|
||
|
|
||
|
{0, 1017}, /* 6 */
|
||
|
{0, 1353}, /* 7 */
|
||
|
{0, 1555}, /* 8 */
|
||
|
{0, 1708}, /* 9 */
|
||
|
{0, 2092}, /* 10 */
|
||
|
{0, 2133}, /* 11 */
|
||
|
{0, 2736}, /* 12 */
|
||
|
{0, 3196} /* 13 */
|
||
|
};
|
||
|
#else
|
||
|
#define NUM_BUS_TABLE 1
|
||
|
#define BUS_W 0
|
||
|
|
||
|
int ab_ib_bus_vectors[NUM_BUS_TABLE][2] = {
|
||
|
{0, 0}, /* 0 */
|
||
|
};
|
||
|
#endif //set null for other chipset
|
||
|
|
||
|
|
||
|
struct msm_touch_bus_vector_bps {
|
||
|
uint32_t ab;
|
||
|
uint32_t ib;
|
||
|
};
|
||
|
struct msm_touch_bus_vector_bps touch_bus_vectors_bps[NUM_BUS_TABLE];
|
||
|
void fill_bus_vector(void)
|
||
|
{
|
||
|
int i = 0;
|
||
|
|
||
|
for (i = 0; i < NUM_BUS_TABLE; i++) {
|
||
|
touch_bus_vectors_bps[i].ab = ab_ib_bus_vectors[i][0];
|
||
|
touch_bus_vectors_bps[i].ib = MHZ_TO_KBPS(ab_ib_bus_vectors[i][1], BUS_W);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int trans_freq_to_idx(long request_ddr_freq)
|
||
|
{
|
||
|
int i = 0;
|
||
|
|
||
|
if (request_ddr_freq <= 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// in case of null table, return 0
|
||
|
if (NUM_BUS_TABLE == 1) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < NUM_BUS_TABLE-1; i++) {
|
||
|
if (request_ddr_freq > ab_ib_bus_vectors[i][1] &&
|
||
|
request_ddr_freq <= ab_ib_bus_vectors[i+1][1]) {
|
||
|
return (i+1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return i+1;
|
||
|
}
|
||
|
|
||
|
void ib_set_booster(long* qos_values)
|
||
|
{
|
||
|
long value = -1;
|
||
|
int ddr_idx = 0;
|
||
|
int res_type =0;
|
||
|
int cur_res_idx;
|
||
|
int rc = 0;
|
||
|
|
||
|
for (res_type = 0; res_type < allowed_res_count; res_type++) {
|
||
|
|
||
|
cur_res_idx = allowed_resources[res_type];
|
||
|
value = qos_values[cur_res_idx];
|
||
|
|
||
|
if (value <= 0)
|
||
|
continue;
|
||
|
|
||
|
switch (cur_res_idx) {
|
||
|
case CPUFREQ:
|
||
|
set_freq_limit(DVFS_TOUCH_ID, value);
|
||
|
pr_booster("%s :: cpufreq value : %ld", __func__, value);
|
||
|
break;
|
||
|
case DDRFREQ:
|
||
|
ddr_idx = trans_freq_to_idx(value);
|
||
|
pr_booster("%s :: bus value : %ld, %u", __func__, value, touch_bus_vectors_bps[ddr_idx].ib);
|
||
|
if (register_ddr)
|
||
|
rc = icc_set_bw(path_touch_bw,
|
||
|
touch_bus_vectors_bps[ddr_idx].ab, touch_bus_vectors_bps[ddr_idx].ib);
|
||
|
break;
|
||
|
case HMPBOOST:
|
||
|
set_hmp(value);
|
||
|
pr_booster("%s :: hmpboost value : %ld", __func__, value);
|
||
|
break;
|
||
|
case LPMBIAS:
|
||
|
pm_qos_update_request(&lpm_bias_pm_qos_request, value);
|
||
|
pr_booster("%s :: LPM Bias value : %ld", __func__, value);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ib_release_booster(long *rel_flags)
|
||
|
{
|
||
|
//cpufreq : -1, ddrfreq : 0, HMP : 0, lpm_bias = 0
|
||
|
int ddr_idx;
|
||
|
int flag;
|
||
|
int rc = 0;
|
||
|
int value;
|
||
|
|
||
|
int res_type = 0;
|
||
|
int cur_res_idx;
|
||
|
|
||
|
for (res_type = 0; res_type < allowed_res_count; res_type++) {
|
||
|
|
||
|
cur_res_idx = allowed_resources[res_type];
|
||
|
flag = rel_flags[cur_res_idx];
|
||
|
if (flag <= 0)
|
||
|
continue;
|
||
|
|
||
|
value = release_val[cur_res_idx];
|
||
|
|
||
|
switch (cur_res_idx) {
|
||
|
case CPUFREQ:
|
||
|
set_freq_limit(DVFS_TOUCH_ID, value);
|
||
|
break;
|
||
|
case DDRFREQ:
|
||
|
ddr_idx = trans_freq_to_idx(value);
|
||
|
if (register_ddr)
|
||
|
rc = icc_set_bw(path_touch_bw,
|
||
|
touch_bus_vectors_bps[ddr_idx].ab, touch_bus_vectors_bps[ddr_idx].ib);
|
||
|
break;
|
||
|
case HMPBOOST:
|
||
|
set_hmp(value);
|
||
|
break;
|
||
|
case LPMBIAS:
|
||
|
pm_qos_update_request(&lpm_bias_pm_qos_request, value);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef USE_HMP_BOOST
|
||
|
void set_hmp(int level)
|
||
|
{
|
||
|
if (level != current_hmp_boost) {
|
||
|
if (level == 0) {
|
||
|
level = -current_hmp_boost;
|
||
|
current_hmp_boost = 0;
|
||
|
} else {
|
||
|
current_hmp_boost = level;
|
||
|
}
|
||
|
pr_booster("[Input Booster2] ****** hmp_boost : %d ( %s )\n", level, __func__);
|
||
|
if (sched_set_boost(level) < 0)
|
||
|
pr_err("[Input Booster2] ****** !!! fail to HMP !!!\n");
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
void set_hmp(int level)
|
||
|
{
|
||
|
pr_booster("It does not use hmp\n", level, __func__);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
static void icc_release(struct device *dev)
|
||
|
{
|
||
|
pr_booster("Release icc path of device\n");
|
||
|
}
|
||
|
|
||
|
int input_booster_init_vendor(void)
|
||
|
{
|
||
|
|
||
|
int bus_ret = 0;
|
||
|
|
||
|
//Bus boost factors initailized
|
||
|
dev = kzalloc(sizeof(struct device), GFP_KERNEL);
|
||
|
dev_set_name(dev, "input_booster");
|
||
|
dev->release = icc_release;
|
||
|
device_register(dev);
|
||
|
|
||
|
if (!register_ddr) {
|
||
|
path_touch_bw = icc_get(dev, MASTER_APPSS_PROC, SLAVE_EBI1);
|
||
|
if (IS_ERR(path_touch_bw)) {
|
||
|
bus_ret = PTR_ERR(path_touch_bw);
|
||
|
if (bus_ret != -EPROBE_DEFER)
|
||
|
pr_err("Failed to get path from input bus booster. ret=%d\n", bus_ret);
|
||
|
} else {
|
||
|
pr_info(ITAG" Making icc path for bus success");
|
||
|
register_ddr = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fill_bus_vector();
|
||
|
pm_qos_add_request(&lpm_bias_pm_qos_request,
|
||
|
PM_QOS_BIAS_HYST, PM_QOS_BIAS_HYST_DEFAULT_VALUE);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
void input_booster_exit_vendor(void)
|
||
|
{
|
||
|
if (register_ddr)
|
||
|
icc_put(path_touch_bw);
|
||
|
|
||
|
device_unregister(dev);
|
||
|
kfree(dev);
|
||
|
pm_qos_remove_request(&lpm_bias_pm_qos_request);
|
||
|
}
|
||
|
|
||
|
MODULE_LICENSE("GPL");
|