mirror of
https://github.com/hardkernel/linux.git
synced 2026-04-18 19:40:46 +09:00
Merge branch android-tegra-2.6.36 into android-tegra-moto-2.6.36
Change-Id: I3a5bce1a80f73fd289031d7f329b67eaaf6ce8b5
This commit is contained in:
@@ -37,12 +37,4 @@ void twd_timer_setup(struct clock_event_device *);
|
||||
void twd_timer_setup_scalable(struct clock_event_device *,
|
||||
unsigned long target_rate, unsigned int periphclk_prescaler);
|
||||
|
||||
/*
|
||||
* Recalculate the twd prescaler value when the cpu frequency changes. To
|
||||
* prevent early timer interrupts, must be called before changing the cpu
|
||||
* frequency if the frequency is increasing, or after if the frequency is
|
||||
* decreasing.
|
||||
*/
|
||||
void twd_recalc_prescaler(unsigned long new_rate);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/cpufreq.h>
|
||||
|
||||
#include <asm/smp_twd.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
@@ -26,7 +27,7 @@ void __iomem *twd_base;
|
||||
|
||||
static unsigned long twd_timer_rate;
|
||||
static unsigned long twd_periphclk_prescaler;
|
||||
static unsigned long twd_target_rate;
|
||||
static unsigned long twd_cpu_rate;
|
||||
|
||||
static void twd_set_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *clk)
|
||||
@@ -82,7 +83,13 @@ int twd_timer_ack(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void twd_recalc_prescaler(unsigned long new_rate)
|
||||
/*
|
||||
* Recalculate the twd prescaler value when the cpu frequency changes. To
|
||||
* prevent early timer interrupts, must be called before changing the cpu
|
||||
* frequency if the frequency is increasing, or after if the frequency is
|
||||
* decreasing.
|
||||
*/
|
||||
static void twd_update_prescaler(void *data)
|
||||
{
|
||||
u32 ctrl;
|
||||
int prescaler;
|
||||
@@ -90,7 +97,7 @@ void twd_recalc_prescaler(unsigned long new_rate)
|
||||
|
||||
BUG_ON(twd_periphclk_prescaler == 0 || twd_timer_rate == 0);
|
||||
|
||||
periphclk_rate = new_rate / twd_periphclk_prescaler;
|
||||
periphclk_rate = twd_cpu_rate / twd_periphclk_prescaler;
|
||||
|
||||
prescaler = DIV_ROUND_UP(periphclk_rate, twd_timer_rate);
|
||||
prescaler = clamp(prescaler - 1, 0, 0xFF);
|
||||
@@ -101,60 +108,95 @@ void twd_recalc_prescaler(unsigned long new_rate)
|
||||
__raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
|
||||
}
|
||||
|
||||
static int twd_cpufreq_transition(struct notifier_block *nb,
|
||||
unsigned long state, void *data)
|
||||
{
|
||||
struct cpufreq_freqs *freqs = data;
|
||||
if (((freqs->new > freqs->old) && state == CPUFREQ_PRECHANGE) ||
|
||||
((freqs->old > freqs->new) && state == CPUFREQ_POSTCHANGE)) {
|
||||
/* freqs->new is in kHz, twd_cpu_rate is in Hz */
|
||||
twd_cpu_rate = freqs->new * 1000;
|
||||
|
||||
smp_call_function_single(freqs->cpu, twd_update_prescaler,
|
||||
NULL, 1);
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block twd_cpufreq_nb = {
|
||||
.notifier_call = twd_cpufreq_transition,
|
||||
};
|
||||
|
||||
static int twd_cpufreq_init(void)
|
||||
{
|
||||
if (twd_cpu_rate)
|
||||
return cpufreq_register_notifier(&twd_cpufreq_nb,
|
||||
CPUFREQ_TRANSITION_NOTIFIER);
|
||||
|
||||
return 0;
|
||||
}
|
||||
core_initcall(twd_cpufreq_init);
|
||||
|
||||
static void __cpuinit twd_calibrate_rate(unsigned long target_rate,
|
||||
unsigned int periphclk_prescaler)
|
||||
{
|
||||
unsigned long load, count;
|
||||
u64 waitjiffies;
|
||||
unsigned long cpu_rate;
|
||||
|
||||
/*
|
||||
* If this is the first time round, we need to work out how fast
|
||||
* the timer ticks
|
||||
*/
|
||||
printk(KERN_INFO "Calibrating local timer... ");
|
||||
if (twd_timer_rate == 0) {
|
||||
printk(KERN_INFO "Calibrating local timer... ");
|
||||
|
||||
/* Wait for a tick to start */
|
||||
waitjiffies = get_jiffies_64() + 1;
|
||||
/* Wait for a tick to start */
|
||||
waitjiffies = get_jiffies_64() + 1;
|
||||
|
||||
while (get_jiffies_64() < waitjiffies)
|
||||
udelay(10);
|
||||
while (get_jiffies_64() < waitjiffies)
|
||||
udelay(10);
|
||||
|
||||
/* OK, now the tick has started, let's get the timer going */
|
||||
waitjiffies += 5;
|
||||
/* OK, now the tick has started, let's get the timer going */
|
||||
waitjiffies += 5;
|
||||
|
||||
/* enable, no interrupt or reload */
|
||||
__raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
|
||||
/* enable, no interrupt or reload */
|
||||
__raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
|
||||
|
||||
/* maximum value */
|
||||
__raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
|
||||
/* maximum value */
|
||||
__raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
|
||||
|
||||
while (get_jiffies_64() < waitjiffies)
|
||||
udelay(10);
|
||||
while (get_jiffies_64() < waitjiffies)
|
||||
udelay(10);
|
||||
|
||||
count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
|
||||
count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
|
||||
|
||||
twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
|
||||
twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
|
||||
|
||||
/*
|
||||
* If a target rate has been requested, adjust the TWD prescaler
|
||||
* to get the closest lower frequency.
|
||||
*/
|
||||
if (target_rate) {
|
||||
twd_periphclk_prescaler = periphclk_prescaler;
|
||||
twd_target_rate = target_rate;
|
||||
/*
|
||||
* If a target rate has been requested, adjust the TWD prescaler
|
||||
* to get the closest lower frequency.
|
||||
*/
|
||||
if (target_rate) {
|
||||
twd_periphclk_prescaler = periphclk_prescaler;
|
||||
|
||||
printk("%lu.%02luMHz, setting to ",
|
||||
twd_timer_rate / 1000000,
|
||||
printk("%lu.%02luMHz, setting to ",
|
||||
twd_timer_rate / 1000000,
|
||||
(twd_timer_rate / 10000) % 100);
|
||||
twd_cpu_rate = twd_timer_rate * periphclk_prescaler;
|
||||
twd_timer_rate = target_rate;
|
||||
twd_update_prescaler(NULL);
|
||||
}
|
||||
|
||||
printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
|
||||
(twd_timer_rate / 10000) % 100);
|
||||
cpu_rate = twd_timer_rate * periphclk_prescaler;
|
||||
twd_timer_rate = twd_target_rate;
|
||||
twd_recalc_prescaler(cpu_rate);
|
||||
} else {
|
||||
if (target_rate) {
|
||||
BUG_ON(target_rate != twd_timer_rate);
|
||||
twd_update_prescaler(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000,
|
||||
(twd_timer_rate / 10000) % 100);
|
||||
|
||||
load = twd_timer_rate / HZ;
|
||||
|
||||
__raw_writel(load, twd_base + TWD_TIMER_LOAD);
|
||||
|
||||
@@ -37,7 +37,10 @@
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/clk.h>
|
||||
|
||||
/* Frequency table index must be sequential starting at 0 and frequencies must be ascending*/
|
||||
/*
|
||||
* Frequency table index must be sequential starting at 0 and frequencies
|
||||
* must be ascending.
|
||||
*/
|
||||
static struct cpufreq_frequency_table freq_table[] = {
|
||||
{ 0, 216000 },
|
||||
{ 1, 312000 },
|
||||
@@ -61,44 +64,35 @@ static bool is_suspended;
|
||||
|
||||
unsigned int tegra_getspeed(unsigned int cpu);
|
||||
static int tegra_update_cpu_speed(unsigned long rate);
|
||||
|
||||
/* CPU frequency is gradually lowered when throttling is enabled */
|
||||
#define THROTTLE_START_INDEX 2
|
||||
#define THROTTLE_END_INDEX 6
|
||||
static unsigned long tegra_cpu_highest_speed(void);
|
||||
|
||||
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
|
||||
/* CPU frequency is gradually lowered when throttling is enabled */
|
||||
#define THROTTLE_LOWEST_INDEX 2 /* 456000 */
|
||||
#define THROTTLE_HIGHEST_INDEX 6 /* 912000 */
|
||||
#define THROTTLE_DELAY msecs_to_jiffies(2000)
|
||||
#define NO_DELAY msecs_to_jiffies(0)
|
||||
|
||||
static DEFINE_MUTEX(throttling_lock);
|
||||
static bool is_throttling;
|
||||
static int throttle_index;
|
||||
static int throttle_next_index;
|
||||
static struct delayed_work throttle_work;
|
||||
static struct workqueue_struct *workqueue;
|
||||
|
||||
#define tegra_cpu_is_throttling() (is_throttling)
|
||||
|
||||
static bool tegra_throttling_needed(unsigned long *rate)
|
||||
{
|
||||
unsigned int current_freq = tegra_getspeed(0);
|
||||
int i;
|
||||
|
||||
for (i = THROTTLE_END_INDEX; i >= THROTTLE_START_INDEX; i--) {
|
||||
if (freq_table[i].frequency < current_freq) {
|
||||
*rate = freq_table[i].frequency;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void tegra_throttle_work_func(struct work_struct *work)
|
||||
{
|
||||
unsigned long rate;
|
||||
unsigned int current_freq;
|
||||
|
||||
mutex_lock(&tegra_cpu_lock);
|
||||
current_freq = tegra_getspeed(0);
|
||||
throttle_index = throttle_next_index;
|
||||
|
||||
if (tegra_throttling_needed(&rate) && tegra_update_cpu_speed(rate) == 0) {
|
||||
if (freq_table[throttle_index].frequency < current_freq)
|
||||
tegra_update_cpu_speed(freq_table[throttle_index].frequency);
|
||||
|
||||
if (throttle_index > THROTTLE_LOWEST_INDEX) {
|
||||
throttle_next_index = throttle_index - 1;
|
||||
queue_delayed_work(workqueue, &throttle_work, THROTTLE_DELAY);
|
||||
}
|
||||
|
||||
@@ -111,20 +105,48 @@ static void tegra_throttle_work_func(struct work_struct *work)
|
||||
*/
|
||||
void tegra_throttling_enable(bool enable)
|
||||
{
|
||||
mutex_lock(&throttling_lock);
|
||||
mutex_lock(&tegra_cpu_lock);
|
||||
|
||||
if (enable && !is_throttling) {
|
||||
unsigned int current_freq = tegra_getspeed(0);
|
||||
|
||||
is_throttling = true;
|
||||
queue_delayed_work(workqueue, &throttle_work, NO_DELAY);
|
||||
|
||||
for (throttle_index = THROTTLE_HIGHEST_INDEX;
|
||||
throttle_index >= THROTTLE_LOWEST_INDEX;
|
||||
throttle_index--)
|
||||
if (freq_table[throttle_index].frequency
|
||||
< current_freq)
|
||||
break;
|
||||
|
||||
throttle_index = max(throttle_index, THROTTLE_LOWEST_INDEX);
|
||||
throttle_next_index = throttle_index;
|
||||
queue_delayed_work(workqueue, &throttle_work, 0);
|
||||
} else if (!enable && is_throttling) {
|
||||
cancel_delayed_work_sync(&throttle_work);
|
||||
is_throttling = false;
|
||||
/* restore speed requested by governor */
|
||||
tegra_update_cpu_speed(tegra_cpu_highest_speed());
|
||||
}
|
||||
|
||||
mutex_unlock(&throttling_lock);
|
||||
mutex_unlock(&tegra_cpu_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tegra_throttling_enable);
|
||||
|
||||
static unsigned int throttle_governor_speed(unsigned int requested_speed)
|
||||
{
|
||||
return tegra_cpu_is_throttling() ?
|
||||
min(requested_speed, freq_table[throttle_index].frequency) :
|
||||
requested_speed;
|
||||
}
|
||||
|
||||
static ssize_t show_throttle(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", is_throttling);
|
||||
}
|
||||
|
||||
cpufreq_freq_attr_ro(throttle);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int throttle_debug_set(void *data, u64 val)
|
||||
{
|
||||
@@ -170,6 +192,7 @@ module_exit(tegra_cpu_debug_exit);
|
||||
|
||||
#else /* CONFIG_TEGRA_THERMAL_THROTTLE */
|
||||
#define tegra_cpu_is_throttling() (0)
|
||||
#define throttle_governor_speed(requested_speed) (requested_speed)
|
||||
|
||||
void tegra_throttling_enable(bool enable)
|
||||
{
|
||||
@@ -192,23 +215,6 @@ unsigned int tegra_getspeed(unsigned int cpu)
|
||||
return rate;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAVE_ARM_TWD
|
||||
static void tegra_cpufreq_rescale_twd_other_cpu(void *data) {
|
||||
unsigned long new_rate = *(unsigned long *)data;
|
||||
twd_recalc_prescaler(new_rate);
|
||||
}
|
||||
|
||||
static void tegra_cpufreq_rescale_twds(unsigned long new_rate)
|
||||
{
|
||||
twd_recalc_prescaler(new_rate);
|
||||
smp_call_function(tegra_cpufreq_rescale_twd_other_cpu, &new_rate, 1);
|
||||
}
|
||||
#else
|
||||
static inline void tegra_cpufreq_rescale_twds(unsigned long new_rate)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static int tegra_update_cpu_speed(unsigned long rate)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -234,9 +240,6 @@ static int tegra_update_cpu_speed(unsigned long rate)
|
||||
for_each_online_cpu(freqs.cpu)
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
|
||||
|
||||
if (freqs.new > freqs.old)
|
||||
tegra_cpufreq_rescale_twds(freqs.new * 1000);
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_DEBUG
|
||||
printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n",
|
||||
freqs.old, freqs.new);
|
||||
@@ -249,9 +252,6 @@ static int tegra_update_cpu_speed(unsigned long rate)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (freqs.new < freqs.old)
|
||||
tegra_cpufreq_rescale_twds(freqs.new * 1000);
|
||||
|
||||
for_each_online_cpu(freqs.cpu)
|
||||
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
|
||||
|
||||
@@ -289,25 +289,7 @@ static int tegra_target(struct cpufreq_policy *policy,
|
||||
freq = freq_table[idx].frequency;
|
||||
|
||||
target_cpu_speed[policy->cpu] = freq;
|
||||
|
||||
new_speed = tegra_cpu_highest_speed();
|
||||
|
||||
/* Do not go above this frequency when throttling */
|
||||
|
||||
if (tegra_cpu_is_throttling()) {
|
||||
unsigned int throttle_limit =
|
||||
freq_table[THROTTLE_START_INDEX].frequency;
|
||||
|
||||
if (new_speed > throttle_limit) {
|
||||
if (tegra_getspeed(0) < throttle_limit) {
|
||||
new_speed = throttle_limit;
|
||||
} else {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_speed = throttle_governor_speed(tegra_cpu_highest_speed());
|
||||
ret = tegra_update_cpu_speed(new_speed);
|
||||
out:
|
||||
mutex_unlock(&tegra_cpu_lock);
|
||||
@@ -381,6 +363,9 @@ static int tegra_cpu_exit(struct cpufreq_policy *policy)
|
||||
|
||||
static struct freq_attr *tegra_cpufreq_attr[] = {
|
||||
&cpufreq_freq_attr_scaling_available_freqs,
|
||||
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
|
||||
&throttle,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -397,7 +382,13 @@ static struct cpufreq_driver tegra_cpufreq_driver = {
|
||||
static int __init tegra_cpufreq_init(void)
|
||||
{
|
||||
#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
|
||||
workqueue = create_singlethread_workqueue("cpu-tegra");
|
||||
/*
|
||||
* High-priority, others flags default: not bound to a specific
|
||||
* CPU, has rescue worker task (in case of allocation deadlock,
|
||||
* etc.). Single-threaded.
|
||||
*/
|
||||
workqueue = alloc_workqueue("cpu-tegra",
|
||||
WQ_HIGHPRI | WQ_UNBOUND | WQ_RESCUER, 1);
|
||||
if (!workqueue)
|
||||
return -ENOMEM;
|
||||
INIT_DELAYED_WORK(&throttle_work, tegra_throttle_work_func);
|
||||
|
||||
@@ -568,13 +568,16 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
|
||||
int stop = (i == (num - 1)) ? 1 : 0;
|
||||
ret = tegra_i2c_xfer_msg(i2c_bus, &msgs[i], stop);
|
||||
if (ret)
|
||||
break;
|
||||
goto out;
|
||||
}
|
||||
ret = i;
|
||||
|
||||
out:
|
||||
clk_disable(i2c_dev->clk);
|
||||
|
||||
rt_mutex_unlock(&i2c_dev->dev_lock);
|
||||
|
||||
return i;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 tegra_i2c_func(struct i2c_adapter *adap)
|
||||
|
||||
@@ -369,7 +369,7 @@ static int get_topmost_window(u32 *depths, unsigned long *wins)
|
||||
{
|
||||
int idx, best = -1;
|
||||
|
||||
for_each_set_bit(idx, wins, sizeof(*wins)) {
|
||||
for_each_set_bit(idx, wins, DC_N_WINDOWS) {
|
||||
if (best == -1 || depths[idx] < depths[best])
|
||||
best = idx;
|
||||
}
|
||||
@@ -406,13 +406,15 @@ static u32 blend_2win(int idx, unsigned long behind_mask, u32* flags, int xy)
|
||||
static u32 blend_3win(int idx, unsigned long behind_mask, u32* flags)
|
||||
{
|
||||
unsigned long infront_mask;
|
||||
int first;
|
||||
|
||||
infront_mask = ~(behind_mask | BIT(idx));
|
||||
infront_mask &= (BIT(DC_N_WINDOWS) - 1);
|
||||
first = ffs(infront_mask) - 1;
|
||||
|
||||
if (!infront_mask)
|
||||
return blend_topwin(flags[idx]);
|
||||
else if (behind_mask && flags[ffs(infront_mask)])
|
||||
else if (behind_mask && first != -1 && flags[first])
|
||||
return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
|
||||
else
|
||||
return BLEND(NOKEY, FIX, 0x0, 0x0);
|
||||
|
||||
@@ -396,7 +396,7 @@
|
||||
#define BLEND_WEIGHT1(x) (((x) & 0xff) << 16)
|
||||
#define BLEND(key, control, weight0, weight1) \
|
||||
(CKEY_ ## key | BLEND_CONTROL_ ## control | \
|
||||
BLEND_WEIGHT0(weight0) | BLEND_WEIGHT0(weight1))
|
||||
BLEND_WEIGHT0(weight0) | BLEND_WEIGHT1(weight1))
|
||||
|
||||
|
||||
#define DC_WIN_HP_FETCH_CONTROL 0x714
|
||||
|
||||
Reference in New Issue
Block a user