summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Murphy <dmurphy@ti.com>2011-10-26 10:17:18 -0500
committerDan Murphy <dmurphy@ti.com>2011-10-26 10:17:18 -0500
commitbb10c38c127952a7d84cb0b9d6ce8090b61bdd40 (patch)
tree0b90e2f4e0023a9710c41ce6a18907a591108217
parent0700a3c3af2f21c6b226dc2c9b7a2b7eeb4cc6fa (diff)
parent99ae0ab9af0b3c53de250c6a7e9d09793f9add0b (diff)
Merge branch 'android-omap-3.0' into p-android-omap-3.0android-3.0-4AI.3
* android-omap-3.0: ARM: omap4: check debug uart wake status on i/o pad wakeup ARM: omap2: fiq_debugger: restore UART state after ctxt lost ARM: omap4: add OMAP support for the fiq debugger ARM: common: fiq_debugger: protect the uart state from the sleep timer ARM: common: fiq_debugger: add suspend/resume handlers ARM: common: fiq_debugger: add uart_enable/disable platform callbacks ARM: common: fiq_debugger: add non-fiq debugger support ARM: common: fiq_debugger: peek the 0th char in ringbuf ARM: common: fiq_debugger: fix the cleanup on errors in probe ARM: common: fiq_debugger: do not disable debug when console is enabled ARM: omap4: resetreason: add newline to end of reset reason string ram_console: pass in a boot info string Revert "omap: dispc: force L3_1 CD to NOSLEEP when dispc module is active." ARM: omap4: cpuidle: configure MPU C4 state to CSWR ARM: omap4: resetreason: export reset reason string Change-Id: Ifc32c00529e08f43dc2f618a917c168b0a66f8f5 Signed-off-by: Dan Murphy <dmurphy@ti.com>
-rw-r--r--arch/arm/common/fiq_debugger.c320
-rw-r--r--arch/arm/include/asm/fiq_debugger.h18
-rw-r--r--arch/arm/mach-omap2/Kconfig7
-rw-r--r--arch/arm/mach-omap2/Makefile1
-rw-r--r--arch/arm/mach-omap2/cpuidle44xx.c17
-rw-r--r--arch/arm/mach-omap2/include/mach/omap_fiq_debugger.h35
-rw-r--r--arch/arm/mach-omap2/omap_fiq_debugger.c418
-rw-r--r--arch/arm/mach-omap2/pm44xx.c3
-rw-r--r--arch/arm/mach-omap2/resetreason.c58
-rw-r--r--arch/arm/mach-omap2/resetreason.h22
-rw-r--r--drivers/staging/android/ram_console.c45
-rw-r--r--include/linux/platform_data/ram_console.h22
12 files changed, 856 insertions, 110 deletions
diff --git a/arch/arm/common/fiq_debugger.c b/arch/arm/common/fiq_debugger.c
index 080f69edd75..a120b75afe3 100644
--- a/arch/arm/common/fiq_debugger.c
+++ b/arch/arm/common/fiq_debugger.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/smp.h>
#include <linux/timer.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -53,6 +54,7 @@ struct fiq_debugger_state {
struct fiq_glue_handler handler;
int fiq;
+ int uart_irq;
int signal_irq;
int wakeup_irq;
bool wakeup_irq_no_set_wake;
@@ -71,7 +73,8 @@ struct fiq_debugger_state {
bool debug_enable;
bool ignore_next_wakeup_irq;
struct timer_list sleep_timer;
- bool uart_clk_enabled;
+ spinlock_t sleep_timer_lock;
+ bool uart_enabled;
struct wake_lock debugger_wake_lock;
bool console_enable;
int current_cpu;
@@ -130,18 +133,42 @@ static inline void disable_wakeup_irq(struct fiq_debugger_state *state)
}
#endif
+static bool inline debug_have_fiq(struct fiq_debugger_state *state)
+{
+ return (state->fiq >= 0);
+}
+
static void debug_force_irq(struct fiq_debugger_state *state)
{
unsigned int irq = state->signal_irq;
- if (state->pdata->force_irq)
+
+ if (WARN_ON(!debug_have_fiq(state)))
+ return;
+ if (state->pdata->force_irq) {
state->pdata->force_irq(state->pdev, irq);
- else {
+ } else {
struct irq_chip *chip = irq_get_chip(irq);
if (chip && chip->irq_retrigger)
chip->irq_retrigger(irq_get_irq_data(irq));
}
}
+static void debug_uart_enable(struct fiq_debugger_state *state)
+{
+ if (state->clk)
+ clk_enable(state->clk);
+ if (state->pdata->uart_enable)
+ state->pdata->uart_enable(state->pdev);
+}
+
+static void debug_uart_disable(struct fiq_debugger_state *state)
+{
+ if (state->pdata->uart_disable)
+ state->pdata->uart_disable(state->pdev);
+ if (state->clk)
+ clk_disable(state->clk);
+}
+
static void debug_uart_flush(struct fiq_debugger_state *state)
{
if (state->pdata->uart_flush)
@@ -447,7 +474,7 @@ void dump_stacktrace(struct fiq_debugger_state *state,
tail = user_backtrace(state, tail);
}
-static void debug_help(struct fiq_debugger_state *state)
+static bool debug_help(struct fiq_debugger_state *state)
{
debug_printf(state, "FIQ Debugger commands:\n"
" pc PC status\n"
@@ -466,15 +493,37 @@ static void debug_help(struct fiq_debugger_state *state)
if (!state->debug_busy) {
strcpy(state->debug_cmd, "help");
state->debug_busy = 1;
- debug_force_irq(state);
+ return true;
}
+
+ return false;
+}
+
+static void take_affinity(void *info)
+{
+ struct fiq_debugger_state *state = info;
+ struct cpumask cpumask;
+
+ cpumask_clear(&cpumask);
+ cpumask_set_cpu(get_cpu(), &cpumask);
+
+ irq_set_affinity(state->uart_irq, &cpumask);
+}
+
+static void switch_cpu(struct fiq_debugger_state *state, int cpu)
+{
+ if (!debug_have_fiq(state))
+ smp_call_function_single(cpu, take_affinity, state, false);
+ state->current_cpu = cpu;
}
-static void debug_exec(struct fiq_debugger_state *state,
+static bool debug_exec(struct fiq_debugger_state *state,
const char *cmd, unsigned *regs, void *svc_sp)
{
+ bool signal_helper = false;
+
if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) {
- debug_help(state);
+ signal_helper |= debug_help(state);
} else if (!strcmp(cmd, "pc")) {
debug_printf(state, " pc %08x cpsr %08x mode %s\n",
regs[15], regs[16], mode_name(regs[16]));
@@ -494,8 +543,10 @@ static void debug_exec(struct fiq_debugger_state *state,
debug_printf(state, "%s\n", linux_banner);
} else if (!strcmp(cmd, "sleep")) {
state->no_sleep = false;
+ debug_printf(state, "enabling sleep\n");
} else if (!strcmp(cmd, "nosleep")) {
state->no_sleep = true;
+ debug_printf(state, "disabling sleep\n");
} else if (!strcmp(cmd, "console")) {
state->console_enable = true;
debug_printf(state, "console mode\n");
@@ -504,7 +555,7 @@ static void debug_exec(struct fiq_debugger_state *state,
} else if (!strncmp(cmd, "cpu ", 4)) {
unsigned long cpu = 0;
if (strict_strtoul(cmd + 4, 10, &cpu) == 0)
- state->current_cpu = cpu;
+ switch_cpu(state, cpu);
else
debug_printf(state, "invalid cpu\n");
debug_printf(state, "cpu %d\n", state->current_cpu);
@@ -518,67 +569,79 @@ static void debug_exec(struct fiq_debugger_state *state,
state->debug_busy = 1;
}
- debug_force_irq(state);
-
- return;
+ return true;
}
if (!state->console_enable)
debug_prompt(state);
+
+ return signal_helper;
}
static void sleep_timer_expired(unsigned long data)
{
struct fiq_debugger_state *state = (struct fiq_debugger_state *)data;
+ unsigned long flags;
- if (state->uart_clk_enabled && !state->no_sleep) {
- if (state->debug_enable) {
+ spin_lock_irqsave(&state->sleep_timer_lock, flags);
+ if (state->uart_enabled && !state->no_sleep) {
+ if (state->debug_enable && !state->console_enable) {
state->debug_enable = false;
debug_printf_nfiq(state, "suspending fiq debugger\n");
}
state->ignore_next_wakeup_irq = true;
- if (state->clk)
- clk_disable(state->clk);
- state->uart_clk_enabled = false;
+ debug_uart_disable(state);
+ state->uart_enabled = false;
enable_wakeup_irq(state);
}
wake_unlock(&state->debugger_wake_lock);
+ spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
}
-static irqreturn_t wakeup_irq_handler(int irq, void *dev)
+static void handle_wakeup(struct fiq_debugger_state *state)
{
- struct fiq_debugger_state *state = dev;
+ unsigned long flags;
- if (!state->no_sleep)
- debug_puts(state, "WAKEUP\n");
- if (state->ignore_next_wakeup_irq)
+ spin_lock_irqsave(&state->sleep_timer_lock, flags);
+ if (state->wakeup_irq >= 0 && state->ignore_next_wakeup_irq) {
state->ignore_next_wakeup_irq = false;
- else if (!state->uart_clk_enabled) {
+ } else if (!state->uart_enabled) {
wake_lock(&state->debugger_wake_lock);
- if (state->clk)
- clk_enable(state->clk);
- state->uart_clk_enabled = true;
+ debug_uart_enable(state);
+ state->uart_enabled = true;
disable_wakeup_irq(state);
mod_timer(&state->sleep_timer, jiffies + HZ / 2);
}
- return IRQ_HANDLED;
+ spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
}
-static irqreturn_t debug_irq(int irq, void *dev)
+static irqreturn_t wakeup_irq_handler(int irq, void *dev)
{
struct fiq_debugger_state *state = dev;
- if (state->pdata->force_irq_ack)
- state->pdata->force_irq_ack(state->pdev, state->signal_irq);
+ if (!state->no_sleep)
+ debug_puts(state, "WAKEUP\n");
+ handle_wakeup(state);
+
+ return IRQ_HANDLED;
+}
+
+
+static void debug_handle_irq_context(struct fiq_debugger_state *state)
+{
if (!state->no_sleep) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&state->sleep_timer_lock, flags);
wake_lock(&state->debugger_wake_lock);
mod_timer(&state->sleep_timer, jiffies + HZ * 5);
+ spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
}
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
if (state->tty) {
int i;
int count = fiq_debugger_ringbuf_level(state->tty_rbuf);
for (i = 0; i < count; i++) {
- int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, i);
+ int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0);
tty_insert_flip_char(state->tty, c, TTY_NORMAL);
if (!fiq_debugger_ringbuf_consume(state->tty_rbuf, 1))
pr_warn("fiq tty failed to consume byte\n");
@@ -596,7 +659,6 @@ static irqreturn_t debug_irq(int irq, void *dev)
state->debug_busy = 0;
}
- return IRQ_HANDLED;
}
static int debug_getc(struct fiq_debugger_state *state)
@@ -604,30 +666,29 @@ static int debug_getc(struct fiq_debugger_state *state)
return state->pdata->uart_getc(state->pdev);
}
-static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
+static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state,
+ int this_cpu, void *regs, void *svc_sp)
{
- struct fiq_debugger_state *state =
- container_of(h, struct fiq_debugger_state, handler);
int c;
static int last_c;
int count = 0;
- unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
+ bool signal_helper = false;
if (this_cpu != state->current_cpu) {
if (state->in_fiq)
- return;
+ return false;
if (atomic_inc_return(&state->unhandled_fiq_count) !=
MAX_UNHANDLED_FIQ_COUNT)
- return;
+ return false;
debug_printf(state, "fiq_debugger: cpu %d not responding, "
"reverting to cpu %d\n", state->current_cpu,
this_cpu);
atomic_set(&state->unhandled_fiq_count, 0);
- state->current_cpu = this_cpu;
- return;
+ switch_cpu(state, this_cpu);
+ return false;
}
state->in_fiq = true;
@@ -648,7 +709,7 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
} else if (state->console_enable && state->tty_rbuf) {
fiq_debugger_ringbuf_push(state->tty_rbuf, c);
- debug_force_irq(state);
+ signal_helper = true;
#endif
} else if ((c >= ' ') && (c < 127)) {
if (state->debug_count < (DEBUG_MAX - 1)) {
@@ -670,8 +731,9 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
if (state->debug_count) {
state->debug_buf[state->debug_count] = 0;
state->debug_count = 0;
- debug_exec(state, state->debug_buf,
- regs, svc_sp);
+ signal_helper |=
+ debug_exec(state, state->debug_buf,
+ regs, svc_sp);
} else {
debug_prompt(state);
}
@@ -684,10 +746,63 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
/* poke sleep timer if necessary */
if (state->debug_enable && !state->no_sleep)
- debug_force_irq(state);
+ signal_helper = true;
atomic_set(&state->unhandled_fiq_count, 0);
state->in_fiq = false;
+
+ return signal_helper;
+}
+
+static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
+{
+ struct fiq_debugger_state *state =
+ container_of(h, struct fiq_debugger_state, handler);
+ unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
+ bool need_irq;
+
+ need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp);
+ if (need_irq)
+ debug_force_irq(state);
+}
+
+/*
+ * When not using FIQs, we only use this single interrupt as an entry point.
+ * This just effectively takes over the UART interrupt and does all the work
+ * in this context.
+ */
+static irqreturn_t debug_uart_irq(int irq, void *dev)
+{
+ struct fiq_debugger_state *state = dev;
+ bool not_done;
+
+ handle_wakeup(state);
+
+ /* handle the debugger irq in regular context */
+ not_done = debug_handle_uart_interrupt(state, smp_processor_id(),
+ get_irq_regs(),
+ current_thread_info());
+ if (not_done)
+ debug_handle_irq_context(state);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * If FIQs are used, not everything can happen in fiq context.
+ * FIQ handler does what it can and then signals this interrupt to finish the
+ * job in irq context.
+ */
+static irqreturn_t debug_signal_irq(int irq, void *dev)
+{
+ struct fiq_debugger_state *state = dev;
+
+ if (state->pdata->force_irq_ack)
+ state->pdata->force_irq_ack(state->pdev, state->signal_irq);
+
+ debug_handle_irq_context(state);
+
+ return IRQ_HANDLED;
}
static void debug_resume(struct fiq_glue_handler *h)
@@ -717,12 +832,14 @@ static void debug_console_write(struct console *co,
if (!state->console_enable)
return;
+ debug_uart_enable(state);
while (count--) {
if (*s == '\n')
state->pdata->uart_putc(state->pdev, '\r');
state->pdata->uart_putc(state->pdev, *s++);
}
debug_uart_flush(state);
+ debug_uart_disable(state);
}
static struct console fiq_debugger_console = {
@@ -759,12 +876,10 @@ int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
if (!state->console_enable)
return count;
- if (state->clk)
- clk_enable(state->clk);
+ debug_uart_enable(state);
for (i = 0; i < count; i++)
state->pdata->uart_putc(state->pdev, *buf++);
- if (state->clk)
- clk_disable(state->clk);
+ debug_uart_disable(state);
return count;
}
@@ -829,18 +944,51 @@ err:
}
#endif
+static int fiq_debugger_dev_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fiq_debugger_state *state = platform_get_drvdata(pdev);
+
+ if (state->pdata->uart_dev_suspend)
+ return state->pdata->uart_dev_suspend(pdev);
+ return 0;
+}
+
+static int fiq_debugger_dev_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fiq_debugger_state *state = platform_get_drvdata(pdev);
+
+ if (state->pdata->uart_dev_resume)
+ return state->pdata->uart_dev_resume(pdev);
+ return 0;
+}
+
static int fiq_debugger_probe(struct platform_device *pdev)
{
int ret;
struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev);
struct fiq_debugger_state *state;
+ int fiq;
+ int uart_irq;
+
+ if (!pdata->uart_getc || !pdata->uart_putc)
+ return -EINVAL;
+ if ((pdata->uart_enable && !pdata->uart_disable) ||
+ (!pdata->uart_enable && pdata->uart_disable))
+ return -EINVAL;
+
+ fiq = platform_get_irq_byname(pdev, "fiq");
+ uart_irq = platform_get_irq_byname(pdev, "uart_irq");
- if (!pdata->uart_getc || !pdata->uart_putc || !pdata->fiq_enable)
+ /* uart_irq mode and fiq mode are mutually exclusive, but one of them
+ * is required */
+ if ((uart_irq < 0 && fiq < 0) || (uart_irq >= 0 && fiq >= 0))
+ return -EINVAL;
+ if (fiq >= 0 && !pdata->fiq_enable)
return -EINVAL;
state = kzalloc(sizeof(*state), GFP_KERNEL);
- state->handler.fiq = debug_fiq;
- state->handler.resume = debug_resume;
setup_timer(&state->sleep_timer, sleep_timer_expired,
(unsigned long)state);
state->pdata = pdata;
@@ -849,11 +997,16 @@ static int fiq_debugger_probe(struct platform_device *pdev)
state->debug_enable = initial_debug_enable;
state->console_enable = initial_console_enable;
- state->fiq = platform_get_irq_byname(pdev, "fiq");
+ state->fiq = fiq;
+ state->uart_irq = uart_irq;
state->signal_irq = platform_get_irq_byname(pdev, "signal");
state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup");
- if (state->wakeup_irq < 0)
+ platform_set_drvdata(pdev, state);
+
+ spin_lock_init(&state->sleep_timer_lock);
+
+ if (state->wakeup_irq < 0 && debug_have_fiq(state))
state->no_sleep = true;
state->ignore_next_wakeup_irq = !state->no_sleep;
@@ -864,6 +1017,10 @@ static int fiq_debugger_probe(struct platform_device *pdev)
if (IS_ERR(state->clk))
state->clk = NULL;
+ /* do not call pdata->uart_enable here since uart_init may still
+ * need to do some initialization before uart_enable can work.
+ * So, only try to manage the clock during init.
+ */
if (state->clk)
clk_enable(state->clk);
@@ -876,21 +1033,39 @@ static int fiq_debugger_probe(struct platform_device *pdev)
debug_printf_nfiq(state, "<hit enter %sto activate fiq debugger>\n",
state->no_sleep ? "" : "twice ");
- ret = fiq_glue_register_handler(&state->handler);
- if (ret) {
- pr_err("serial_debugger: could not install fiq handler\n");
- goto err_register_fiq;
- }
+ if (debug_have_fiq(state)) {
+ state->handler.fiq = debug_fiq;
+ state->handler.resume = debug_resume;
+ ret = fiq_glue_register_handler(&state->handler);
+ if (ret) {
+ pr_err("%s: could not install fiq handler\n", __func__);
+ goto err_register_fiq;
+ }
+
+ pdata->fiq_enable(pdev, state->fiq, 1);
+ } else {
+ ret = request_irq(state->uart_irq, debug_uart_irq,
+ 0, "debug", state);
+ if (ret) {
+ pr_err("%s: could not install irq handler\n", __func__);
+ goto err_register_irq;
+ }
- pdata->fiq_enable(pdev, state->fiq, 1);
+ /* for irq-only mode, we want this irq to wake us up, if it
+ * can.
+ */
+ enable_irq_wake(state->uart_irq);
+ }
if (state->clk)
clk_disable(state->clk);
- ret = request_irq(state->signal_irq, debug_irq,
- IRQF_TRIGGER_RISING, "debug", state);
- if (ret)
- pr_err("serial_debugger: could not install signal_irq");
+ if (state->signal_irq >= 0) {
+ ret = request_irq(state->signal_irq, debug_signal_irq,
+ IRQF_TRIGGER_RISING, "debug-signal", state);
+ if (ret)
+ pr_err("serial_debugger: could not install signal_irq");
+ }
if (state->wakeup_irq >= 0) {
ret = request_irq(state->wakeup_irq, wakeup_irq_handler,
@@ -910,7 +1085,7 @@ static int fiq_debugger_probe(struct platform_device *pdev)
}
}
if (state->no_sleep)
- wakeup_irq_handler(state->wakeup_irq, state);
+ handle_wakeup(state);
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
state->console = fiq_debugger_console;
@@ -919,19 +1094,32 @@ static int fiq_debugger_probe(struct platform_device *pdev)
#endif
return 0;
+err_register_irq:
err_register_fiq:
if (pdata->uart_free)
pdata->uart_free(pdev);
err_uart_init:
- kfree(state);
+ if (state->clk)
+ clk_disable(state->clk);
if (state->clk)
clk_put(state->clk);
+ wake_lock_destroy(&state->debugger_wake_lock);
+ platform_set_drvdata(pdev, NULL);
+ kfree(state);
return ret;
}
+static const struct dev_pm_ops fiq_debugger_dev_pm_ops = {
+ .suspend = fiq_debugger_dev_suspend,
+ .resume = fiq_debugger_dev_resume,
+};
+
static struct platform_driver fiq_debugger_driver = {
- .probe = fiq_debugger_probe,
- .driver.name = "fiq_debugger",
+ .probe = fiq_debugger_probe,
+ .driver = {
+ .name = "fiq_debugger",
+ .pm = &fiq_debugger_dev_pm_ops,
+ },
};
static int __init fiq_debugger_init(void)
diff --git a/arch/arm/include/asm/fiq_debugger.h b/arch/arm/include/asm/fiq_debugger.h
index e711b57b22f..4d274883ba6 100644
--- a/arch/arm/include/asm/fiq_debugger.h
+++ b/arch/arm/include/asm/fiq_debugger.h
@@ -27,6 +27,19 @@
#define FIQ_DEBUGGER_SIGNAL_IRQ_NAME "signal"
#define FIQ_DEBUGGER_WAKEUP_IRQ_NAME "wakeup"
+/**
+ * struct fiq_debugger_pdata - fiq debugger platform data
+ * @uart_resume: used to restore uart state right before enabling
+ * the fiq.
+ * @uart_enable: Do the work necessary to communicate with the uart
+ * hw (enable clocks, etc.). This must be ref-counted.
+ * @uart_disable: Do the work necessary to disable the uart hw
+ * (disable clocks, etc.). This must be ref-counted.
+ * @uart_dev_suspend: called during PM suspend, generally not needed
+ * for real fiq mode debugger.
+ * @uart_dev_resume: called during PM resume, generally not needed
+ * for real fiq mode debugger.
+ */
struct fiq_debugger_pdata {
int (*uart_init)(struct platform_device *pdev);
void (*uart_free)(struct platform_device *pdev);
@@ -34,6 +47,11 @@ struct fiq_debugger_pdata {
int (*uart_getc)(struct platform_device *pdev);
void (*uart_putc)(struct platform_device *pdev, unsigned int c);
void (*uart_flush)(struct platform_device *pdev);
+ void (*uart_enable)(struct platform_device *pdev);
+ void (*uart_disable)(struct platform_device *pdev);
+
+ int (*uart_dev_suspend)(struct platform_device *pdev);
+ int (*uart_dev_resume)(struct platform_device *pdev);
void (*fiq_enable)(struct platform_device *pdev, unsigned int fiq,
bool enable);
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 0e6c3e57587..20ea0776ef2 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -393,6 +393,13 @@ config OMAP_ALLOW_OSWR
Which means the Logic of power domains can be lost now
unlike the CSWR wherein the logic is retained
+config OMAP_FIQ_DEBUGGER
+ bool "Enable the serial FIQ debugger on OMAP"
+ default y
+ select FIQ_DEBUGGER
+ help
+ Enables the serial FIQ debugger on OMAP"
+
endmenu
endif
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index d99f98915a0..78ccde5fc6d 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -309,3 +309,4 @@ obj-$(CONFIG_OMAP_REMOTE_PROC) += remoteproc.o
obj-$(CONFIG_OMAP_HSI_DEVICE) += omap_hsi.o
obj-$(CONFIG_ION_OMAP) += omap4_ion.o
obj-$(CONFIG_ARCH_OMAP4) += omap_dmm.o
+obj-$(CONFIG_OMAP_FIQ_DEBUGGER) += omap_fiq_debugger.o
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index ec560b34034..0712675a4d9 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -43,7 +43,7 @@
#define OMAP4_STATE_C2 1
/* C3 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE CSWR */
#define OMAP4_STATE_C3 2
-/* C4 - CPU0 OFF + CPU1 OFF + MPU OSWR + CORE OSWR */
+/* C4 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE OSWR */
#define OMAP4_STATE_C4 3
#define OMAP4_MAX_STATES 4
@@ -118,13 +118,8 @@ static struct cpuidle_params cpuidle_params_table[] = {
/* C3 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE CSWR */
{.exit_latency = 1200, .target_residency = 1200, .valid = 1},
#ifdef CONFIG_OMAP_ALLOW_OSWR
- /* C4 - CPU0 OFF + CPU1 OFF + MPU OSWR + CORE OSWR */
- /*
- * OSWR is disabled to avoid a HW bug that occurs when there is
- * no static dependency between mpuss and emif, and mpuss enters
- * OSWR
- */
- {.exit_latency = 1500, .target_residency = 1500, .valid = 0},
+ /* C4 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE OSWR */
+ {.exit_latency = 1500, .target_residency = 1500, .valid = 1},
#else
{.exit_latency = 1500, .target_residency = 1500, .valid = 0},
#endif
@@ -656,7 +651,7 @@ void omap4_init_power_states(void)
omap4_power_states[OMAP4_STATE_C3].desc = "CPUs OFF, MPU + CORE CSWR";
/*
- * C4 - CPU0 OFF + CPU1 OFF + MPU OFF + CORE CSWR
+ * C4 - CPU0 OFF + CPU1 OFF + MPU CSWR + CORE OSWR
*/
omap4_power_states[OMAP4_STATE_C4].valid =
cpuidle_params_table[OMAP4_STATE_C4].valid;
@@ -666,10 +661,10 @@ void omap4_init_power_states(void)
omap4_power_states[OMAP4_STATE_C4].target_residency =
cpuidle_params_table[OMAP4_STATE_C4].target_residency;
omap4_power_states[OMAP4_STATE_C4].mpu_state = PWRDM_POWER_RET;
- omap4_power_states[OMAP4_STATE_C4].mpu_logic_state = PWRDM_POWER_OFF;
+ omap4_power_states[OMAP4_STATE_C4].mpu_logic_state = PWRDM_POWER_RET;
omap4_power_states[OMAP4_STATE_C4].core_state = PWRDM_POWER_RET;
omap4_power_states[OMAP4_STATE_C4].core_logic_state = PWRDM_POWER_OFF;
- omap4_power_states[OMAP4_STATE_C4].desc = "CPUs OFF, MPU + CORE OSWR";
+ omap4_power_states[OMAP4_STATE_C4].desc = "CPUs OFF, MPU CSWR + CORE OSWR";
}
diff --git a/arch/arm/mach-omap2/include/mach/omap_fiq_debugger.h b/arch/arm/mach-omap2/include/mach/omap_fiq_debugger.h
new file mode 100644
index 00000000000..c49608e248d
--- /dev/null
+++ b/arch/arm/mach-omap2/include/mach/omap_fiq_debugger.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 Google, 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.
+ *
+ */
+
+#ifndef __MACH_OMAP_FIQ_DEBUGGER_H
+#define __MACH_OMAP_FIQ_DEBUGGER_H
+
+#ifdef CONFIG_OMAP_FIQ_DEBUGGER
+int __init omap_serial_debug_init(int id, bool is_fiq, bool is_high_prio_irq,
+ struct omap_device_pad *pads, int num_pads);
+u32 omap_debug_uart_resume_idle(void);
+
+#else
+static inline int __init omap_serial_debug_init(int id, bool is_fiq, bool is_high_prio_irq,
+ struct omap_device_pad *pads, int num_pads)
+{
+}
+
+static inline u32 omap_debug_uart_resume_idle(void)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/arch/arm/mach-omap2/omap_fiq_debugger.c b/arch/arm/mach-omap2/omap_fiq_debugger.c
new file mode 100644
index 00000000000..174bba044d2
--- /dev/null
+++ b/arch/arm/mach-omap2/omap_fiq_debugger.c
@@ -0,0 +1,418 @@
+/*
+ * Serial Debugger Interface for Omap
+ *
+ * Copyright (C) 2011 Google, 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/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/stacktrace.h>
+#include <linux/uaccess.h>
+
+#include <plat/omap_device.h>
+#include <plat/omap-pm.h>
+#include <plat/omap-serial.h>
+
+#include <asm/fiq_debugger.h>
+
+#include <mach/omap_fiq_debugger.h>
+#include <mach/system.h>
+
+#include "mux.h"
+
+struct omap_fiq_debugger {
+ struct fiq_debugger_pdata pdata;
+ struct platform_device *pdev;
+ void __iomem *debug_port_base;
+ bool suspended;
+ spinlock_t lock;
+ bool have_state;
+
+ /* uart state */
+ unsigned char lcr;
+ unsigned char fcr;
+ unsigned char efr;
+ unsigned char dll;
+ unsigned char dlh;
+ unsigned char mcr;
+ unsigned char ier;
+ unsigned char wer;
+};
+
+static struct omap_fiq_debugger *dbgs[OMAP_MAX_HSUART_PORTS];
+
+static inline struct omap_fiq_debugger *get_dbg(struct platform_device *pdev)
+{
+ struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev);
+ return container_of(pdata, struct omap_fiq_debugger, pdata);
+}
+
+static inline void omap_write(struct omap_fiq_debugger *dbg,
+ unsigned int val, unsigned int off)
+{
+ __raw_writel(val, dbg->debug_port_base + off * 4);
+}
+
+static inline unsigned int omap_read(struct omap_fiq_debugger *dbg,
+ unsigned int off)
+{
+ return __raw_readl(dbg->debug_port_base + off * 4);
+}
+
+static void debug_omap_port_enable(struct platform_device *pdev)
+{
+ pm_runtime_get_sync(&pdev->dev);
+}
+
+static void debug_omap_port_disable(struct platform_device *pdev)
+{
+ struct omap_fiq_debugger *dbg = get_dbg(pdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dbg->lock, flags);
+ if (!dbg->suspended) {
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+ } else {
+ pm_runtime_put_sync_suspend(&pdev->dev);
+ }
+ spin_unlock_irqrestore(&dbg->lock, flags);
+}
+
+static int debug_omap_port_resume(struct platform_device *pdev)
+{
+ struct omap_fiq_debugger *dbg = get_dbg(pdev);
+
+ dbg->suspended = false;
+ barrier();
+ return 0;
+}
+
+static int debug_omap_port_suspend(struct platform_device *pdev)
+{
+ struct omap_fiq_debugger *dbg = get_dbg(pdev);
+ unsigned long flags;
+
+ /* this will force the device to be idle'd now, in case it was
+ * autosuspended but timer has not yet run out.
+ */
+ spin_lock_irqsave(&dbg->lock, flags);
+ dbg->suspended = true;
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_put_sync_suspend(&pdev->dev);
+ spin_unlock_irqrestore(&dbg->lock, flags);
+
+ return 0;
+}
+
+/* mostly copied from drivers/tty/serial/omap-serial.c */
+static void omap_write_mdr1(struct omap_fiq_debugger *dbg, u8 mdr1)
+{
+ u8 timeout = 255;
+
+ if (!(cpu_is_omap34xx() || cpu_is_omap44xx())) {
+ omap_write(dbg, UART_OMAP_MDR1_DISABLE, UART_OMAP_MDR1);
+ return;
+ }
+
+ omap_write(dbg, mdr1, UART_OMAP_MDR1);
+ udelay(2);
+ omap_write(dbg, dbg->fcr | UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR,
+ UART_FCR);
+
+ /*
+ * Wait for FIFO to empty: when empty, RX_FIFO_E bit is 0 and
+ * TX_FIFO_E bit is 1.
+ */
+ while (UART_LSR_THRE !=
+ (omap_read(dbg, UART_LSR) & (UART_LSR_THRE | UART_LSR_DR))) {
+ timeout--;
+ if (!timeout) {
+ /* Should *never* happen. we warn and carry on */
+ dev_crit(&dbg->pdev->dev, "Errata i202: timedout %x\n",
+ omap_read(dbg, UART_LSR));
+ break;
+ }
+ udelay(1);
+ }
+}
+
+/* assume the bootloader programmed us correctly */
+static void debug_port_read_state(struct omap_fiq_debugger *dbg)
+{
+ /* assume we're in operational mode when we are called */
+ dbg->lcr = omap_read(dbg, UART_LCR);
+
+ /* config mode A */
+ omap_write(dbg, UART_LCR_CONF_MODE_A, UART_LCR);
+ dbg->mcr = omap_read(dbg, UART_MCR);
+
+ /* config mode B */
+ omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR);
+ dbg->efr = omap_read(dbg, UART_EFR);
+ dbg->dll = omap_read(dbg, UART_DLL);
+ dbg->dlh = omap_read(dbg, UART_DLM);
+
+ /* back to operational */
+ omap_write(dbg, dbg->lcr, UART_LCR);
+
+ pr_debug("%s: lcr=%02x mcr=%02x efr=%02x dll=%02x dlh=%02x\n",
+ __func__, dbg->lcr, dbg->mcr, dbg->efr, dbg->dll, dbg->dlh);
+}
+
+static void debug_port_restore(struct omap_fiq_debugger *dbg)
+{
+ omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR); /* Config B mode */
+ omap_write(dbg, dbg->efr | UART_EFR_ECB, UART_EFR);
+ omap_write(dbg, 0x0, UART_LCR); /* Operational mode */
+ omap_write(dbg, 0x0, UART_IER);
+ omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR); /* Config B mode */
+ omap_write(dbg, 0, UART_DLL);
+ omap_write(dbg, 0, UART_DLM);
+ omap_write(dbg, UART_LCR_CONF_MODE_A, UART_LCR);
+ omap_write(dbg, dbg->mcr | UART_MCR_TCRTLR, UART_MCR);
+ omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR);
+ omap_write(dbg, 0, UART_TI752_TLR);
+ omap_write(dbg, 0, UART_SCR);
+ omap_write(dbg, dbg->efr, UART_EFR);
+ omap_write(dbg, UART_LCR_CONF_MODE_A, UART_LCR);
+ omap_write(dbg, dbg->fcr, UART_FCR);
+ omap_write(dbg, dbg->mcr, UART_MCR);
+ omap_write_mdr1(dbg, UART_OMAP_MDR1_DISABLE);
+
+ omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR);
+ omap_write(dbg, dbg->efr | UART_EFR_ECB, UART_EFR);
+ omap_write(dbg, dbg->dll, UART_DLL);
+ omap_write(dbg, dbg->dlh, UART_DLM);
+ omap_write(dbg, 0, UART_LCR);
+ omap_write(dbg, dbg->ier, UART_IER);
+ omap_write(dbg, UART_LCR_CONF_MODE_B, UART_LCR);
+ omap_write(dbg, dbg->efr, UART_EFR);
+
+ /* will put us back to operational mode */
+ omap_write(dbg, dbg->lcr, UART_LCR);
+ omap_write_mdr1(dbg, UART_OMAP_MDR1_16X_MODE);
+
+ omap_write(dbg, dbg->wer, UART_OMAP_WER);
+}
+
+u32 omap_debug_uart_resume_idle(void)
+{
+ int i;
+ u32 ret = 0;
+
+ for (i = 0; i < OMAP_MAX_HSUART_PORTS; i++) {
+ struct omap_fiq_debugger *dbg = dbgs[i];
+ struct omap_device *od;
+
+ if (!dbg || !dbg->pdev)
+ continue;
+
+ od = to_omap_device(dbg->pdev);
+ if (omap_hwmod_pad_get_wakeup_status(od->hwmods[0])) {
+ /*
+ * poke the uart and let it stay on long enough
+ * to process any further data. It's ok to use
+ * autosuspend here since this is on the resume path
+ * during the wakeup. We'll still go through a full
+ * resume cycle, so if we go back to suspend
+ * the suspended flag will properly get reset.
+ */
+ pm_runtime_get_sync(&dbg->pdev->dev);
+ pm_runtime_mark_last_busy(&dbg->pdev->dev);
+ pm_runtime_put_autosuspend(&dbg->pdev->dev);
+ dev_dbg(&dbg->pdev->dev, "woke up from IO pad\n");
+ ret++;
+ }
+ }
+
+ return ret;
+}
+
+static int debug_port_init(struct platform_device *pdev)
+{
+ struct omap_fiq_debugger *dbg = get_dbg(pdev);
+
+ dbg->ier = UART_IER_RLSI | UART_IER_RDI;
+ dbg->fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 |
+ UART_FCR_T_TRIG_01;
+ dbg->wer = 0;
+
+ device_init_wakeup(&pdev->dev, true);
+
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, DEFAULT_AUTOSUSPEND_DELAY);
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_irq_safe(&pdev->dev);
+
+ omap_hwmod_idle(to_omap_device(pdev)->hwmods[0]);
+ debug_omap_port_enable(pdev);
+ debug_omap_port_disable(pdev);
+
+ debug_omap_port_enable(pdev);
+
+ if (device_may_wakeup(&pdev->dev))
+ omap_hwmod_enable_wakeup(to_omap_device(pdev)->hwmods[0]);
+
+ debug_port_read_state(dbg);
+ debug_port_restore(dbg);
+
+ dbg->have_state = true;
+
+
+ debug_omap_port_disable(pdev);
+ return 0;
+}
+
+static int debug_getc(struct platform_device *pdev)
+{
+ struct omap_fiq_debugger *dbg = get_dbg(pdev);
+ unsigned int lsr;
+ int ret = FIQ_DEBUGGER_NO_CHAR;
+
+ lsr = omap_read(dbg, UART_LSR);
+ if (lsr & UART_LSR_BI) {
+ /* need to read RHR to clear the BI condition */
+ omap_read(dbg, UART_RX);
+ ret = FIQ_DEBUGGER_BREAK;
+ } else if (lsr & UART_LSR_DR) {
+ ret = omap_read(dbg, UART_RX);
+ }
+
+ return ret;
+}
+
+static void debug_putc(struct platform_device *pdev, unsigned int c)
+{
+ struct omap_fiq_debugger *dbg = get_dbg(pdev);
+
+ while (!(omap_read(dbg, UART_LSR) & UART_LSR_THRE))
+ cpu_relax();
+
+ omap_write(dbg, c, UART_TX);
+}
+
+static void debug_flush(struct platform_device *pdev)
+{
+ struct omap_fiq_debugger *dbg = get_dbg(pdev);
+
+ while (!(omap_read(dbg, UART_LSR) & UART_LSR_TEMT))
+ cpu_relax();
+}
+
+static int uart_idle_hwmod(struct omap_device *od)
+{
+ omap_hwmod_idle(od->hwmods[0]);
+
+ return 0;
+}
+
+static int uart_enable_hwmod(struct omap_device *od)
+{
+ struct platform_device *pdev = &od->pdev;
+ struct omap_fiq_debugger *dbg = get_dbg(pdev);
+
+ omap_hwmod_enable(od->hwmods[0]);
+ if (omap_pm_was_context_lost(&pdev->dev) && dbg->have_state) {
+ debug_port_restore(dbg);
+ dev_dbg(&pdev->dev, "restoring lost context!\n");
+ }
+
+ return 0;
+}
+
+static struct omap_device_pm_latency omap_uart_latency[] = {
+ {
+ .deactivate_func = uart_idle_hwmod,
+ .activate_func = uart_enable_hwmod,
+ .flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
+ },
+};
+
+extern struct omap_hwmod *omap_uart_hwmod_lookup(int num);
+
+int __init omap_serial_debug_init(int id, bool is_fiq, bool is_high_prio_irq,
+ struct omap_device_pad *pads, int num_pads)
+{
+ struct omap_fiq_debugger *dbg;
+ struct omap_hwmod *oh;
+ struct omap_device *od;
+ int ret;
+
+ if (id >= OMAP_MAX_HSUART_PORTS)
+ return -EINVAL;
+ if (dbgs[id])
+ return -EBUSY;
+
+ oh = omap_uart_hwmod_lookup(id);
+ if (!oh)
+ return -ENODEV;
+
+ oh->mpu_irqs[0].name = "uart_irq";
+ oh->mux = omap_hwmod_mux_init(pads, num_pads);
+
+ dbg = kzalloc(sizeof(struct omap_fiq_debugger), GFP_KERNEL);
+ if (!dbg) {
+ pr_err("Failed to allocate for fiq debugger\n");
+ return -ENOMEM;
+ }
+
+ dbg->debug_port_base = ioremap(oh->slaves[0]->addr[0].pa_start,
+ PAGE_SIZE);
+ if (!dbg->debug_port_base) {
+ pr_err("Failed to ioremap for fiq debugger\n");
+ ret = -ENOMEM;
+ goto err_ioremap;
+ }
+
+ spin_lock_init(&dbg->lock);
+
+ dbg->pdata.uart_init = debug_port_init;
+ dbg->pdata.uart_getc = debug_getc;
+ dbg->pdata.uart_putc = debug_putc;
+ dbg->pdata.uart_flush = debug_flush;
+ dbg->pdata.uart_enable = debug_omap_port_enable;
+ dbg->pdata.uart_disable = debug_omap_port_disable;
+ dbg->pdata.uart_dev_suspend = debug_omap_port_suspend;
+ dbg->pdata.uart_dev_resume = debug_omap_port_resume;
+
+ od = omap_device_build("fiq_debugger", id,
+ oh, dbg, sizeof(*dbg), omap_uart_latency,
+ ARRAY_SIZE(omap_uart_latency), false);
+ if (IS_ERR(od)) {
+ pr_err("Could not build omap_device for fiq_debugger: %s\n",
+ oh->name);
+ ret = PTR_ERR(od);
+ goto err_dev_build;
+ }
+
+ dbg->pdev = &od->pdev;
+ dbgs[id] = dbg;
+
+ return 0;
+
+err_dev_build:
+ iounmap(dbg->debug_port_base);
+err_ioremap:
+ kfree(dbg);
+ return ret;
+}
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 77cda51e50c..32c390cc2f6 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -33,6 +33,8 @@
#include <plat/gpmc.h>
#include <plat/dma.h>
+#include <mach/omap_fiq_debugger.h>
+
#include "powerdomain.h"
#include "clockdomain.h"
#include "pm.h"
@@ -942,6 +944,7 @@ static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
}
omap_uart_resume_idle();
usbhs_wakeup();
+ omap_debug_uart_resume_idle();
omap4_trigger_ioctrl();
}
diff --git a/arch/arm/mach-omap2/resetreason.c b/arch/arm/mach-omap2/resetreason.c
index 5190d0a90e0..316bfebbe1e 100644
--- a/arch/arm/mach-omap2/resetreason.c
+++ b/arch/arm/mach-omap2/resetreason.c
@@ -15,44 +15,56 @@
*/
#include <linux/kernel.h>
+#include <linux/string.h>
#include "prm-regbits-44xx.h"
#include "prcm44xx.h"
#include "prm44xx.h"
#include "prminst44xx.h"
+#include "resetreason.h"
+
+static char resetreason[1024];
+
+static struct {
+ const char *str;
+ u32 mask;
+} resetreason_flags[] = {
+ { "C2C ", OMAP4430_C2C_RST_MASK },
+ { "IcePick ", OMAP4430_ICEPICK_RST_MASK },
+ { "Voltage Manager ", OMAP4430_VDD_MPU_VOLT_MGR_RST_MASK |
+ OMAP4430_VDD_IVA_VOLT_MGR_RST_MASK |
+ OMAP4430_VDD_CORE_VOLT_MGR_RST_MASK },
+ { "external warm ", OMAP4430_EXTERNAL_WARM_RST_MASK },
+ { "MPU Watchdog Timer ", OMAP4430_MPU_WDT_RST_MASK },
+ { "warm software ", OMAP4430_GLOBAL_WARM_SW_RST_MASK },
+ { "cold ", OMAP4430_GLOBAL_COLD_RST_MASK },
+};
+
+const char *omap4_get_resetreason(void)
+{
+ return resetreason;
+}
static int __init resetreason_init(void)
{
+ int i;
u32 reasons =
omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
OMAP4430_PRM_DEVICE_INST,
OMAP4_PRM_RSTST_OFFSET);
+ char buf[128];
- pr_info("Last reset was ");
-
- if (reasons & OMAP4430_C2C_RST_MASK)
- pr_cont("C2C ");
-
- if (reasons & OMAP4430_ICEPICK_RST_MASK)
- pr_cont("IcePick ");
-
- if (reasons & (OMAP4430_VDD_MPU_VOLT_MGR_RST_MASK |
- OMAP4430_VDD_IVA_VOLT_MGR_RST_MASK |
- OMAP4430_VDD_CORE_VOLT_MGR_RST_MASK))
- pr_cont("Voltage Manager ");
-
- if (reasons & OMAP4430_EXTERNAL_WARM_RST_MASK)
- pr_cont("external warm ");
+ strlcpy(resetreason, "Last reset was ", sizeof(resetreason));
- if (reasons & OMAP4430_MPU_WDT_RST_MASK)
- pr_cont("MPU Watchdog Timer ");
+ for (i = 0; i < ARRAY_SIZE(resetreason_flags); i++)
+ if (reasons & resetreason_flags[i].mask)
+ strlcat(resetreason, resetreason_flags[i].str,
+ sizeof(resetreason));
- if (reasons & OMAP4430_GLOBAL_WARM_SW_RST_MASK)
- pr_cont("warm software ");
- else if (reasons & OMAP4430_GLOBAL_COLD_RST_MASK)
- pr_cont("cold ");
+ snprintf(buf, sizeof(buf), "reset (PRM_RSTST=0x%x)\n", reasons);
+ strlcat(resetreason, buf, sizeof(resetreason));
- pr_cont("reset (PRM_RSTST=0x%x)\n", reasons);
+ pr_info("%s\n", resetreason);
omap4_prminst_write_inst_reg(reasons, OMAP4430_PRM_PARTITION,
OMAP4430_PRM_DEVICE_INST, OMAP4_PRM_RSTST_OFFSET);
@@ -60,4 +72,4 @@ static int __init resetreason_init(void)
return 0;
}
-arch_initcall(resetreason_init);
+postcore_initcall(resetreason_init);
diff --git a/arch/arm/mach-omap2/resetreason.h b/arch/arm/mach-omap2/resetreason.h
new file mode 100644
index 00000000000..96c9a0027f4
--- /dev/null
+++ b/arch/arm/mach-omap2/resetreason.h
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/mach-omap2/resetreason.h
+ *
+ * Copyright (C) 2011 Google, 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.
+ *
+ */
+
+#ifndef _MACH_OMAP2_RESETREASON_H_
+#define _MACH_OMAP2_RESETREASON_H_
+
+const char *omap4_get_resetreason(void);
+
+#endif
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index 53f736b0ec8..cb42d899822 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -21,6 +21,7 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/platform_data/ram_console.h>
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
#include <linux/rslib.h>
@@ -155,14 +156,20 @@ void ram_console_enable_console(int enabled)
}
static void __init
-ram_console_save_old(struct ram_console_buffer *buffer, char *dest)
+ram_console_save_old(struct ram_console_buffer *buffer, const char *bootinfo,
+ char *dest)
{
size_t old_log_size = buffer->size;
+ size_t bootinfo_size = 0;
+ size_t total_size = old_log_size;
+ char *ptr;
+ const char *bootinfo_label = "Boot info:\n";
+
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
uint8_t *block;
uint8_t *par;
char strbuf[80];
- int strbuf_len;
+ int strbuf_len = 0;
block = buffer->data;
par = ram_console_par_buffer;
@@ -197,11 +204,15 @@ ram_console_save_old(struct ram_console_buffer *buffer, char *dest)
"\nNo errors detected\n");
if (strbuf_len >= sizeof(strbuf))
strbuf_len = sizeof(strbuf) - 1;
- old_log_size += strbuf_len;
+ total_size += strbuf_len;
#endif
+ if (bootinfo)
+ bootinfo_size = strlen(bootinfo) + strlen(bootinfo_label);
+ total_size += bootinfo_size;
+
if (dest == NULL) {
- dest = kmalloc(old_log_size, GFP_KERNEL);
+ dest = kmalloc(total_size, GFP_KERNEL);
if (dest == NULL) {
printk(KERN_ERR
"ram_console: failed to allocate buffer\n");
@@ -210,19 +221,27 @@ ram_console_save_old(struct ram_console_buffer *buffer, char *dest)
}
ram_console_old_log = dest;
- ram_console_old_log_size = old_log_size;
+ ram_console_old_log_size = total_size;
memcpy(ram_console_old_log,
&buffer->data[buffer->start], buffer->size - buffer->start);
memcpy(ram_console_old_log + buffer->size - buffer->start,
&buffer->data[0], buffer->start);
+ ptr = ram_console_old_log + old_log_size;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
- memcpy(ram_console_old_log + old_log_size - strbuf_len,
- strbuf, strbuf_len);
+ memcpy(ptr, strbuf, strbuf_len);
+ ptr += strbuf_len;
#endif
+ if (bootinfo) {
+ memcpy(ptr, bootinfo_label, strlen(bootinfo_label));
+ ptr += strlen(bootinfo_label);
+ memcpy(ptr, bootinfo, bootinfo_size);
+ ptr += bootinfo_size;
+ }
}
static int __init ram_console_init(struct ram_console_buffer *buffer,
- size_t buffer_size, char *old_buf)
+ size_t buffer_size, const char *bootinfo,
+ char *old_buf)
{
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
int numerr;
@@ -289,7 +308,7 @@ static int __init ram_console_init(struct ram_console_buffer *buffer,
printk(KERN_INFO "ram_console: found existing buffer, "
"size %d, start %d\n",
buffer->size, buffer->start);
- ram_console_save_old(buffer, old_buf);
+ ram_console_save_old(buffer, bootinfo, old_buf);
}
} else {
printk(KERN_INFO "ram_console: no valid data in buffer "
@@ -313,6 +332,7 @@ static int __init ram_console_early_init(void)
return ram_console_init((struct ram_console_buffer *)
CONFIG_ANDROID_RAM_CONSOLE_EARLY_ADDR,
CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE,
+ NULL,
ram_console_old_log_init_buffer);
}
#else
@@ -322,6 +342,8 @@ static int ram_console_driver_probe(struct platform_device *pdev)
size_t start;
size_t buffer_size;
void *buffer;
+ const char *bootinfo = NULL;
+ struct ram_console_platform_data *pdata = pdev->dev.platform_data;
if (res == NULL || pdev->num_resources != 1 ||
!(res->flags & IORESOURCE_MEM)) {
@@ -339,7 +361,10 @@ static int ram_console_driver_probe(struct platform_device *pdev)
return -ENOMEM;
}
- return ram_console_init(buffer, buffer_size, NULL/* allocate */);
+ if (pdata)
+ bootinfo = pdata->bootinfo;
+
+ return ram_console_init(buffer, buffer_size, bootinfo, NULL/* allocate */);
}
static struct platform_driver ram_console_driver = {
diff --git a/include/linux/platform_data/ram_console.h b/include/linux/platform_data/ram_console.h
new file mode 100644
index 00000000000..9f1125c1106
--- /dev/null
+++ b/include/linux/platform_data/ram_console.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2010 Google, 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.
+ *
+ */
+
+#ifndef _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_
+#define _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_
+
+struct ram_console_platform_data {
+ const char *bootinfo;
+};
+
+#endif /* _INCLUDE_LINUX_PLATFORM_DATA_RAM_CONSOLE_H_ */