Merge branch android-tegra-2.6.36 into android-tegra-moto-2.6.36

Change-Id: I3a5bce1a80f73fd289031d7f329b67eaaf6ce8b5
This commit is contained in:
Erik Gilling
2011-01-04 17:54:53 -08:00
6 changed files with 147 additions and 117 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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