linux-omap2: More beagleboard updates from OE.dev

git-svn-id: https://svn.o-hand.com/repos/poky/trunk@5010 311d38ba-8fff-0310-9ca6-ca027cbcb966
This commit is contained in:
Richard Purdie 2008-08-03 13:16:29 +00:00
parent 5e4da78218
commit 1ada01f130
8 changed files with 436 additions and 8 deletions

View File

@ -0,0 +1,25 @@
clear
From: Paul Walmsley <paul@pwsan.com>
---
arch/arm/plat-omap/dmtimer.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index f22506a..e38a11e 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -703,6 +703,10 @@ int __init omap_dm_timer_init(void)
timer->fclk = clk_get(NULL, clk_name);
}
#endif
+ omap_dm_timer_write_status(timer, OMAP_TIMER_INT_OVERFLOW |
+ OMAP_TIMER_INT_MATCH |
+ OMAP_TIMER_INT_CAPTURE);
+
}
return 0;

View File

@ -0,0 +1,97 @@
OMAP2/3 system tick GPTIMER: use match interrupts rather than overflow interrupts
From: Paul Walmsley <paul@pwsan.com>
On some OMAP3 chips, GPTIMER1 will occasionally decline to interrupt
the MPU when a timer overflow event occurs. The timer stops running;
and TOCR is sometimes incremented; but the MPU apparently never receives
the interrupt. This patch was an experiment in using the GPTIMER
match interrupt to determine if it resolves the problem.
Unfortunately, it does not; the same problem occurs with match
interrupts; but this patch is preserved as the base for a
match+overflow interrupt workaround used in a following patch.
---
arch/arm/mach-omap2/timer-gp.c | 32 ++++++++++----------------------
1 files changed, 10 insertions(+), 22 deletions(-)
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 557603f..51996ba 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -36,6 +36,8 @@
#include <asm/mach/time.h>
#include <asm/arch/dmtimer.h>
+#define GPTIMER_MATCH_VAL 0xffff0000
+
static struct omap_dm_timer *gptimer;
static struct clock_event_device clockevent_gpt;
@@ -44,7 +46,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id;
struct clock_event_device *evt = &clockevent_gpt;
- omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_OVERFLOW);
+ omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_MATCH);
evt->event_handler(evt);
return IRQ_HANDLED;
@@ -59,7 +61,7 @@ static struct irqaction omap2_gp_timer_irq = {
static int omap2_gp_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
- omap_dm_timer_set_load_start(gptimer, 0, 0xffffffff - cycles);
+ omap_dm_timer_set_load_start(gptimer, 0, GPTIMER_MATCH_VAL - cycles);
return 0;
}
@@ -67,29 +69,12 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles,
static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
- u32 period;
-
omap_dm_timer_stop(gptimer);
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ;
- period -= 1;
-
- omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period);
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_RESUME:
- break;
- }
}
static struct clock_event_device clockevent_gpt = {
.name = "gp timer",
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
.shift = 32,
.set_next_event = omap2_gp_timer_set_next_event,
.set_mode = omap2_gp_timer_set_mode,
@@ -111,12 +96,15 @@ static void __init omap2_gp_clockevent_init(void)
omap2_gp_timer_irq.dev_id = (void *)gptimer;
setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq);
- omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
+ omap_dm_timer_stop(gptimer);
+ /* omap_dm_timer_set_load(gptimer, 0, 0);*/
+ omap_dm_timer_set_match(gptimer, 1, GPTIMER_MATCH_VAL);
+ omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_MATCH);
clockevent_gpt.mult = div_sc(tick_rate, NSEC_PER_SEC,
clockevent_gpt.shift);
clockevent_gpt.max_delta_ns =
- clockevent_delta2ns(0xffffffff, &clockevent_gpt);
+ clockevent_delta2ns(GPTIMER_MATCH_VAL, &clockevent_gpt);
clockevent_gpt.min_delta_ns =
clockevent_delta2ns(1, &clockevent_gpt);

View File

@ -0,0 +1,94 @@
OMAP2/3 system tick GPTIMER: use overflow interrupts to detect missing match interrupts
From: Paul Walmsley <paul@pwsan.com>
GPTIMER1 on some OMAP3 chips occasionally misses match conditions
between the timer counter and the target register value, and does not
interrupt to the MPU. This patch adds another line of defense by
setting the timer to generate an overflow interrupt 0.5 seconds after the
timer passes the original comparison value.
If interrupts are masked for a long period of time, one would expect
both a match and an overflow interrupt to be logged. This is considered
a normal condition. However, if only an overflow interrupt is logged,
this is considered evidence of a hardware bug and the kernel will issue
a warning.
This workaround is unlikely to be 100% effective, since GPTIMER1 has
also been observed to lose overflow interrupts occasionally. It is
hoped that the probability of losing both will be significantly lower
than the probability of losing either one.
---
arch/arm/mach-omap2/timer-gp.c | 36 ++++++++++++++++++++++++++++++++----
1 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 51996ba..ce5c2b4 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -36,17 +36,43 @@
#include <asm/mach/time.h>
#include <asm/arch/dmtimer.h>
-#define GPTIMER_MATCH_VAL 0xffff0000
+/*
+ * The number of timer ticks to delay will be subtracted from
+ * GPTIMER_MATCH_VAL before loading into the timer. So GPTIMER_MATCH_VAL
+ * constrains the longest delay that can be generated with the timer.
+ * Since the current code uses overflow interrupts as protection against
+ * missed comparison interrupts, this value should also be sufficiently
+ * large such that there is not an excessively long delay between ticks
+ * if the comparison interrupt fails to arrive. The 0xfffff800 value
+ * below results in a half-second delay in such a case when using
+ * the 32kHz timer as source.
+ */
+#define GPTIMER_MATCH_VAL (0xffffffff - (32768/2))
static struct omap_dm_timer *gptimer;
static struct clock_event_device clockevent_gpt;
+static u32 last_load;
+
static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
{
struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id;
struct clock_event_device *evt = &clockevent_gpt;
-
- omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_MATCH);
+ u32 v;
+
+ v = omap_dm_timer_read_status(gpt);
+ if ((v & OMAP_TIMER_INT_OVERFLOW) && !(v & OMAP_TIMER_INT_MATCH)) {
+ /*
+ * Should never happen. Current belief is that this is
+ * due to a hardware bug in the GPTIMER block on some
+ * OMAP3 revisions.
+ */
+ pr_err("*** GPTIMER missed match interrupt! last load: %08x\n",
+ last_load);
+ WARN_ON(1);
+ }
+
+ omap_dm_timer_write_status(gpt, v);
evt->event_handler(evt);
return IRQ_HANDLED;
@@ -61,6 +87,7 @@ static struct irqaction omap2_gp_timer_irq = {
static int omap2_gp_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
+ last_load = GPTIMER_MATCH_VAL - cycles;
omap_dm_timer_set_load_start(gptimer, 0, GPTIMER_MATCH_VAL - cycles);
return 0;
@@ -99,7 +126,8 @@ static void __init omap2_gp_clockevent_init(void)
omap_dm_timer_stop(gptimer);
/* omap_dm_timer_set_load(gptimer, 0, 0);*/
omap_dm_timer_set_match(gptimer, 1, GPTIMER_MATCH_VAL);
- omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_MATCH);
+ omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_MATCH |
+ OMAP_TIMER_INT_OVERFLOW);
clockevent_gpt.mult = div_sc(tick_rate, NSEC_PER_SEC,
clockevent_gpt.shift);

View File

@ -0,0 +1,110 @@
Add extra debug for the q_d_w_o() when work fn is already active.
From: Paul Walmsley <paul@pwsan.com>
---
arch/arm/mach-omap2/timer-gp.c | 3 ++-
arch/arm/plat-omap/dmtimer.c | 20 ++++++++++++++++++++
include/asm-arm/arch-omap/dmtimer.h | 1 +
kernel/time/timer_list.c | 8 ++++++++
4 files changed, 31 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index ce5c2b4..e3ed368 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -50,6 +50,7 @@
#define GPTIMER_MATCH_VAL (0xffffffff - (32768/2))
static struct omap_dm_timer *gptimer;
+struct omap_dm_timer *gptimer_pub;
static struct clock_event_device clockevent_gpt;
static u32 last_load;
@@ -111,7 +112,7 @@ static void __init omap2_gp_clockevent_init(void)
{
u32 tick_rate;
- gptimer = omap_dm_timer_request_specific(1);
+ gptimer = gptimer_pub = omap_dm_timer_request_specific(1);
BUG_ON(gptimer == NULL);
#if defined(CONFIG_OMAP_32K_TIMER)
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index e38a11e..b10f8ac 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -614,6 +614,26 @@ void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value);
}
+void omap_dm_timer_dump_int_enable(struct omap_dm_timer *timer)
+{
+ u32 l;
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
+ pr_err("GPT TCRR: %08x\n", l);
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_MATCH_REG);
+ pr_err("GPT TMAT: %08x\n", l);
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+ pr_err("GPT TISR: %08x\n", l);
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_INT_EN_REG);
+ pr_err("GPT TIER: %08x\n", l);
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+ pr_err("GPT TCLR: %08x\n", l);
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_TICK_INT_MASK_SET_REG);
+ pr_err("GPT TOCR: %08x\n", l);
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_TICK_INT_MASK_COUNT_REG);
+ pr_err("GPT TOWR: %08x\n", l);
+}
+
+
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
{
unsigned int l;
diff --git a/include/asm-arm/arch-omap/dmtimer.h b/include/asm-arm/arch-omap/dmtimer.h
index 02b29e8..a8123e9 100644
--- a/include/asm-arm/arch-omap/dmtimer.h
+++ b/include/asm-arm/arch-omap/dmtimer.h
@@ -73,6 +73,7 @@ void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler);
void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, unsigned int value);
+void omap_dm_timer_dump_int_enable(struct omap_dm_timer *timer);
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer);
void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value);
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer);
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index a40e20f..452eab7 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -18,6 +18,8 @@
#include <linux/kallsyms.h>
#include <linux/tick.h>
+#include <asm/arch/dmtimer.h>
+
#include <asm/uaccess.h>
typedef void (*print_fn_t)(struct seq_file *m, unsigned int *classes);
@@ -239,6 +241,8 @@ static void timer_list_show_tickdevices(struct seq_file *m)
static void timer_list_show_tickdevices(struct seq_file *m) { }
#endif
+extern struct omap_dm_timer *gptimer_pub;
+
static int timer_list_show(struct seq_file *m, void *v)
{
u64 now = ktime_to_ns(ktime_get());
@@ -254,6 +258,10 @@ static int timer_list_show(struct seq_file *m, void *v)
SEQ_printf(m, "\n");
timer_list_show_tickdevices(m);
+ SEQ_printf(m, "\n");
+
+ omap_dm_timer_dump_int_enable(gptimer_pub);
+
return 0;
}

View File

@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.26-rc9-omap1
# Tue Jul 8 15:36:02 2008
# Linux kernel version: 2.6.26-omap1
# Wed Jul 30 14:28:15 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@ -331,6 +331,7 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_VFP=y
CONFIG_VFPv3=y
CONFIG_NEON=y
CONFIG_NEON_CACHE_BUG=y
#
# Userspace binary formats
@ -1406,9 +1407,7 @@ CONFIG_USB_MUSB_SOC=y
CONFIG_USB_MUSB_OTG=y
CONFIG_USB_GADGET_MUSB_HDRC=y
CONFIG_USB_MUSB_HDRC_HCD=y
# CONFIG_MUSB_PIO_ONLY is not set
CONFIG_USB_INVENTRA_DMA=y
# CONFIG_USB_TI_CPPI_DMA is not set
CONFIG_MUSB_PIO_ONLY=y
CONFIG_USB_MUSB_LOGLEVEL=0
#

View File

@ -0,0 +1,75 @@
From: Mans Rullgard <mans@mansr.com>
Date: Wed, 30 Jul 2008 08:25:51 +0000 (+0100)
Subject: ARM: NEON L1 cache bug workaround (erratum 451034)
X-Git-Url: http://git.mansr.com/?p=linux-omap;a=commitdiff_plain;h=26023493baf13e0a67fd6cf08d87be5ff6f7c56d
ARM: NEON L1 cache bug workaround (erratum 451034)
On Cortex-A8 r1p0 and r1p1, executing a NEON store with an integer
store in the store buffer, can cause a processor deadlock under
certain conditions.
Executing a DMB instruction before saving NEON/VFP registers and before
return to userspace makes it safe to run code which includes similar
counter-measures. Userspace code can still trigger the deadlock, so
a different workaround is required to safely run untrusted code.
See ARM Cortex-A8 Errata Notice (PR120-PRDC-008070) for full details.
---
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 8c75840..1172e14 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1071,6 +1071,22 @@ config NEON
Say Y to include support code for NEON, the ARMv7 Advanced SIMD
Extension.
+config NEON_CACHE_BUG
+ bool "NEON L1 cache bug workaround (erratum 451034)"
+ depends on VFPv3
+ help
+ On Cortex-A8 r1p0 and r1p1, executing a NEON store with an integer
+ store in the store buffer, can cause a processor deadlock under
+ certain conditions.
+
+ See ARM Cortex-A8 Errata Notice (PR120-PRDC-008070) for full details.
+
+ Say Y to include a workaround.
+
+ WARNING: Even with this option enabled, userspace code can trigger
+ the deadlock. To safely run untrusted code, a different fix is
+ required.
+
endmenu
menu "Userspace binary formats"
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 597ed00..e50094e 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -68,6 +68,10 @@ no_work_pending:
/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr
+#ifdef CONFIG_NEON_CACHE_BUG
+ dmb
+#endif
+
@ slow_restore_user_regs
ldr r1, [sp, #S_PSR] @ get calling cpsr
ldr lr, [sp, #S_PC]! @ get pc
diff --git a/include/asm-arm/vfpmacros.h b/include/asm-arm/vfpmacros.h
index cccb389..c9d2976 100644
--- a/include/asm-arm/vfpmacros.h
+++ b/include/asm-arm/vfpmacros.h
@@ -32,6 +32,9 @@
@ write all the working registers out of the VFP
.macro VFPFSTMIA, base, tmp
+#ifdef CONFIG_NEON_CACHE_BUG
+ dmb
+#endif
#if __LINUX_ARM_ARCH__ < 6
STC p11, cr0, [\base],#33*4 @ FSTMIAX \base!, {d0-d15}
#else

View File

@ -0,0 +1,23 @@
OMAP2/3 TAP: enable debug messages
From: Paul Walmsley <paul@pwsan.com>
This patch causes the OMAP2/3 chip ID code to display the full DIE_ID registers at boot.
---
arch/arm/mach-omap2/id.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index c7f9ab7..a154b5e 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -10,6 +10,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#define DEBUG
#include <linux/module.h>
#include <linux/kernel.h>

View File

@ -5,8 +5,8 @@ FILESPATH = "${@os.path.dirname(bb.data.getVar('FILE',d,1))}/linux-omap2-git/${M
SRCREV = "d3b3ae0fe6c71641da19c8de466ec366d39847e3"
PV = "2.6.26"
#PV = "2.6.25+2.6.26-rc9+${PR}+git${SRCREV}"
PR = "r49"
#PV = "2.6.26+2.6.27-rc1+${PR}+git${SRCREV}"
PR = "r53"
SRC_URI = "git://source.mvista.com/git/linux-omap-2.6.git;protocol=git \
file://fixes.patch;patch=1 \
@ -30,7 +30,6 @@ SRC_URI_append_beagleboard = " file://no-harry-potter.diff;patch=1 \
file://06-ensure-fclk.diff;patch=1 \
file://07-set-burst-size.diff;patch=1 \
file://cache-display-fix.patch;patch=1 \
file://serialfix.diff;patch=1 \
file://i2c-omap-race-fix.diff;patch=1 \
file://TWL4030-01.patch;patch=1 \
file://TWL4030-02.patch;patch=1 \
@ -46,6 +45,12 @@ SRC_URI_append_beagleboard = " file://no-harry-potter.diff;patch=1 \
file://mru-clocks3.diff;patch=1 \
file://4bitmmc.diff;patch=1 \
file://400khz-i2c.diff;patch=1 \
file://no-cortex-deadlock.patch;patch=1 \
file://01-gptimer_clear_isrs_on_init;patch=1 \
file://02-gptimer_use_match_for_tick;patch=1 \
file://03-gptimer_match_plus_ovf;patch=1 \
file://04-gptimer_add_debug_to_sysrq_q;patch=1 \
file://read_die_ids.patch;patch=1 \
"
SRC_URI_append_omap3evm = " file://no-harry-potter.diff;patch=1 \