summaryrefslogtreecommitdiff
path: root/arch/arm
diff options
context:
space:
mode:
authorNitin Kumbhar <nkumbhar@nvidia.com>2010-12-23 14:58:35 +0530
committerNitin Kumbhar <nkumbhar@nvidia.com>2010-12-23 14:58:35 +0530
commit96a476b53360de76f20774122111f031be9ac9c2 (patch)
treee603fb33cb93cac7bbcc750bbaea8010a22dcea7 /arch/arm
parent8302d262e4801d44fa1b1952e15666256692b7b6 (diff)
parent3f29a8834975956ed5590959bfced00cb9bd03ed (diff)
merging android-tegra-2.6.36 into git-master/linux-2.6/android-tegra-2.6.36
Conflicts: arch/arm/mach-tegra/board-ventana-power.c drivers/mfd/tps6586x.c Change-Id: Ic8c46d4251d6e71fa2900b7e876f87e256299bc4
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/include/asm/assembler.h2
-rw-r--r--arch/arm/include/asm/kgdb.h5
-rw-r--r--arch/arm/kernel/kgdb.c2
-rw-r--r--arch/arm/lib/findbit.S6
-rw-r--r--arch/arm/mach-cns3xxx/include/mach/debug-macro.S2
-rw-r--r--arch/arm/mach-cns3xxx/pcie.c2
-rw-r--r--arch/arm/mach-tegra/Kconfig7
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c263
-rw-r--r--arch/arm/mm/fault-armv.c28
-rw-r--r--arch/arm/plat-omap/dma.c50
-rw-r--r--arch/arm/plat-omap/include/plat/dma.h4
11 files changed, 224 insertions, 147 deletions
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 6e8f05c8a1c8..d7575554e407 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -215,7 +215,7 @@
@ Slightly optimised to avoid incrementing the pointer twice
usraccoff \instr, \reg, \ptr, \inc, 0, \cond, \abort
.if \rept == 2
- usraccoff \instr, \reg, \ptr, \inc, 4, \cond, \abort
+ usraccoff \instr, \reg, \ptr, \inc, \inc, \cond, \abort
.endif
add\cond \ptr, #\rept * \inc
diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h
index 08265993227f..48066ce9ea34 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -70,7 +70,8 @@ extern int kgdb_fault_expected;
#define _GP_REGS 16
#define _FP_REGS 8
#define _EXTRA_REGS 2
-#define DBG_MAX_REG_NUM (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
+#define GDB_MAX_REGS (_GP_REGS + (_FP_REGS * 3) + _EXTRA_REGS)
+#define DBG_MAX_REG_NUM (_GP_REGS + _FP_REGS + _EXTRA_REGS)
#define KGDB_MAX_NO_CPUS 1
#define BUFMAX 400
@@ -93,7 +94,7 @@ extern int kgdb_fault_expected;
#define _SPT 13
#define _LR 14
#define _PC 15
-#define _CPSR (DBG_MAX_REG_NUM - 1)
+#define _CPSR (GDB_MAX_REGS - 1)
/*
* So that we can denote the end of a frame for tracing,
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c
index d6e8b4d2e60d..778c2f7024ff 100644
--- a/arch/arm/kernel/kgdb.c
+++ b/arch/arm/kernel/kgdb.c
@@ -79,7 +79,7 @@ sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
return;
/* Initialize to zero */
- for (regno = 0; regno < DBG_MAX_REG_NUM; regno++)
+ for (regno = 0; regno < GDB_MAX_REGS; regno++)
gdb_regs[regno] = 0;
/* Otherwise, we have only some registers from switch_to() */
diff --git a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S
index 1e4cbd4e7be9..64f6bc1a9132 100644
--- a/arch/arm/lib/findbit.S
+++ b/arch/arm/lib/findbit.S
@@ -174,8 +174,8 @@ ENDPROC(_find_next_bit_be)
*/
.L_found:
#if __LINUX_ARM_ARCH__ >= 5
- rsb r1, r3, #0
- and r3, r3, r1
+ rsb r0, r3, #0
+ and r3, r3, r0
clz r3, r3
rsb r3, r3, #31
add r0, r2, r3
@@ -190,5 +190,7 @@ ENDPROC(_find_next_bit_be)
addeq r2, r2, #1
mov r0, r2
#endif
+ cmp r1, r0 @ Clamp to maxbit
+ movlo r0, r1
mov pc, lr
diff --git a/arch/arm/mach-cns3xxx/include/mach/debug-macro.S b/arch/arm/mach-cns3xxx/include/mach/debug-macro.S
index d16ce7eb00e9..9b50442d4b9b 100644
--- a/arch/arm/mach-cns3xxx/include/mach/debug-macro.S
+++ b/arch/arm/mach-cns3xxx/include/mach/debug-macro.S
@@ -10,7 +10,7 @@
* published by the Free Software Foundation.
*/
- .macro addruart,rx
+ .macro addruart,rx,rtmp
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
moveq \rx, #0x10000000
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
index 38088c36936c..78defd71a829 100644
--- a/arch/arm/mach-cns3xxx/pcie.c
+++ b/arch/arm/mach-cns3xxx/pcie.c
@@ -369,7 +369,7 @@ static int __init cns3xxx_pcie_init(void)
{
int i;
- hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS,
+ hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0,
"imprecise external abort");
for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 1412df271021..f38f4ed94b5b 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -108,3 +108,10 @@ config TEGRA_IOVMM
config TEGRA_ARB_SEMAPHORE
bool
+
+config TEGRA_THERMAL_THROTTLE
+ bool "Enable throttling of CPU speed on overtemp"
+ depends on CPU_FREQ
+ default y
+ help
+ Also requires enabling a temperature sensor such as NCT1008.
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index d8c103e8964c..a878545d2740 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -50,27 +50,131 @@ static struct cpufreq_frequency_table freq_table[] = {
{ 8, CPUFREQ_TABLE_END },
};
-/* CPU frequency is gradually lowered when throttling is enabled */
-#define THROTTLE_START_INDEX 2
-#define THROTTLE_END_INDEX 6
-#define THROTTLE_DELAY msecs_to_jiffies(2000)
-#define NO_DELAY msecs_to_jiffies(0)
-
#define NUM_CPUS 2
static struct clk *cpu_clk;
static struct clk *emc_clk;
-static struct workqueue_struct *workqueue;
-
static unsigned long target_cpu_speed[NUM_CPUS];
static DEFINE_MUTEX(tegra_cpu_lock);
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
+
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
+#define THROTTLE_DELAY msecs_to_jiffies(2000)
+#define NO_DELAY msecs_to_jiffies(0)
+
static DEFINE_MUTEX(throttling_lock);
static bool is_throttling;
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;
+
+ mutex_lock(&tegra_cpu_lock);
+
+ if (tegra_throttling_needed(&rate) && tegra_update_cpu_speed(rate) == 0) {
+ queue_delayed_work(workqueue, &throttle_work, THROTTLE_DELAY);
+ }
+
+ mutex_unlock(&tegra_cpu_lock);
+}
+
+/*
+ * tegra_throttling_enable
+ * This function may sleep
+ */
+void tegra_throttling_enable(bool enable)
+{
+ mutex_lock(&throttling_lock);
+
+ if (enable && !is_throttling) {
+ is_throttling = true;
+ queue_delayed_work(workqueue, &throttle_work, NO_DELAY);
+ } else if (!enable && is_throttling) {
+ cancel_delayed_work_sync(&throttle_work);
+ is_throttling = false;
+ }
+
+ mutex_unlock(&throttling_lock);
+}
+EXPORT_SYMBOL_GPL(tegra_throttling_enable);
+
+#ifdef CONFIG_DEBUG_FS
+static int throttle_debug_set(void *data, u64 val)
+{
+ tegra_throttling_enable(val);
+ return 0;
+}
+static int throttle_debug_get(void *data, u64 *val)
+{
+ *val = (u64) is_throttling;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(throttle_fops, throttle_debug_get, throttle_debug_set, "%llu\n");
+
+static struct dentry *cpu_tegra_debugfs_root;
+
+static int __init tegra_cpu_debug_init(void)
+{
+ cpu_tegra_debugfs_root = debugfs_create_dir("cpu-tegra", 0);
+
+ if (!cpu_tegra_debugfs_root)
+ return -ENOMEM;
+
+ if (!debugfs_create_file("throttle", 0644, cpu_tegra_debugfs_root, NULL, &throttle_fops))
+ goto err_out;
+
+ return 0;
+
+err_out:
+ debugfs_remove_recursive(cpu_tegra_debugfs_root);
+ return -ENOMEM;
+
+}
+
+static void __exit tegra_cpu_debug_exit(void)
+{
+ debugfs_remove_recursive(cpu_tegra_debugfs_root);
+}
+
+late_initcall(tegra_cpu_debug_init);
+module_exit(tegra_cpu_debug_exit);
+#endif /* CONFIG_DEBUG_FS */
+
+#else /* CONFIG_TEGRA_THERMAL_THROTTLE */
+#define tegra_cpu_is_throttling() (0)
+void tegra_throttling_enable(bool enable)
+{
+}
+#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */
int tegra_verify_speed(struct cpufreq_policy *policy)
{
@@ -169,8 +273,7 @@ static int tegra_target(struct cpufreq_policy *policy,
{
int idx;
unsigned int freq;
- unsigned int highest_speed;
- unsigned int limit_when_throttling;
+ unsigned int new_speed;
int ret = 0;
mutex_lock(&tegra_cpu_lock);
@@ -187,136 +290,30 @@ static int tegra_target(struct cpufreq_policy *policy,
target_cpu_speed[policy->cpu] = freq;
- highest_speed = tegra_cpu_highest_speed();
+ new_speed = tegra_cpu_highest_speed();
/* Do not go above this frequency when throttling */
- limit_when_throttling = freq_table[THROTTLE_START_INDEX].frequency;
-
- if (is_throttling && highest_speed > limit_when_throttling) {
- if (tegra_getspeed(0) < limit_when_throttling) {
- ret = tegra_update_cpu_speed(limit_when_throttling);
- goto out;
- } else {
- ret = -EBUSY;
- goto out;
+
+ 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;
+ }
}
}
- ret = tegra_update_cpu_speed(highest_speed);
+ ret = tegra_update_cpu_speed(new_speed);
out:
mutex_unlock(&tegra_cpu_lock);
return ret;
}
-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;
-
- mutex_lock(&tegra_cpu_lock);
-
- if (tegra_throttling_needed(&rate) && tegra_update_cpu_speed(rate) == 0) {
- queue_delayed_work(workqueue, &throttle_work, THROTTLE_DELAY);
- }
-
- mutex_unlock(&tegra_cpu_lock);
-}
-
-/**
- * tegra_throttling_enable
- * This functions may sleep
- */
-void tegra_throttling_enable(void)
-{
- mutex_lock(&throttling_lock);
-
- if (!is_throttling) {
- is_throttling = true;
- queue_delayed_work(workqueue, &throttle_work, NO_DELAY);
- }
-
- mutex_unlock(&throttling_lock);
-}
-EXPORT_SYMBOL_GPL(tegra_throttling_enable);
-
-/**
- * tegra_throttling_disable
- * This functions may sleep
- */
-void tegra_throttling_disable(void)
-{
- mutex_lock(&throttling_lock);
-
- if (is_throttling) {
- cancel_delayed_work_sync(&throttle_work);
- is_throttling = false;
- }
-
- mutex_unlock(&throttling_lock);
-}
-EXPORT_SYMBOL_GPL(tegra_throttling_disable);
-
-#ifdef CONFIG_DEBUG_FS
-static int throttle_debug_set(void *data, u64 val)
-{
- if (val) {
- tegra_throttling_enable();
- } else {
- tegra_throttling_disable();
- }
-
- return 0;
-}
-static int throttle_debug_get(void *data, u64 *val)
-{
- *val = (u64) is_throttling;
- return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(throttle_fops, throttle_debug_get, throttle_debug_set, "%llu\n");
-
-static struct dentry *cpu_tegra_debugfs_root;
-
-static int __init tegra_cpu_debug_init(void)
-{
- cpu_tegra_debugfs_root = debugfs_create_dir("cpu-tegra", 0);
-
- if (!cpu_tegra_debugfs_root)
- return -ENOMEM;
-
- if (!debugfs_create_file("throttle", 0644, cpu_tegra_debugfs_root, NULL, &throttle_fops))
- goto err_out;
-
- return 0;
-
-err_out:
- debugfs_remove_recursive(cpu_tegra_debugfs_root);
- return -ENOMEM;
-
-}
-
-static void __exit tegra_cpu_debug_exit(void)
-{
- debugfs_remove_recursive(cpu_tegra_debugfs_root);
-}
-
-late_initcall(tegra_cpu_debug_init);
-module_exit(tegra_cpu_debug_exit);
-#endif
static int tegra_pm_notify(struct notifier_block *nb, unsigned long event,
void *dummy)
@@ -367,7 +364,6 @@ static int tegra_cpu_init(struct cpufreq_policy *policy)
cpumask_copy(policy->related_cpus, cpu_possible_mask);
if (policy->cpu == 0) {
- INIT_DELAYED_WORK(&throttle_work, tegra_throttle_work_func);
register_pm_notifier(&tegra_cpu_pm_notifier);
}
@@ -400,15 +396,20 @@ 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");
if (!workqueue)
return -ENOMEM;
+ INIT_DELAYED_WORK(&throttle_work, tegra_throttle_work_func);
+#endif
return cpufreq_register_driver(&tegra_cpufreq_driver);
}
static void __exit tegra_cpufreq_exit(void)
{
+#ifdef CONFIG_TEGRA_THERMAL_THROTTLE
destroy_workqueue(workqueue);
+#endif
cpufreq_unregister_driver(&tegra_cpufreq_driver);
}
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index 030f1dab88f7..33486f952d63 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -66,6 +66,30 @@ static int do_adjust_pte(struct vm_area_struct *vma, unsigned long address,
return ret;
}
+#if USE_SPLIT_PTLOCKS
+/*
+ * If we are using split PTE locks, then we need to take the page
+ * lock here. Otherwise we are using shared mm->page_table_lock
+ * which is already locked, thus cannot take it.
+ */
+static inline void do_pte_lock(spinlock_t *ptl)
+{
+ /*
+ * Use nested version here to indicate that we are already
+ * holding one similar spinlock.
+ */
+ spin_lock_nested(ptl, SINGLE_DEPTH_NESTING);
+}
+
+static inline void do_pte_unlock(spinlock_t *ptl)
+{
+ spin_unlock(ptl);
+}
+#else /* !USE_SPLIT_PTLOCKS */
+static inline void do_pte_lock(spinlock_t *ptl) {}
+static inline void do_pte_unlock(spinlock_t *ptl) {}
+#endif /* USE_SPLIT_PTLOCKS */
+
static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
unsigned long pfn)
{
@@ -90,11 +114,11 @@ static int adjust_pte(struct vm_area_struct *vma, unsigned long address,
*/
ptl = pte_lockptr(vma->vm_mm, pmd);
pte = pte_offset_map_nested(pmd, address);
- spin_lock(ptl);
+ do_pte_lock(ptl);
ret = do_adjust_pte(vma, address, pfn, pte);
- spin_unlock(ptl);
+ do_pte_unlock(ptl);
pte_unmap_nested(pte);
return ret;
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index ec7eddf9e525..f5c5b8da9a87 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -30,6 +30,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <asm/system.h>
#include <mach/hardware.h>
@@ -996,11 +997,17 @@ void omap_start_dma(int lch)
l = dma_read(CCR(lch));
/*
- * Errata: On ES2.0 BUFFERING disable must be set.
- * This will always fail on ES1.0
+ * Errata: Inter Frame DMA buffering issue (All OMAP2420 and
+ * OMAP2430ES1.0): DMA will wrongly buffer elements if packing and
+ * bursting is enabled. This might result in data gets stalled in
+ * FIFO at the end of the block.
+ * Workaround: DMA channels must have BUFFERING_DISABLED bit set to
+ * guarantee no data will stay in the DMA FIFO in case inter frame
+ * buffering occurs.
*/
- if (cpu_is_omap24xx())
- l |= OMAP_DMA_CCR_EN;
+ if (cpu_is_omap2420() ||
+ (cpu_is_omap2430() && (omap_type() == OMAP2430_REV_ES1_0)))
+ l |= OMAP_DMA_CCR_BUFFERING_DISABLE;
l |= OMAP_DMA_CCR_EN;
dma_write(l, CCR(lch));
@@ -1018,8 +1025,39 @@ void omap_stop_dma(int lch)
dma_write(0, CICR(lch));
l = dma_read(CCR(lch));
- l &= ~OMAP_DMA_CCR_EN;
- dma_write(l, CCR(lch));
+ /* OMAP3 Errata i541: sDMA FIFO draining does not finish */
+ if (cpu_is_omap34xx() && (l & OMAP_DMA_CCR_SEL_SRC_DST_SYNC)) {
+ int i = 0;
+ u32 sys_cf;
+
+ /* Configure No-Standby */
+ l = dma_read(OCP_SYSCONFIG);
+ sys_cf = l;
+ l &= ~DMA_SYSCONFIG_MIDLEMODE_MASK;
+ l |= DMA_SYSCONFIG_MIDLEMODE(DMA_IDLEMODE_NO_IDLE);
+ dma_write(l , OCP_SYSCONFIG);
+
+ l = dma_read(CCR(lch));
+ l &= ~OMAP_DMA_CCR_EN;
+ dma_write(l, CCR(lch));
+
+ /* Wait for sDMA FIFO drain */
+ l = dma_read(CCR(lch));
+ while (i < 100 && (l & (OMAP_DMA_CCR_RD_ACTIVE |
+ OMAP_DMA_CCR_WR_ACTIVE))) {
+ udelay(5);
+ i++;
+ l = dma_read(CCR(lch));
+ }
+ if (i >= 100)
+ printk(KERN_ERR "DMA drain did not complete on "
+ "lch %d\n", lch);
+ /* Restore OCP_SYSCONFIG */
+ dma_write(sys_cf, OCP_SYSCONFIG);
+ } else {
+ l &= ~OMAP_DMA_CCR_EN;
+ dma_write(l, CCR(lch));
+ }
if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
int next_lch, cur_lch = lch;
diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h
index af3a03941add..cf66f85a011c 100644
--- a/arch/arm/plat-omap/include/plat/dma.h
+++ b/arch/arm/plat-omap/include/plat/dma.h
@@ -335,6 +335,10 @@
#define OMAP2_DMA_MISALIGNED_ERR_IRQ (1 << 11)
#define OMAP_DMA_CCR_EN (1 << 7)
+#define OMAP_DMA_CCR_RD_ACTIVE (1 << 9)
+#define OMAP_DMA_CCR_WR_ACTIVE (1 << 10)
+#define OMAP_DMA_CCR_SEL_SRC_DST_SYNC (1 << 24)
+#define OMAP_DMA_CCR_BUFFERING_DISABLE (1 << 25)
#define OMAP_DMA_DATA_TYPE_S8 0x00
#define OMAP_DMA_DATA_TYPE_S16 0x01