mirror of
https://github.com/torvalds/linux.git
synced 2026-06-09 23:23:53 +02:00
rk3188:add status to dvfs dts node, modify rk3188-cpufreq.c to rockchip-cpufreq.c as common cpufreq.c
This commit is contained in:
parent
3cbd19d1c8
commit
a6dfabe2f6
|
|
@ -641,8 +641,8 @@ pwm3: pwm@20050030{
|
|||
|
||||
};
|
||||
dvfs {
|
||||
vd_cpu:
|
||||
vd_cpu {
|
||||
vd_arm:
|
||||
vd_arm {
|
||||
regulator_name="vdd_arm";
|
||||
suspend_volt=<1000>; //mV
|
||||
pd_a9 {
|
||||
|
|
@ -658,12 +658,13 @@ clk_core {
|
|||
1416000 1300000
|
||||
1608000 1350000
|
||||
>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
vd_core:
|
||||
vd_core {
|
||||
vd_logic:
|
||||
vd_logic {
|
||||
regulator_name="vdd_logic";
|
||||
suspend_volt=<1000>; //mV
|
||||
|
||||
|
|
@ -676,6 +677,7 @@ clk_gpu {
|
|||
300000 1200000
|
||||
400000 1200000
|
||||
>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -688,6 +690,7 @@ clk_ddr {
|
|||
300000 1200000
|
||||
400000 1200000
|
||||
>;
|
||||
status = "disable";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -54,11 +54,6 @@ config DVFS
|
|||
select PM_OPP
|
||||
select CPU_FREQ
|
||||
|
||||
config DDR_FREQ
|
||||
bool "Enable DDR frequency scaling"
|
||||
default n
|
||||
select DVFS
|
||||
|
||||
config RK_VPU
|
||||
tristate "VPU (Video Processing Unit) service driver in kernel"
|
||||
depends on ARCH_ROCKCHIP
|
||||
|
|
|
|||
|
|
@ -2,17 +2,15 @@ obj-y += common.o
|
|||
obj-y += cpu.o
|
||||
obj-y += rk3188.o
|
||||
obj-y += rk3288.o
|
||||
obj-y += ddr_freq.o
|
||||
obj-$(CONFIG_PM) += pm.o
|
||||
obj-$(CONFIG_RK_FPGA) += fpga.o
|
||||
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
|
||||
obj-$(CONFIG_SMP) += platsmp.o
|
||||
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||
obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o
|
||||
obj-$(CONFIG_CPU_FREQ) += rk3188-cpufreq.o
|
||||
obj-$(CONFIG_DVFS) += dvfs.o
|
||||
obj-$(CONFIG_RK_VCODEC) += vcodec_service.o
|
||||
obj-$(CONFIG_RK_VPU) += vpu_service.o
|
||||
obj-$(CONFIG_RK_PL330_DMA_TEST) += dma_memcpy_test.o
|
||||
obj-$(CONFIG_DDR_FREQ) += ddr_freq.o
|
||||
obj-$(CONFIG_BLOCK_RKNAND) += rknandbase.o
|
||||
|
||||
|
|
|
|||
|
|
@ -349,12 +349,14 @@ static int ddrfreq_init(void)
|
|||
{
|
||||
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
|
||||
int ret;
|
||||
|
||||
|
||||
ddr.clk_dvfs_node = clk_get_dvfs_node("clk_ddr");
|
||||
if (!ddr.clk_dvfs_node){
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_enable_dvfs(ddr.clk_dvfs_node);
|
||||
|
||||
init_waitqueue_head(&ddr.wait);
|
||||
ddr.mode = "normal";
|
||||
|
||||
|
|
|
|||
|
|
@ -1021,6 +1021,9 @@ int of_dvfs_init(void)
|
|||
DVFS_DBG("%s:pd(%s) register ok, parent vd:%s\n",
|
||||
__func__, pd->name, vd->name);
|
||||
for_each_available_child_of_node(pd_dev_node, clk_dev_node) {
|
||||
if (!of_device_is_available(clk_dev_node))
|
||||
continue;
|
||||
|
||||
dvfs_node = kzalloc(sizeof(struct dvfs_node), GFP_KERNEL);
|
||||
if (!dvfs_node)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -94,3 +94,4 @@ obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq.o
|
|||
obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o
|
||||
obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o
|
||||
obj-$(CONFIG_UNICORE32) += unicore2-cpufreq.o
|
||||
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip-cpufreq.o
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
#include <asm/unistd.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#define VERSION "2.2"
|
||||
#define VERSION "1.0"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define FREQ_DBG(fmt, args...) pr_debug(fmt, ## args)
|
||||
|
|
@ -55,11 +55,8 @@ static struct cpufreq_frequency_table default_freq_table[] = {
|
|||
{.frequency = 1608 * 1000, .index = 1350 * 1000},
|
||||
{.frequency = CPUFREQ_TABLE_END},
|
||||
};
|
||||
|
||||
static struct cpufreq_frequency_table *freq_table = default_freq_table;
|
||||
|
||||
/*********************************************************/
|
||||
|
||||
/* additional symantics for "relation" in cpufreq with pm */
|
||||
#define DISABLE_FURTHER_CPUFREQ 0x10
|
||||
#define ENABLE_FURTHER_CPUFREQ 0x20
|
||||
|
|
@ -68,25 +65,17 @@ static struct cpufreq_frequency_table *freq_table = default_freq_table;
|
|||
#define CPUFREQ_PRIVATE 0x100
|
||||
static int no_cpufreq_access;
|
||||
static unsigned int suspend_freq = 816 * 1000;
|
||||
#if defined(CONFIG_ARCH_RK3026)
|
||||
static unsigned int suspend_volt = 1100000; // 1.1V
|
||||
#else
|
||||
static unsigned int suspend_volt = 1000000; // 1V
|
||||
#endif
|
||||
static unsigned int low_battery_freq = 600 * 1000;
|
||||
//static unsigned int low_battery_capacity = 5; // 5%
|
||||
static unsigned int low_battery_capacity = 5; // 5%
|
||||
static bool is_booting = true;
|
||||
static struct workqueue_struct *freq_wq;
|
||||
static DEFINE_MUTEX(cpufreq_mutex);
|
||||
static bool gpu_is_mali400;
|
||||
struct dvfs_node *clk_cpu_dvfs_node = NULL;
|
||||
struct dvfs_node *clk_gpu_dvfs_node = NULL;
|
||||
struct dvfs_node *clk_ddr_dvfs_node = NULL;
|
||||
|
||||
static int cpufreq_scale_rate_for_dvfs(struct clk *clk, unsigned long rate);
|
||||
|
||||
/*******************************************************/
|
||||
static unsigned int rk3188_cpufreq_get(unsigned int cpu)
|
||||
static unsigned int cpufreq_get_rate(unsigned int cpu)
|
||||
{
|
||||
if (clk_cpu_dvfs_node)
|
||||
return clk_get_rate(clk_cpu_dvfs_node->clk) / 1000;
|
||||
|
|
@ -156,7 +145,7 @@ static struct cpufreq_frequency_table temp_limits_gpu_perf[] = {
|
|||
{.frequency = 1008 * 1000, .index = 0},
|
||||
};
|
||||
|
||||
static int rk3188_get_temp(void)
|
||||
static int get_temp(void)
|
||||
{
|
||||
return 60;
|
||||
}
|
||||
|
|
@ -187,7 +176,7 @@ static struct miscdevice sys_state_dev = {
|
|||
.minor = MISC_DYNAMIC_MINOR,
|
||||
};
|
||||
|
||||
static void rk3188_cpufreq_temp_limit_work_func(struct work_struct *work)
|
||||
static void cpufreq_temp_limit_work_func(struct work_struct *work)
|
||||
{
|
||||
static bool in_perf = false;
|
||||
struct cpufreq_policy *policy;
|
||||
|
|
@ -198,7 +187,7 @@ static void rk3188_cpufreq_temp_limit_work_func(struct work_struct *work)
|
|||
const struct cpufreq_frequency_table *limits_table = temp_limits[nr_cpus - 1];
|
||||
size_t limits_size = ARRAY_SIZE(temp_limits[nr_cpus - 1]);
|
||||
|
||||
temp = rk3188_get_temp();
|
||||
temp = get_temp();
|
||||
|
||||
if (sys_state == '1') {
|
||||
in_perf = true;
|
||||
|
|
@ -256,7 +245,7 @@ static void rk3188_cpufreq_temp_limit_work_func(struct work_struct *work)
|
|||
if (temp_limit_freq != new_freq) {
|
||||
unsigned int cur_freq;
|
||||
temp_limit_freq = new_freq;
|
||||
cur_freq = rk3188_cpufreq_get(0);
|
||||
cur_freq = cpufreq_get_rate(0);
|
||||
FREQ_DBG("temp limit %7d KHz cur %7d KHz\n", temp_limit_freq, cur_freq);
|
||||
if (cur_freq > temp_limit_freq) {
|
||||
policy = cpufreq_cpu_get(0);
|
||||
|
|
@ -268,9 +257,9 @@ static void rk3188_cpufreq_temp_limit_work_func(struct work_struct *work)
|
|||
queue_delayed_work_on(0, freq_wq, to_delayed_work(work), delay);
|
||||
}
|
||||
|
||||
static DECLARE_DELAYED_WORK(rk3188_cpufreq_temp_limit_work, rk3188_cpufreq_temp_limit_work_func);
|
||||
static DECLARE_DELAYED_WORK(cpufreq_temp_limit_work, cpufreq_temp_limit_work_func);
|
||||
|
||||
static int rk3188_cpufreq_notifier_policy(struct notifier_block *nb, unsigned long val, void *data)
|
||||
static int cpufreq_notifier_policy(struct notifier_block *nb, unsigned long val, void *data)
|
||||
{
|
||||
struct cpufreq_policy *policy = data;
|
||||
|
||||
|
|
@ -279,20 +268,20 @@ static int rk3188_cpufreq_notifier_policy(struct notifier_block *nb, unsigned lo
|
|||
|
||||
if (cpufreq_is_ondemand(policy)) {
|
||||
FREQ_DBG("queue work\n");
|
||||
queue_delayed_work_on(0, freq_wq, &rk3188_cpufreq_temp_limit_work, 0);
|
||||
queue_delayed_work_on(0, freq_wq, &cpufreq_temp_limit_work, 0);
|
||||
} else {
|
||||
FREQ_DBG("cancel work\n");
|
||||
cancel_delayed_work_sync(&rk3188_cpufreq_temp_limit_work);
|
||||
cancel_delayed_work_sync(&cpufreq_temp_limit_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block notifier_policy_block = {
|
||||
.notifier_call = rk3188_cpufreq_notifier_policy
|
||||
.notifier_call = cpufreq_notifier_policy
|
||||
};
|
||||
|
||||
static void rk3188_cpufreq_temp_limit_init(struct cpufreq_policy *policy)
|
||||
static void cpufreq_temp_limit_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int i;
|
||||
struct cpufreq_frequency_table *table;
|
||||
|
|
@ -311,250 +300,31 @@ static void rk3188_cpufreq_temp_limit_init(struct cpufreq_policy *policy)
|
|||
}
|
||||
misc_register(&sys_state_dev);
|
||||
if (cpufreq_is_ondemand(policy)) {
|
||||
queue_delayed_work_on(0, freq_wq, &rk3188_cpufreq_temp_limit_work, 0*HZ);
|
||||
queue_delayed_work_on(0, freq_wq, &cpufreq_temp_limit_work, 0*HZ);
|
||||
}
|
||||
cpufreq_register_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER);
|
||||
}
|
||||
|
||||
static void rk3188_cpufreq_temp_limit_exit(void)
|
||||
static void cpufreq_temp_limit_exit(void)
|
||||
{
|
||||
cpufreq_unregister_notifier(¬ifier_policy_block, CPUFREQ_POLICY_NOTIFIER);
|
||||
if (freq_wq)
|
||||
cancel_delayed_work(&rk3188_cpufreq_temp_limit_work);
|
||||
cancel_delayed_work(&cpufreq_temp_limit_work);
|
||||
}
|
||||
#else
|
||||
static inline void rk3188_cpufreq_temp_limit_init(struct cpufreq_policy *policy) {}
|
||||
static inline void rk3188_cpufreq_temp_limit_exit(void) {}
|
||||
static inline void cpufreq_temp_limit_init(struct cpufreq_policy *policy) {}
|
||||
static inline void cpufreq_temp_limit_exit(void) {}
|
||||
#endif
|
||||
|
||||
/************************************dvfs tst************************************/
|
||||
//#define CPU_FREQ_DVFS_TST
|
||||
#ifdef CPU_FREQ_DVFS_TST
|
||||
static unsigned int freq_dvfs_tst_rate;
|
||||
static int test_count;
|
||||
#define TEST_FRE_NUM 11
|
||||
static int test_tlb_rate[TEST_FRE_NUM] = { 504, 1008, 504, 1200, 252, 816, 1416, 252, 1512, 252, 816 };
|
||||
//static int test_tlb_rate[TEST_FRE_NUM]={504,1008,504,1200,252,816,1416,126,1512,126,816};
|
||||
|
||||
#define TEST_GPU_NUM 3
|
||||
|
||||
static int test_tlb_gpu[TEST_GPU_NUM] = { 360, 400, 180 };
|
||||
static int test_tlb_ddr[TEST_GPU_NUM] = { 401, 200, 500 };
|
||||
|
||||
static int gpu_ddr = 0;
|
||||
|
||||
static void rk3188_cpufreq_dvsf_tst_work_func(struct work_struct *work)
|
||||
{
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
|
||||
|
||||
gpu_ddr++;
|
||||
#if 0
|
||||
FREQ_LOG("cpufreq_dvsf_tst,ddr%u,gpu%u\n",
|
||||
test_tlb_ddr[gpu_ddr % TEST_GPU_NUM],
|
||||
test_tlb_gpu[gpu_ddr % TEST_GPU_NUM]);
|
||||
clk_set_rate(ddr_clk, test_tlb_ddr[gpu_ddr % TEST_GPU_NUM] * 1000 * 1000);
|
||||
clk_set_rate(gpu_clk, test_tlb_gpu[gpu_ddr % TEST_GPU_NUM] * 1000 * 1000);
|
||||
#endif
|
||||
|
||||
test_count++;
|
||||
freq_dvfs_tst_rate = test_tlb_rate[test_count % TEST_FRE_NUM] * 1000;
|
||||
printk("cpufreq_dvsf_tst,cpu set rate %d\n", freq_dvfs_tst_rate);
|
||||
cpufreq_driver_target(policy, policy->cur, CPUFREQ_RELATION_L);
|
||||
cpufreq_cpu_put(policy);
|
||||
|
||||
queue_delayed_work_on(0, freq_wq, to_delayed_work(work), msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
static DECLARE_DELAYED_WORK(rk3188_cpufreq_dvsf_tst_work, rk3188_cpufreq_dvsf_tst_work_func);
|
||||
#endif /* CPU_FREQ_DVFS_TST */
|
||||
|
||||
/***********************************************************************/
|
||||
static int rk3188_cpufreq_verify(struct cpufreq_policy *policy)
|
||||
static int cpufreq_verify(struct cpufreq_policy *policy)
|
||||
{
|
||||
if (!freq_table)
|
||||
return -EINVAL;
|
||||
return cpufreq_frequency_table_verify(policy, freq_table);
|
||||
}
|
||||
|
||||
static int rk3188_cpufreq_init_cpu0(struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int i;
|
||||
//struct cpufreq_frequency_table *table_adjust;
|
||||
|
||||
gpu_is_mali400 = cpu_is_rk3188();
|
||||
|
||||
clk_gpu_dvfs_node = clk_get_dvfs_node("clk_gpu");
|
||||
if (!clk_gpu_dvfs_node){
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_ddr_dvfs_node = clk_get_dvfs_node("clk_ddr");
|
||||
if (!clk_ddr_dvfs_node){
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_cpu_dvfs_node = clk_get_dvfs_node("clk_core");
|
||||
if (!clk_cpu_dvfs_node){
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
//table_adjust = dvfs_get_freq_volt_table(cpu_clk);
|
||||
//dvfs_adjust_table_lmtvolt(cpu_clk, table_adjust);
|
||||
//table_adjust = dvfs_get_freq_volt_table(gpu_clk);
|
||||
//dvfs_adjust_table_lmtvolt(gpu_clk, table_adjust);
|
||||
|
||||
clk_enable_dvfs(clk_gpu_dvfs_node);
|
||||
if (gpu_is_mali400)
|
||||
dvfs_clk_enable_limit(clk_gpu_dvfs_node, 133000000, 600000000);
|
||||
|
||||
clk_enable_dvfs(clk_ddr_dvfs_node);
|
||||
|
||||
dvfs_clk_register_set_rate_callback(clk_cpu_dvfs_node, cpufreq_scale_rate_for_dvfs);
|
||||
freq_table = dvfs_get_freq_volt_table(clk_cpu_dvfs_node);
|
||||
if (freq_table == NULL) {
|
||||
freq_table = default_freq_table;
|
||||
} else {
|
||||
int v = INT_MAX;
|
||||
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
if (freq_table[i].index >= suspend_volt && v > freq_table[i].index) {
|
||||
suspend_freq = freq_table[i].frequency;
|
||||
v = freq_table[i].index;
|
||||
}
|
||||
}
|
||||
}
|
||||
low_battery_freq = get_freq_from_table(low_battery_freq);
|
||||
clk_enable_dvfs(clk_cpu_dvfs_node);
|
||||
/*if(rk_tflag()){
|
||||
#define RK3188_T_LIMIT_FREQ (1416 * 1000)
|
||||
dvfs_clk_enable_limit(cpu_clk, 0, RK3188_T_LIMIT_FREQ * 1000);
|
||||
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
if (freq_table[i].frequency > RK3188_T_LIMIT_FREQ) {
|
||||
printk("cpufreq: delete arm freq(%u)\n", freq_table[i].frequency);
|
||||
freq_table[i].frequency = CPUFREQ_TABLE_END;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
freq_wq = alloc_workqueue("rk3188_cpufreqd", WQ_NON_REENTRANT | WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 1);
|
||||
rk3188_cpufreq_temp_limit_init(policy);
|
||||
#ifdef CPU_FREQ_DVFS_TST
|
||||
queue_delayed_work(freq_wq, &rk3188_cpufreq_dvsf_tst_work, msecs_to_jiffies(20 * 1000));
|
||||
#endif
|
||||
|
||||
printk("rk3188 cpufreq version " VERSION ", suspend freq %d MHz\n", suspend_freq / 1000);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int rk3188_cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
static int cpu0_err;
|
||||
|
||||
if (policy->cpu == 0) {
|
||||
cpu0_err = rk3188_cpufreq_init_cpu0(policy);
|
||||
}
|
||||
|
||||
if (cpu0_err)
|
||||
return cpu0_err;
|
||||
|
||||
//set freq min max
|
||||
cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
//sys nod
|
||||
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
|
||||
|
||||
|
||||
policy->cur = rk3188_cpufreq_get(0);
|
||||
|
||||
policy->cpuinfo.transition_latency = 40 * NSEC_PER_USEC; // make ondemand default sampling_rate to 40000
|
||||
|
||||
/*
|
||||
* On SMP configuartion, both processors share the voltage
|
||||
* and clock. So both CPUs needs to be scaled together and hence
|
||||
* needs software co-ordination. Use cpufreq affected_cpus
|
||||
* interface to handle this scenario. Additional is_smp() check
|
||||
* is to keep SMP_ON_UP build working.
|
||||
*/
|
||||
if (is_smp())
|
||||
cpumask_setall(policy->cpus);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int rk3188_cpufreq_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
if (policy->cpu != 0)
|
||||
return 0;
|
||||
|
||||
cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
// clk_put(clk_cpu_dvfs_node->clk);
|
||||
rk3188_cpufreq_temp_limit_exit();
|
||||
if (freq_wq) {
|
||||
flush_workqueue(freq_wq);
|
||||
destroy_workqueue(freq_wq);
|
||||
freq_wq = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct freq_attr *rk3188_cpufreq_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_POWER_SUPPLY
|
||||
extern int rk_get_system_battery_capacity(void);
|
||||
#else
|
||||
static int rk_get_system_battery_capacity(void) { return 100; }
|
||||
#endif
|
||||
|
||||
static unsigned int cpufreq_scale_limit(unsigned int target_freq, struct cpufreq_policy *policy, bool is_private)
|
||||
{
|
||||
bool is_ondemand = cpufreq_is_ondemand(policy);
|
||||
|
||||
#ifdef CPU_FREQ_DVFS_TST
|
||||
if (freq_dvfs_tst_rate) {
|
||||
target_freq = freq_dvfs_tst_rate;
|
||||
freq_dvfs_tst_rate = 0;
|
||||
return target_freq;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!is_ondemand)
|
||||
return target_freq;
|
||||
|
||||
if (is_booting) {
|
||||
s64 boottime_ms = ktime_to_ms(ktime_get_boottime());
|
||||
if (boottime_ms > 60 * MSEC_PER_SEC) {
|
||||
is_booting = false;
|
||||
}/* else if (target_freq > low_battery_freq &&
|
||||
rk_get_system_battery_capacity() <= low_battery_capacity) {
|
||||
target_freq = low_battery_freq;
|
||||
}*/
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP
|
||||
{
|
||||
static unsigned int ondemand_target = 816 * 1000;
|
||||
if (is_private)
|
||||
target_freq = ondemand_target;
|
||||
else
|
||||
ondemand_target = target_freq;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the new frequency is more than the thermal max allowed
|
||||
* frequency, go ahead and scale the mpu device to proper frequency.
|
||||
*/
|
||||
target_freq = min(target_freq, temp_limit_freq);
|
||||
#endif
|
||||
|
||||
return target_freq;
|
||||
}
|
||||
|
||||
static int cpufreq_scale_rate_for_dvfs(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
|
||||
unsigned int i;
|
||||
int ret;
|
||||
struct cpufreq_freqs freqs;
|
||||
|
|
@ -596,9 +366,148 @@ static int cpufreq_scale_rate_for_dvfs(struct clk *clk, unsigned long rate)
|
|||
|
||||
}
|
||||
|
||||
static int rk3188_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation)
|
||||
{
|
||||
|
||||
static int cpufreq_init_cpu0(struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int i;
|
||||
gpu_is_mali400 = cpu_is_rk3188();
|
||||
|
||||
clk_gpu_dvfs_node = clk_get_dvfs_node("clk_gpu");
|
||||
if (clk_gpu_dvfs_node){
|
||||
clk_enable_dvfs(clk_gpu_dvfs_node);
|
||||
if (gpu_is_mali400)
|
||||
dvfs_clk_enable_limit(clk_gpu_dvfs_node, 133000000, 600000000);
|
||||
}
|
||||
|
||||
clk_cpu_dvfs_node = clk_get_dvfs_node("clk_core");
|
||||
if (!clk_cpu_dvfs_node){
|
||||
return -EINVAL;
|
||||
}
|
||||
dvfs_clk_register_set_rate_callback(clk_cpu_dvfs_node, cpufreq_scale_rate_for_dvfs);
|
||||
freq_table = dvfs_get_freq_volt_table(clk_cpu_dvfs_node);
|
||||
if (freq_table == NULL) {
|
||||
freq_table = default_freq_table;
|
||||
} else {
|
||||
int v = INT_MAX;
|
||||
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
|
||||
if (freq_table[i].index >= suspend_volt && v > freq_table[i].index) {
|
||||
suspend_freq = freq_table[i].frequency;
|
||||
v = freq_table[i].index;
|
||||
}
|
||||
}
|
||||
}
|
||||
low_battery_freq = get_freq_from_table(low_battery_freq);
|
||||
clk_enable_dvfs(clk_cpu_dvfs_node);
|
||||
|
||||
freq_wq = alloc_workqueue("cpufreq", WQ_NON_REENTRANT | WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 1);
|
||||
cpufreq_temp_limit_init(policy);
|
||||
|
||||
printk("cpufreq version " VERSION ", suspend freq %d MHz\n", suspend_freq / 1000);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
static int cpu0_err;
|
||||
|
||||
if (policy->cpu == 0) {
|
||||
cpu0_err = cpufreq_init_cpu0(policy);
|
||||
}
|
||||
|
||||
if (cpu0_err)
|
||||
return cpu0_err;
|
||||
|
||||
//set freq min max
|
||||
cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
//sys nod
|
||||
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
|
||||
|
||||
|
||||
policy->cur = clk_get_rate(clk_cpu_dvfs_node->clk) / 1000;
|
||||
|
||||
policy->cpuinfo.transition_latency = 40 * NSEC_PER_USEC; // make ondemand default sampling_rate to 40000
|
||||
|
||||
/*
|
||||
* On SMP configuartion, both processors share the voltage
|
||||
* and clock. So both CPUs needs to be scaled together and hence
|
||||
* needs software co-ordination. Use cpufreq affected_cpus
|
||||
* interface to handle this scenario. Additional is_smp() check
|
||||
* is to keep SMP_ON_UP build working.
|
||||
*/
|
||||
if (is_smp())
|
||||
cpumask_setall(policy->cpus);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int cpufreq_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
if (policy->cpu != 0)
|
||||
return 0;
|
||||
|
||||
cpufreq_frequency_table_cpuinfo(policy, freq_table);
|
||||
clk_put_dvfs_node(clk_cpu_dvfs_node);
|
||||
cpufreq_temp_limit_exit();
|
||||
if (freq_wq) {
|
||||
flush_workqueue(freq_wq);
|
||||
destroy_workqueue(freq_wq);
|
||||
freq_wq = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct freq_attr *cpufreq_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
NULL,
|
||||
};
|
||||
|
||||
//#ifdef CONFIG_POWER_SUPPLY
|
||||
#if 0
|
||||
extern int rk_get_system_battery_capacity(void);
|
||||
#else
|
||||
static int rk_get_system_battery_capacity(void) { return 100; }
|
||||
#endif
|
||||
|
||||
static unsigned int cpufreq_scale_limit(unsigned int target_freq, struct cpufreq_policy *policy, bool is_private)
|
||||
{
|
||||
bool is_ondemand = cpufreq_is_ondemand(policy);
|
||||
|
||||
if (!is_ondemand)
|
||||
return target_freq;
|
||||
|
||||
if (is_booting) {
|
||||
s64 boottime_ms = ktime_to_ms(ktime_get_boottime());
|
||||
if (boottime_ms > 60 * MSEC_PER_SEC) {
|
||||
is_booting = false;
|
||||
} else if (target_freq > low_battery_freq &&
|
||||
rk_get_system_battery_capacity() <= low_battery_capacity) {
|
||||
target_freq = low_battery_freq;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP
|
||||
{
|
||||
static unsigned int ondemand_target = 816 * 1000;
|
||||
if (is_private)
|
||||
target_freq = ondemand_target;
|
||||
else
|
||||
ondemand_target = target_freq;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the new frequency is more than the thermal max allowed
|
||||
* frequency, go ahead and scale the mpu device to proper frequency.
|
||||
*/
|
||||
target_freq = min(target_freq, temp_limit_freq);
|
||||
#endif
|
||||
|
||||
return target_freq;
|
||||
}
|
||||
|
||||
static int cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation)
|
||||
{
|
||||
unsigned int i, new_freq = target_freq, new_rate, cur_rate;
|
||||
int ret = 0;
|
||||
bool is_private;
|
||||
|
|
@ -634,7 +543,7 @@ static int rk3188_cpufreq_target(struct cpufreq_policy *policy, unsigned int tar
|
|||
new_freq = cpufreq_scale_limit(new_freq, policy, is_private);
|
||||
|
||||
new_rate = new_freq * 1000;
|
||||
cur_rate = clk_get_rate(clk_cpu_dvfs_node->clk);
|
||||
cur_rate = dvfs_clk_get_rate(clk_cpu_dvfs_node);
|
||||
FREQ_LOG("req = %7u new = %7u (was = %7u)\n", target_freq, new_freq, cur_rate / 1000);
|
||||
if (new_rate == cur_rate)
|
||||
goto out;
|
||||
|
|
@ -647,7 +556,7 @@ static int rk3188_cpufreq_target(struct cpufreq_policy *policy, unsigned int tar
|
|||
|
||||
}
|
||||
|
||||
static int rk3188_cpufreq_pm_notifier_event(struct notifier_block *this, unsigned long event, void *ptr)
|
||||
static int cpufreq_pm_notifier_event(struct notifier_block *this, unsigned long event, void *ptr)
|
||||
{
|
||||
int ret = NOTIFY_DONE;
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
|
||||
|
|
@ -678,11 +587,11 @@ static int rk3188_cpufreq_pm_notifier_event(struct notifier_block *this, unsigne
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct notifier_block rk3188_cpufreq_pm_notifier = {
|
||||
.notifier_call = rk3188_cpufreq_pm_notifier_event,
|
||||
static struct notifier_block cpufreq_pm_notifier = {
|
||||
.notifier_call = cpufreq_pm_notifier_event,
|
||||
};
|
||||
|
||||
static int rk3188_cpufreq_reboot_notifier_event(struct notifier_block *this, unsigned long event, void *ptr)
|
||||
static int cpufreq_reboot_notifier_event(struct notifier_block *this, unsigned long event, void *ptr)
|
||||
{
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
|
||||
|
||||
|
|
@ -695,28 +604,26 @@ static int rk3188_cpufreq_reboot_notifier_event(struct notifier_block *this, uns
|
|||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block rk3188_cpufreq_reboot_notifier = {
|
||||
.notifier_call = rk3188_cpufreq_reboot_notifier_event,
|
||||
static struct notifier_block cpufreq_reboot_notifier = {
|
||||
.notifier_call = cpufreq_reboot_notifier_event,
|
||||
};
|
||||
|
||||
static struct cpufreq_driver rk3188_cpufreq_driver = {
|
||||
static struct cpufreq_driver cpufreq_driver = {
|
||||
.flags = CPUFREQ_CONST_LOOPS,
|
||||
.verify = rk3188_cpufreq_verify,
|
||||
.target = rk3188_cpufreq_target,
|
||||
.get = rk3188_cpufreq_get,
|
||||
.init = rk3188_cpufreq_init,
|
||||
.exit = rk3188_cpufreq_exit,
|
||||
.name = "rk3188",
|
||||
.attr = rk3188_cpufreq_attr,
|
||||
.verify = cpufreq_verify,
|
||||
.target = cpufreq_target,
|
||||
.get = cpufreq_get_rate,
|
||||
.init = cpufreq_init,
|
||||
.exit = cpufreq_exit,
|
||||
.name = "rockchip",
|
||||
.attr = cpufreq_attr,
|
||||
};
|
||||
|
||||
static int __init rk3188_cpufreq_driver_init(void)
|
||||
static int __init cpufreq_driver_init(void)
|
||||
{
|
||||
if (!cpu_is_rk3188())
|
||||
return 0;
|
||||
register_pm_notifier(&rk3188_cpufreq_pm_notifier);
|
||||
register_reboot_notifier(&rk3188_cpufreq_reboot_notifier);
|
||||
return cpufreq_register_driver(&rk3188_cpufreq_driver);
|
||||
register_pm_notifier(&cpufreq_pm_notifier);
|
||||
register_reboot_notifier(&cpufreq_reboot_notifier);
|
||||
return cpufreq_register_driver(&cpufreq_driver);
|
||||
}
|
||||
|
||||
device_initcall(rk3188_cpufreq_driver_init);
|
||||
device_initcall(cpufreq_driver_init);
|
||||
Loading…
Reference in New Issue
Block a user