diff options
author | Dan Murphy <dmurphy@ti.com> | 2011-10-26 10:17:18 -0500 |
---|---|---|
committer | Dan Murphy <dmurphy@ti.com> | 2011-10-26 10:17:18 -0500 |
commit | bb10c38c127952a7d84cb0b9d6ce8090b61bdd40 (patch) | |
tree | 0b90e2f4e0023a9710c41ce6a18907a591108217 | |
parent | 0700a3c3af2f21c6b226dc2c9b7a2b7eeb4cc6fa (diff) | |
parent | 99ae0ab9af0b3c53de250c6a7e9d09793f9add0b (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.c | 320 | ||||
-rw-r--r-- | arch/arm/include/asm/fiq_debugger.h | 18 | ||||
-rw-r--r-- | arch/arm/mach-omap2/Kconfig | 7 | ||||
-rw-r--r-- | arch/arm/mach-omap2/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/cpuidle44xx.c | 17 | ||||
-rw-r--r-- | arch/arm/mach-omap2/include/mach/omap_fiq_debugger.h | 35 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_fiq_debugger.c | 418 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm44xx.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/resetreason.c | 58 | ||||
-rw-r--r-- | arch/arm/mach-omap2/resetreason.h | 22 | ||||
-rw-r--r-- | drivers/staging/android/ram_console.c | 45 | ||||
-rw-r--r-- | include/linux/platform_data/ram_console.h | 22 |
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_ */ |