mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-10 04:48:04 +09:00
rk29: move ddr frequency scaling from cpufreq.c to ddrfreq.c
This commit is contained in:
@@ -8,6 +8,7 @@ obj-$(CONFIG_RK29_LAST_LOG) += last_log.o
|
||||
obj-$(CONFIG_USB_GADGET) += usb_detect.o
|
||||
obj-$(CONFIG_PM) += pm.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
|
||||
obj-$(CONFIG_DDR_FREQ) += ddrfreq.o
|
||||
obj-$(CONFIG_RK29_VPU) += vpu_mem.o
|
||||
obj-y += spi_sram.o
|
||||
obj-$(CONFIG_RK29_VPU_SERVICE) += vpu_service.o
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <mach/clock.h>
|
||||
#include <mach/cpufreq.h>
|
||||
#include <mach/ddr.h>
|
||||
#include <../../../drivers/video/rk29_fb.h>
|
||||
|
||||
#define MHZ (1000*1000)
|
||||
@@ -84,9 +83,8 @@ enum {
|
||||
DEBUG_CHANGE = 1U << 0,
|
||||
DEBUG_TEMP = 1U << 1,
|
||||
DEBUG_DISP = 1U << 2,
|
||||
DEBUG_DDR = 1U << 3,
|
||||
};
|
||||
static uint debug_mask = DEBUG_CHANGE | DEBUG_DDR;
|
||||
static uint debug_mask = DEBUG_CHANGE;
|
||||
module_param(debug_mask, uint, 0644);
|
||||
#define dprintk(mask, fmt, ...) do { if (mask & debug_mask) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0)
|
||||
|
||||
@@ -125,12 +123,6 @@ static int limit_index_1008 = -1;
|
||||
static unsigned int limit_freq_1008;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DDR_FREQ
|
||||
static void rk29_cpufreq_change_ddr_freq(unsigned long mhz);
|
||||
#else
|
||||
static inline void rk29_cpufreq_change_ddr_freq(unsigned long mhz) {}
|
||||
#endif
|
||||
|
||||
static bool rk29_cpufreq_is_ondemand_policy(struct cpufreq_policy *policy)
|
||||
{
|
||||
char c = 0;
|
||||
@@ -366,7 +358,6 @@ static int rk29_cpufreq_do_target(struct cpufreq_policy *policy, unsigned int ta
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
dprintk(DEBUG_CHANGE, "pre change\n");
|
||||
clk_set_rate(arm_clk, freqs.new * KHZ + aclk_limit());
|
||||
rk29_cpufreq_change_ddr_freq(0);
|
||||
dprintk(DEBUG_CHANGE, "post change\n");
|
||||
freqs.new = clk_get_rate(arm_clk) / KHZ;
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
@@ -485,119 +476,6 @@ static struct notifier_block rk29_cpufreq_fb_notifier = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DDR_FREQ
|
||||
static struct clk *ddr_pll_clk;
|
||||
static struct clk *aclk_lcdc;
|
||||
static bool ddr_pll_can_change;
|
||||
static bool aclk_lcdc_disabled;
|
||||
static bool disable_ddr_freq;
|
||||
module_param(ddr_pll_can_change, bool, 0644);
|
||||
module_param(aclk_lcdc_disabled, bool, 0644);
|
||||
module_param(disable_ddr_freq, bool, 0644);
|
||||
static unsigned long ddr_max_mhz;
|
||||
static unsigned long ddr_min_mhz;
|
||||
module_param(ddr_max_mhz, ulong, 0644);
|
||||
module_param(ddr_min_mhz, ulong, 0644);
|
||||
#define DDR_ARM_RATE (408 * MHZ)
|
||||
|
||||
static void rk29_cpufreq_change_ddr_freq(unsigned long mhz)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long ddr_rate, arm_rate;
|
||||
bool changed = false;
|
||||
|
||||
if (disable_ddr_freq)
|
||||
return;
|
||||
|
||||
if (DEBUG_DDR & debug_mask) {
|
||||
unsigned long _mhz = mhz;
|
||||
ddr_rate = clk_get_rate(ddr_clk);
|
||||
if (!mhz && ddr_pll_can_change && aclk_lcdc_disabled) {
|
||||
arm_rate = clk_get_rate(arm_clk);
|
||||
if (arm_rate <= DDR_ARM_RATE && ddr_rate == ddr_max_rate)
|
||||
_mhz = ddr_min_mhz;
|
||||
else if (arm_rate > DDR_ARM_RATE && ddr_rate < ddr_max_rate)
|
||||
_mhz = ddr_max_mhz;
|
||||
}
|
||||
if (_mhz) {
|
||||
unsigned long hz = _mhz * MHZ;
|
||||
if (hz != ddr_rate)
|
||||
dprintk(DEBUG_DDR, "ddr %lu -> %lu Hz\n", ddr_rate, hz);
|
||||
}
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
ddr_rate = clk_get_rate(ddr_clk);
|
||||
if (!mhz && ddr_pll_can_change && aclk_lcdc_disabled) {
|
||||
arm_rate = clk_get_rate(arm_clk);
|
||||
if (arm_rate <= DDR_ARM_RATE && ddr_rate == ddr_max_rate)
|
||||
mhz = ddr_min_mhz;
|
||||
else if (arm_rate > DDR_ARM_RATE && ddr_rate < ddr_max_rate)
|
||||
mhz = ddr_max_mhz;
|
||||
}
|
||||
if (mhz && (mhz * MHZ) != ddr_rate) {
|
||||
ddr_change_freq(mhz);
|
||||
changed = true;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
|
||||
if (changed)
|
||||
dprintk(DEBUG_DDR, "ok, got %lu Hz\n", clk_get_rate(ddr_clk));
|
||||
}
|
||||
|
||||
static int rk29_cpufreq_ddr_pll_notifier_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
switch (event) {
|
||||
case CLK_PRE_ENABLE:
|
||||
ddr_pll_can_change = false;
|
||||
break;
|
||||
case CLK_ABORT_ENABLE:
|
||||
case CLK_POST_DISABLE:
|
||||
ddr_pll_can_change = true;
|
||||
break;
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
if (!disable_ddr_freq) {
|
||||
dprintk(DEBUG_DDR, "event: %lu ddr_pll_can_change: %d\n", event, ddr_pll_can_change);
|
||||
rk29_cpufreq_change_ddr_freq(ddr_pll_can_change ? 0 : ddr_max_mhz);
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block rk29_cpufreq_ddr_pll_notifier = {
|
||||
.notifier_call = rk29_cpufreq_ddr_pll_notifier_event,
|
||||
};
|
||||
|
||||
static int rk29_cpufreq_aclk_lcdc_notifier_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
switch (event) {
|
||||
case CLK_PRE_ENABLE:
|
||||
aclk_lcdc_disabled = false;
|
||||
break;
|
||||
case CLK_ABORT_ENABLE:
|
||||
case CLK_POST_DISABLE:
|
||||
aclk_lcdc_disabled = true;
|
||||
break;
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
if (!disable_ddr_freq) {
|
||||
dprintk(DEBUG_DDR, "event: %lu aclk_lcdc_disabled: %d\n", event, aclk_lcdc_disabled);
|
||||
rk29_cpufreq_change_ddr_freq(aclk_lcdc_disabled ? 0 : ddr_max_mhz);
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block rk29_cpufreq_aclk_lcdc_notifier = {
|
||||
.notifier_call = rk29_cpufreq_aclk_lcdc_notifier_event,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int rk29_cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
if (policy->cpu != 0)
|
||||
@@ -620,23 +498,6 @@ static int rk29_cpufreq_init(struct cpufreq_policy *policy)
|
||||
}
|
||||
ddr_max_rate = clk_get_rate(ddr_clk);
|
||||
|
||||
#ifdef CONFIG_DDR_FREQ
|
||||
ddr_max_mhz = ddr_max_rate / MHZ;
|
||||
{
|
||||
unsigned long ddr_min_rate;
|
||||
ddr_min_rate = ddr_max_rate >> 1;
|
||||
if (ddr_min_rate > 150 * MHZ)
|
||||
ddr_min_rate >>= 1;
|
||||
ddr_min_mhz = ddr_min_rate / MHZ;
|
||||
}
|
||||
|
||||
ddr_pll_clk = clk_get(NULL, "ddr_pll");
|
||||
aclk_lcdc = clk_get(NULL, "aclk_lcdc");
|
||||
|
||||
clk_notifier_register(ddr_pll_clk, &rk29_cpufreq_ddr_pll_notifier);
|
||||
clk_notifier_register(aclk_lcdc, &rk29_cpufreq_aclk_lcdc_notifier);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_REGULATOR
|
||||
vcore = regulator_get(NULL, "vcore");
|
||||
if (IS_ERR(vcore)) {
|
||||
@@ -673,10 +534,6 @@ static int rk29_cpufreq_init(struct cpufreq_policy *policy)
|
||||
|
||||
static int rk29_cpufreq_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
#ifdef CONFIG_DDR_FREQ
|
||||
clk_notifier_unregister(ddr_pll_clk, &rk29_cpufreq_ddr_pll_notifier);
|
||||
clk_notifier_unregister(aclk_lcdc, &rk29_cpufreq_aclk_lcdc_notifier);
|
||||
#endif
|
||||
#ifdef CONFIG_RK29_CPU_FREQ_LIMIT_BY_DISP
|
||||
rk29fb_unregister_notifier(&rk29_cpufreq_fb_notifier);
|
||||
#endif
|
||||
|
||||
155
arch/arm/mach-rk29/ddrfreq.c
Normal file
155
arch/arm/mach-rk29/ddrfreq.c
Normal file
@@ -0,0 +1,155 @@
|
||||
/* arch/arm/mach-rk29/ddrfreq.c
|
||||
*
|
||||
* Copyright (C) 2011 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/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <mach/clock.h>
|
||||
#include <mach/ddr.h>
|
||||
|
||||
#define MHZ (1000*1000)
|
||||
|
||||
enum {
|
||||
DEBUG_CHANGE = 1U << 0,
|
||||
DEBUG_EVENT = 1U << 1,
|
||||
};
|
||||
static uint debug_mask = DEBUG_CHANGE;
|
||||
module_param(debug_mask, uint, 0644);
|
||||
#define dprintk(mask, fmt, ...) do { if (mask & debug_mask) printk(KERN_DEBUG "ddrfreq: " fmt, ##__VA_ARGS__); } while (0)
|
||||
|
||||
static struct clk *clk_ddr;
|
||||
static struct clk *ddr_pll_clk;
|
||||
static struct clk *aclk_lcdc;
|
||||
static bool ddr_pll_can_change;
|
||||
static bool aclk_lcdc_disabled;
|
||||
static bool disable_ddr_freq;
|
||||
module_param(ddr_pll_can_change, bool, 0644);
|
||||
module_param(aclk_lcdc_disabled, bool, 0644);
|
||||
module_param(disable_ddr_freq, bool, 0644);
|
||||
|
||||
static unsigned long ddr_max_mhz;
|
||||
static unsigned long ddr_min_mhz = 96;
|
||||
static void rk29_ddrfreq_change_freq(void);
|
||||
static int rk29_ddrfreq_set_ddr_mhz(const char *val, struct kernel_param *kp)
|
||||
{
|
||||
int err = param_set_uint(val, kp);
|
||||
if (!err) {
|
||||
rk29_ddrfreq_change_freq();
|
||||
}
|
||||
return err;
|
||||
}
|
||||
module_param_call(ddr_max_mhz, rk29_ddrfreq_set_ddr_mhz, param_get_uint, &ddr_max_mhz, 0644);
|
||||
module_param_call(ddr_min_mhz, rk29_ddrfreq_set_ddr_mhz, param_get_uint, &ddr_min_mhz, 0644);
|
||||
|
||||
static DEFINE_SPINLOCK(ddr_lock);
|
||||
|
||||
static void rk29_ddrfreq_change_freq(void)
|
||||
{
|
||||
unsigned long ddr_rate, mhz;
|
||||
|
||||
if (disable_ddr_freq)
|
||||
return;
|
||||
|
||||
ddr_rate = clk_get_rate(clk_ddr);
|
||||
mhz = (ddr_pll_can_change && aclk_lcdc_disabled) ? ddr_min_mhz : ddr_max_mhz;
|
||||
if ((mhz * MHZ) != ddr_rate) {
|
||||
dprintk(DEBUG_CHANGE, "%lu -> %lu Hz\n", ddr_rate, mhz * MHZ);
|
||||
ddr_change_freq(mhz);
|
||||
dprintk(DEBUG_CHANGE, "got %lu Hz\n", clk_get_rate(clk_ddr));
|
||||
}
|
||||
}
|
||||
|
||||
static int rk29_ddrfreq_ddr_pll_notifier_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
spin_lock_bh(&ddr_lock);
|
||||
switch (event) {
|
||||
case CLK_PRE_ENABLE:
|
||||
ddr_pll_can_change = false;
|
||||
break;
|
||||
case CLK_ABORT_ENABLE:
|
||||
case CLK_POST_DISABLE:
|
||||
ddr_pll_can_change = true;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!disable_ddr_freq) {
|
||||
dprintk(DEBUG_EVENT, "event: %lu ddr_pll_can_change: %d\n", event, ddr_pll_can_change);
|
||||
rk29_ddrfreq_change_freq();
|
||||
}
|
||||
out:
|
||||
spin_unlock_bh(&ddr_lock);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block rk29_ddrfreq_ddr_pll_notifier = {
|
||||
.notifier_call = rk29_ddrfreq_ddr_pll_notifier_event,
|
||||
};
|
||||
|
||||
static int rk29_ddrfreq_aclk_lcdc_notifier_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
spin_lock_bh(&ddr_lock);
|
||||
switch (event) {
|
||||
case CLK_PRE_ENABLE:
|
||||
aclk_lcdc_disabled = false;
|
||||
break;
|
||||
case CLK_ABORT_ENABLE:
|
||||
case CLK_POST_DISABLE:
|
||||
aclk_lcdc_disabled = true;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!disable_ddr_freq) {
|
||||
dprintk(DEBUG_EVENT, "event: %lu aclk_lcdc_disabled: %d\n", event, aclk_lcdc_disabled);
|
||||
rk29_ddrfreq_change_freq();
|
||||
}
|
||||
out:
|
||||
spin_unlock_bh(&ddr_lock);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block rk29_ddrfreq_aclk_lcdc_notifier = {
|
||||
.notifier_call = rk29_ddrfreq_aclk_lcdc_notifier_event,
|
||||
};
|
||||
|
||||
static int __init rk29_ddrfreq_init(void)
|
||||
{
|
||||
clk_ddr = clk_get(NULL, "ddr");
|
||||
if (IS_ERR(clk_ddr)) {
|
||||
int err = PTR_ERR(clk_ddr);
|
||||
pr_err("fail to get ddr clk: %d\n", err);
|
||||
clk_ddr = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
ddr_max_mhz = clk_get_rate(clk_ddr) / MHZ;
|
||||
|
||||
ddr_pll_clk = clk_get(NULL, "ddr_pll");
|
||||
aclk_lcdc = clk_get(NULL, "aclk_lcdc");
|
||||
|
||||
clk_notifier_register(ddr_pll_clk, &rk29_ddrfreq_ddr_pll_notifier);
|
||||
clk_notifier_register(aclk_lcdc, &rk29_ddrfreq_aclk_lcdc_notifier);
|
||||
|
||||
printk("ddrfreq: version 1.0\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
late_initcall(rk29_ddrfreq_init);
|
||||
Reference in New Issue
Block a user