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
#include "clock.h"
#include <mach/pmu.h>
#include <mach/dvfs.h>
+#include <mach/ddr.h>
#define MHZ (1000*1000)
#define KHZ (1000)
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),
#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)
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);
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))
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");
DDR_RESTORE_SP(save_sp);
local_fiq_enable();
local_irq_restore(flags);
- clk_set_rate(clk_get(NULL, "ddr_pll"), 0);
return ret;
}
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++)
#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>
#else\r
#define DVFS_DBG(fmt, args...) printk(KERN_DEBUG "DVFS DBG:\t"fmt, ##args)\r
#endif\r
+\r
+#define DVFS_SET_VOLT_FAILURE 1\r
+#define DVFS_SET_VOLT_SUCCESS 0\r
+\r
#define DVFS_ERR(fmt, args...) printk(KERN_ERR "DVFS ERR:\t"fmt, ##args)\r
#define DVFS_LOG(fmt, args...) printk(KERN_DEBUG "DVFS LOG:\t"fmt, ##args)\r
\r
}\r
#endif\r
dvfs_vd_get_newvolt_byclk(dvfs_clk);\r
+ if(dvfs_clk->vd->cur_volt<dvfs_clk->set_volt)\r
+ {\r
+ int ret;\r
+ mutex_lock(&rk_dvfs_mutex);\r
+ ret = dvfs_regulator_set_voltage_readback(dvfs_clk->vd->regulator, dvfs_clk->set_volt, dvfs_clk->set_volt);\r
+ if (ret < 0) {\r
+ dvfs_clk->vd->volt_set_flag = DVFS_SET_VOLT_FAILURE;\r
+ dvfs_clk->enable_dvfs = 0;\r
+ DVFS_ERR("dvfs enable clk %s,set volt error \n", dvfs_clk->name);\r
+ mutex_unlock(&rk_dvfs_mutex);\r
+ return -1;\r
+ }\r
+ dvfs_clk->vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS;\r
+ mutex_unlock(&rk_dvfs_mutex);\r
+ }\r
dvfs_clk->enable_dvfs++;\r
} else {\r
DVFS_ERR("dvfs already enable clk enable = %d!\n", dvfs_clk->enable_dvfs);\r
return 0;\r
}\r
#endif\r
-#define DVFS_SET_VOLT_FAILURE 1\r
-#define DVFS_SET_VOLT_SUCCESS 0\r
+\r
#define ARM_HIGHER_LOGIC (150 * 1000)\r
#define LOGIC_HIGHER_ARM (100 * 1000)\r
\r
/* need round rate */\r
rate_old = clk_get_rate(clk);\r
rate_new = clk_round_rate_nolock(clk, rate_hz);\r
+ if(rate_new==rate_old)\r
+ return 0;\r
DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n", \r
dvfs_clk->name, rate_hz, rate_new, rate_old);\r
\r
/* need round rate */\r
rate_old = clk_get_rate(clk);\r
rate_new = clk_round_rate_nolock(clk, rate_hz);\r
+ if(rate_new==rate_old)\r
+ return 0;\r
DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n", \r
dvfs_clk->name, rate_hz, rate_new, rate_old);\r
\r
static struct vd_node vd_cpu = {\r
.name = "vd_cpu",\r
.regulator_name = "vdd_cpu",\r
+ .volt_set_flag =DVFS_SET_VOLT_FAILURE,\r
.vd_dvfs_target = dvfs_target_cpu,\r
};\r
\r
static struct vd_node vd_core = {\r
.name = "vd_core",\r
.regulator_name = "vdd_core",\r
+ .volt_set_flag =DVFS_SET_VOLT_FAILURE,\r
.vd_dvfs_target = dvfs_target_core,\r
};\r
\r
static struct vd_node vd_rtc = {\r
.name = "vd_rtc",\r
.regulator_name = "vdd_rtc",\r
+ .volt_set_flag =DVFS_SET_VOLT_FAILURE,\r
.vd_dvfs_target = NULL,\r
};\r
\r
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
--- /dev/null
+/* 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);
+
+
+