add video_state function which can reduce reset ddr rate when playing video

This commit is contained in:
xxx
2012-08-13 21:13:29 -07:00
parent 1fb22447a5
commit 6bcf52d724
8 changed files with 311 additions and 47 deletions

2
arch/arm/mach-rk30/Makefile Executable file → Normal file
View File

@@ -16,7 +16,7 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o video_state.o
obj-$(CONFIG_DVFS) += dvfs.o
obj-$(CONFIG_DDR_FREQ) += ddr_freq.o
obj-$(CONFIG_RK30_I2C_INSRAM) += i2c_sram.o

View File

@@ -26,6 +26,7 @@
#include "clock.h"
#include <mach/pmu.h>
#include <mach/dvfs.h>
#include <mach/ddr.h>
#define MHZ (1000*1000)
#define KHZ (1000)
@@ -1115,12 +1116,24 @@ static int ddr_clk_set_rate(struct clk *c, unsigned long rate)
return 0;
}
static long ddr_clk_round_rate(struct clk *clk, unsigned long rate)
{
return ddr_set_pll(rate/MHZ,0)*MHZ;
}
static unsigned long ddr_clk_recalc_rate(struct clk *clk)
{
u32 shift = get_cru_bits(clk->clksel_con,clk->div_mask,clk->div_shift);
unsigned long rate = clk->parent->recalc(clk->parent)>> shift;
pr_debug("%s new clock rate is %lu (shift %u)\n", clk->name, rate, shift);
return rate;
}
static struct clk *clk_ddr_parents[2] = {&ddr_pll_clk, &general_pll_clk};
static struct clk clk_ddr = {
.name = "ddr",
.parent = &ddr_pll_clk,
.recalc = clksel_recalc_shift,
.recalc = ddr_clk_recalc_rate,
.set_rate = ddr_clk_set_rate,
.round_rate = ddr_clk_round_rate,
.clksel_con = CRU_CLKSELS_CON(26),
//CRU_DIV_SET(0x3,0,4),
//CRU_SRC_SET(1,8),

17
arch/arm/mach-rk30/cpufreq.c Executable file → Normal file
View File

@@ -31,6 +31,8 @@
#include <linux/earlysuspend.h>
#include <asm/unistd.h>
#include <asm/uaccess.h>
#include <mach/ddr.h>
#include <linux/cpu.h>
#ifdef DEBUG
#define FREQ_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args)
#define FREQ_PRINTK_LOG(fmt, args...) pr_debug(fmt, ## args)
@@ -68,6 +70,7 @@ static struct clk *cpu_gpll;
static DEFINE_MUTEX(cpufreq_mutex);
static struct clk *gpu_clk;
static struct clk *ddr_clk;
#define GPU_MAX_RATE 350*1000*1000
static int cpufreq_scale_rate_for_dvfs(struct clk *clk, unsigned long rate, dvfs_set_rate_callback set_rate);
@@ -220,11 +223,20 @@ static int rk30_verify_speed(struct cpufreq_policy *policy)
return cpufreq_frequency_table_verify(policy, freq_table);
}
uint32_t ddr_set_rate(uint32_t nMHz);
int ddr_scale_rate_for_dvfs(struct clk *clk, unsigned long rate, dvfs_set_rate_callback set_rate)
{
#if defined (CONFIG_DDR_FREQ)
ddr_set_rate(rate/(1000*1000));
#endif
return 0;
}
static int rk30_cpu_init(struct cpufreq_policy *policy)
{
if (policy->cpu == 0) {
int i;
struct clk *ddr_clk;
gpu_clk = clk_get(NULL, "gpu");
if (!IS_ERR(gpu_clk))
@@ -233,8 +245,9 @@ static int rk30_cpu_init(struct cpufreq_policy *policy)
ddr_clk = clk_get(NULL, "ddr");
if (!IS_ERR(ddr_clk))
{
dvfs_clk_register_set_rate_callback(ddr_clk, ddr_scale_rate_for_dvfs);
clk_enable_dvfs(ddr_clk);
clk_set_rate(ddr_clk,clk_get_rate(ddr_clk)-1);
//clk_set_rate(ddr_clk,clk_get_rate(ddr_clk)-1);
}
cpu_clk = clk_get(NULL, "cpu");

2
arch/arm/mach-rk30/ddr.c Executable file → Normal file
View File

@@ -2978,7 +2978,6 @@ uint32_t __sramfunc ddr_change_freq(uint32_t nMHz)
DDR_RESTORE_SP(save_sp);
local_fiq_enable();
local_irq_restore(flags);
clk_set_rate(clk_get(NULL, "ddr_pll"), 0);
return ret;
}
@@ -3221,6 +3220,7 @@ int ddr_init(uint32_t dram_speed_bin, uint32_t freq)
ddr_adjust_config(mem_type);
value=ddr_change_freq(freq);
clk_set_rate(clk_get(NULL, "ddr_pll"), 0);
ddr_print("init success!!! freq=%dMHz\n", value);
for(value=0;value<4;value++)

130
arch/arm/mach-rk30/ddr_freq.c Executable file → Normal file
View File

@@ -4,82 +4,132 @@
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/clk.h>
#define ddr_print(x...) printk( "DDR DEBUG: " x )
struct ddr{
int suspend;
struct early_suspend early_suspend;
struct ddr {
int suspend;
struct early_suspend early_suspend;
struct clk *ddr_pll;
};
struct ddr *ddr = NULL;
static void ddr_early_suspend(struct early_suspend *h);
static void ddr_late_resume(struct early_suspend *h);
static struct ddr ddr = {
.early_suspend = {
.suspend = ddr_early_suspend,
.resume = ddr_late_resume,
.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 50,
},
};
static volatile bool __sramdata cpu1_pause;
static inline bool is_cpu1_paused(void) { smp_rmb(); return cpu1_pause; }
static inline void set_cpu1_pause(bool pause) { cpu1_pause = pause; smp_wmb(); }
#define MAX_TIMEOUT (16000000UL << 6) //>0.64s
static void __ddr_change_freq(void *info)
{
uint32_t *value = info;
u32 timeout = MAX_TIMEOUT;
while (!is_cpu1_paused() && --timeout);
if (timeout == 0)
return;
*value = ddr_change_freq(*value);
set_cpu1_pause(false);
}
/* Do not use stack, safe on SMP */
static void __sramfunc pause_cpu1(void *info)
{
u32 timeout = MAX_TIMEOUT;
unsigned long flags;
local_irq_save(flags);
set_cpu1_pause(true);
while (is_cpu1_paused() && --timeout);
local_irq_restore(flags);
}
static uint32_t _ddr_change_freq(uint32_t nMHz)
{
int this_cpu = get_cpu();
set_cpu1_pause(false);
if (this_cpu == 0) {
if (smp_call_function_single(1, (smp_call_func_t)pause_cpu1, NULL, 0) == 0) {
u32 timeout = MAX_TIMEOUT;
while (!is_cpu1_paused() && --timeout);
if (timeout == 0)
goto out;
}
nMHz = ddr_change_freq(nMHz);
set_cpu1_pause(false);
} else {
smp_call_function_single(0, __ddr_change_freq, &nMHz, 0);
pause_cpu1(NULL);
}
clk_set_rate(ddr.ddr_pll, 0);
out:
put_cpu();
return nMHz;
}
uint32_t ddr_set_rate(uint32_t nMHz)
{
_ddr_change_freq(nMHz);
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void ddr_early_suspend(struct early_suspend *h)
{
uint32_t value;
bool cpu1_online;
//Enable auto self refresh 0x01*32 DDR clk cycle
ddr_set_auto_self_refresh(true);
cpu1_online = cpu_online(1);
if(cpu1_online)
cpu_down(1);
value=ddr_change_freq(100);
value = _ddr_change_freq(100);
if(cpu1_online)
cpu_up(1);
ddr_print("init success!!! freq=%dMHz\n", value);
return;
}
static void ddr_early_resume(struct early_suspend *h)
static void ddr_late_resume(struct early_suspend *h)
{
uint32_t value;
bool cpu1_online;
//Disable auto self refresh
ddr_set_auto_self_refresh(false);
cpu1_online = cpu_online(1);
if(cpu1_online)
cpu_down(1);
value = _ddr_change_freq(DDR_FREQ);
value=ddr_change_freq(DDR_FREQ);
if(cpu1_online)
cpu_up(1);
ddr_print("init success!!! freq=%dMHz\n", value);
return;
}
#endif
static int rk30_ddr_late_init (void)
{
ddr = kmalloc(sizeof(struct ddr), GFP_KERNEL);
if(!ddr)
{
ddr_print("%s: kmalloc fail!\n",__FUNCTION__);
return -ENOMEM;
}
memset(ddr, 0, sizeof(struct ddr));
#ifdef CONFIG_HAS_EARLYSUSPEND
ddr->early_suspend.suspend = ddr_early_suspend;
ddr->early_suspend.resume = ddr_early_resume;
ddr->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 50;
register_early_suspend(&ddr->early_suspend);
#endif
ddr.ddr_pll = clk_get(NULL, "ddr_pll");
register_early_suspend(&ddr.early_suspend);
return 0;
}
late_initcall(rk30_ddr_late_init);
#endif
#ifdef CONFIG_DDR_TEST
#include <linux/slab.h>

View File

@@ -33,6 +33,10 @@
#else
#define DVFS_DBG(fmt, args...) printk(KERN_DEBUG "DVFS DBG:\t"fmt, ##args)
#endif
#define DVFS_SET_VOLT_FAILURE 1
#define DVFS_SET_VOLT_SUCCESS 0
#define DVFS_ERR(fmt, args...) printk(KERN_ERR "DVFS ERR:\t"fmt, ##args)
#define DVFS_LOG(fmt, args...) printk(KERN_DEBUG "DVFS LOG:\t"fmt, ##args)
@@ -394,6 +398,21 @@ int clk_enable_dvfs(struct clk *clk)
}
#endif
dvfs_vd_get_newvolt_byclk(dvfs_clk);
if(dvfs_clk->vd->cur_volt<dvfs_clk->set_volt)
{
int ret;
mutex_lock(&rk_dvfs_mutex);
ret = dvfs_regulator_set_voltage_readback(dvfs_clk->vd->regulator, dvfs_clk->set_volt, dvfs_clk->set_volt);
if (ret < 0) {
dvfs_clk->vd->volt_set_flag = DVFS_SET_VOLT_FAILURE;
dvfs_clk->enable_dvfs = 0;
DVFS_ERR("dvfs enable clk %s,set volt error \n", dvfs_clk->name);
mutex_unlock(&rk_dvfs_mutex);
return -1;
}
dvfs_clk->vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS;
mutex_unlock(&rk_dvfs_mutex);
}
dvfs_clk->enable_dvfs++;
} else {
DVFS_ERR("dvfs already enable clk enable = %d!\n", dvfs_clk->enable_dvfs);
@@ -694,8 +713,7 @@ static int dvfs_set_depend_post(struct clk_node *dvfs_clk, unsigned long rate_ol
return 0;
}
#endif
#define DVFS_SET_VOLT_FAILURE 1
#define DVFS_SET_VOLT_SUCCESS 0
#define ARM_HIGHER_LOGIC (150 * 1000)
#define LOGIC_HIGHER_ARM (100 * 1000)
@@ -1019,6 +1037,8 @@ int dvfs_target_cpu(struct clk *clk, unsigned long rate_hz)
/* need round rate */
rate_old = clk_get_rate(clk);
rate_new = clk_round_rate_nolock(clk, rate_hz);
if(rate_new==rate_old)
return 0;
DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n",
dvfs_clk->name, rate_hz, rate_new, rate_old);
@@ -1145,6 +1165,8 @@ int dvfs_target_core(struct clk *clk, unsigned long rate_hz)
/* need round rate */
rate_old = clk_get_rate(clk);
rate_new = clk_round_rate_nolock(clk, rate_hz);
if(rate_new==rate_old)
return 0;
DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n",
dvfs_clk->name, rate_hz, rate_new, rate_old);
@@ -1270,18 +1292,21 @@ static struct cpufreq_frequency_table dep_cpu2core_table[] = {
static struct vd_node vd_cpu = {
.name = "vd_cpu",
.regulator_name = "vdd_cpu",
.volt_set_flag =DVFS_SET_VOLT_FAILURE,
.vd_dvfs_target = dvfs_target_cpu,
};
static struct vd_node vd_core = {
.name = "vd_core",
.regulator_name = "vdd_core",
.volt_set_flag =DVFS_SET_VOLT_FAILURE,
.vd_dvfs_target = dvfs_target_core,
};
static struct vd_node vd_rtc = {
.name = "vd_rtc",
.regulator_name = "vdd_rtc",
.volt_set_flag =DVFS_SET_VOLT_FAILURE,
.vd_dvfs_target = NULL,
};

View File

@@ -149,5 +149,7 @@ void __sramfunc ddr_resume(void);
uint32_t __sramfunc ddr_change_freq(uint32_t nMHz);
int ddr_init(uint32_t dram_type, uint32_t freq);
void ddr_set_auto_self_refresh(bool en);
uint32_t __sramlocalfunc ddr_set_pll(uint32_t nMHz, uint32_t set);
#endif

161
arch/arm/mach-rk30/video_state.c Executable file
View File

@@ -0,0 +1,161 @@
/* arch/arm/mach-rk30/video_state.c
*
* Copyright (C) 2012 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <mach/ddr.h>
#include <linux/cpu.h>
#include <linux/clk.h>
#ifdef CONFIG_DDR_SDRAM_FREQ
#define DDR_FREQ (CONFIG_DDR_SDRAM_FREQ)
#else
#define DDR_FREQ 400
#endif
int rk_video_state=0;
static struct clk * ddr_clk;
#define VIDEO_STATE_NAME "video_state"
#define BUFFER_SIZE 16
MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
MODULE_DESCRIPTION("Key chord input driver");
MODULE_SUPPORTED_DEVICE("video_state");
MODULE_LICENSE("GPL");
/*
* video_state_read is used to read video_state events from the driver
*/
static ssize_t video_state_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
return count;
}
/*
* video_state_write is used to configure the driver
*/
static ssize_t video_state_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
char *parameters= 0;
int vedeo_state;
int set_rate=0;
int set_rate_old=0;
if(DDR_FREQ<=333)
return count;
//if (count < sizeof(struct input_keychord))
// return -EINVAL;
parameters = kzalloc(count, GFP_KERNEL);
if (!parameters)
return -ENOMEM;
/* read list of keychords from userspace */
if (copy_from_user(parameters, buffer, count)) {
kfree(parameters);
return -EFAULT;
}
sscanf(parameters, "%d", &vedeo_state);
//printk("video_state %d\n",vedeo_state);
switch(vedeo_state)
{
case 0:
rk_video_state=0;
set_rate=DDR_FREQ;
break;
case 1:
rk_video_state=1;
set_rate=300;
break;
default:
rk_video_state=0;
return -EFAULT;
}
set_rate_old=clk_get_rate(ddr_clk);
set_rate=clk_round_rate(ddr_clk,set_rate*1000*1000);
if(set_rate_old!=set_rate)
{
clk_set_rate(ddr_clk,set_rate);
//printk("ddr rate=%d\n",set_rate/(1000*1000));
}
kfree(parameters);
return count;
}
static unsigned int video_state_poll(struct file *file, poll_table *wait)
{
return 0;
}
static int video_state_open(struct inode *inode, struct file *file)
{
return 0;
}
static int video_state_release(struct inode *inode, struct file *file)
{
return 0;
}
static const struct file_operations video_state_fops = {
.owner = THIS_MODULE,
.open = video_state_open,
.release = video_state_release,
.read = video_state_read,
.write = video_state_write,
.poll = video_state_poll,
};
static struct miscdevice video_state = {
.fops = &video_state_fops,
.name = VIDEO_STATE_NAME,
.minor = MISC_DYNAMIC_MINOR,
};
static int __init video_state_init(void)
{
ddr_clk=clk_get(NULL,"ddr");
if(IS_ERR(ddr_clk))
return -1;
return misc_register(&video_state);
}
static void __exit video_state_exit(void)
{
misc_deregister(&video_state);
}
module_init(video_state_init);
module_exit(video_state_exit);