add fiq debugger
authorhhb <hhb@rock-chips.com>
Tue, 3 Dec 2013 13:41:29 +0000 (21:41 +0800)
committerhhb <hhb@rock-chips.com>
Tue, 3 Dec 2013 13:41:29 +0000 (21:41 +0800)
arch/arm/boot/dts/rk3188-tb.dts
arch/arm/boot/dts/rk3188.dtsi
arch/arm/common/fiq_debugger.c
arch/arm/configs/rockchip_defconfig
arch/arm/mach-rockchip/Makefile
arch/arm/mach-rockchip/rk3188.c
arch/arm/mach-rockchip/rk_fiq_debugger.c [new file with mode: 0644]
arch/arm/mach-rockchip/rk_fiq_debugger.h [new file with mode: 0644]
drivers/irqchip/irq-gic.c

index a9422f3aad0630c12afff1ce3b8457c2a04cd5f6..6659ed1d4c0535db41db598e704c3fc7d3495293 100644 (file)
@@ -9,15 +9,15 @@
        };
 
        chosen {
-               bootargs ="console=ttyS2,115200 androidboot.console=ttyS2";
+
        };
-};
 
-&uart0 {
-       status = "okay";
+       ttyFIQ0 {
+               id = <2>;
+       };
 };
 
-&uart2 {
+&uart0 {
        status = "okay";
 };
 
index 9dc1b2fbca2dadf9855f29bfe6233151a9f64870..96c0b297fe5958a8bf3152aad6889cd1b34cd8bb 100755 (executable)
                pinctrl-0 = <&uart3_xfer &uart3_cts &uart3_rts>;
                status = "disabled";
        };
+
+       ttyFIQ0 {
+               id = <2>;
+               signal_irq = <112>;
+               wake_irq = <0>;
+               status = "disabled";
+       };
 };
index 65b943c7630044a2db113524aa1c7021707e17dd..f1771c00398c87af819c4ba139a7c204ffb61304 100644 (file)
 
 #include "fiq_debugger_ringbuf.h"
 
+#ifdef CONFIG_RK29_WATCHDOG
+extern void rk29_wdt_keepalive(void);
+#define wdt_keepalive() rk29_wdt_keepalive()
+#else
+#define wdt_keepalive() do {} while (0)
+#endif
 #define DEBUG_MAX 64
+#define CMD_COUNT 0x0f
 #define MAX_UNHANDLED_FIQ_COUNT 1000000
 
 #define MAX_FIQ_DEBUGGER_PORTS 4
@@ -70,6 +77,9 @@ struct fiq_debugger_state {
        char debug_buf[DEBUG_MAX];
        int debug_count;
 
+       char cmd_buf[CMD_COUNT+1][DEBUG_MAX];
+       int back_pointer;
+       int current_pointer;
        bool no_sleep;
        bool debug_enable;
        bool ignore_next_wakeup_irq;
@@ -123,6 +133,9 @@ module_param_named(debug_enable, initial_debug_enable, bool, 0644);
 module_param_named(console_enable, initial_console_enable, bool, 0644);
 module_param_named(kgdb_enable, fiq_kgdb_enable, bool, 0644);
 
+void gic_set_irq_secure(struct irq_data *d);
+void gic_set_irq_priority(struct irq_data *d, u8 pri);
+
 #ifdef CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON
 static inline void enable_wakeup_irq(struct fiq_debugger_state *state) {}
 static inline void disable_wakeup_irq(struct fiq_debugger_state *state) {}
@@ -204,7 +217,7 @@ static void debug_puts(struct fiq_debugger_state *state, char *s)
 
 static void debug_prompt(struct fiq_debugger_state *state)
 {
-       debug_puts(state, "debug> ");
+       debug_puts(state, "FIQ debug> ");
 }
 
 static void dump_kernel_log(struct fiq_debugger_state *state)
@@ -219,8 +232,31 @@ static void dump_kernel_log(struct fiq_debugger_state *state)
                                         sizeof(buf) - 1, &len)) {
                buf[len] = 0;
                debug_puts(state, buf);
+               wdt_keepalive();
+       }
+}
+
+#ifdef CONFIG_RK29_LAST_LOG
+#include <linux/ctype.h>
+extern char *last_log_get(unsigned *size);
+static void dump_last_kernel_log(struct fiq_debugger_state *state)
+{
+       unsigned size, i, c;
+       char *s = last_log_get(&size);
+
+       for (i = 0; i < size; i++) {
+               if (i % 1024 == 0)
+                       wdt_keepalive();
+               c = s[i];
+               if (c == '\n') {
+                       debug_putc(state->pdev, '\r');
+                       debug_putc(state->pdev, c);
+               } else if (isascii(c) && isprint(c)) {
+                       debug_putc(state->pdev, c);
+               }
        }
 }
+#endif
 
 static char *mode_name(unsigned cpsr)
 {
@@ -364,6 +400,7 @@ static void dump_allregs(struct fiq_debugger_state *state, unsigned *regs)
 static void dump_irqs(struct fiq_debugger_state *state)
 {
        int n;
+       unsigned int cpu;
        struct irq_desc *desc;
 
        debug_printf(state, "irqnr       total  since-last   status  name\n");
@@ -378,6 +415,18 @@ static void dump_irqs(struct fiq_debugger_state *state)
                        (act && act->name) ? act->name : "???");
                state->last_irqs[n] = kstat_irqs(n);
        }
+
+#if 0  //def CONFIG_LOCAL_TIMERS
+       for (cpu = 0; cpu < NR_CPUS; cpu++) {
+
+               debug_printf(state, "LOC %d: %10u %11u\n", cpu,
+                            __IRQ_STAT(cpu, local_timer_irqs),
+                            __IRQ_STAT(cpu, local_timer_irqs) -
+                            state->last_local_timer_irqs[cpu]);
+               state->last_local_timer_irqs[cpu] =
+                       __IRQ_STAT(cpu, local_timer_irqs);
+       }
+#endif
 }
 
 struct stacktrace_state {
@@ -592,20 +641,61 @@ static void debug_work(struct work_struct *work)
 /* This function CANNOT be called in FIQ context */
 static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd)
 {
+       int invalid_cmd = 0;
        if (!strcmp(cmd, "ps"))
                do_ps(state);
-       if (!strcmp(cmd, "sysrq"))
+       else if (!strcmp(cmd, "sysrq"))
                do_sysrq(state, 'h');
-       if (!strncmp(cmd, "sysrq ", 6))
+       else if (!strncmp(cmd, "sysrq ", 6))
                do_sysrq(state, cmd[6]);
 #ifdef CONFIG_KGDB
-       if (!strcmp(cmd, "kgdb"))
+       else if (!strcmp(cmd, "kgdb"))
                do_kgdb(state);
 #endif
-       if (!strncmp(cmd, "reboot", 6))
+       else if (!strncmp(cmd, "reboot", 6))
                debug_schedule_work(state, cmd);
+       else {
+               invalid_cmd = 1;
+               memset(state->debug_buf, 0, DEBUG_MAX);
+       }
+
+       if (invalid_cmd == 0) {
+               state->current_pointer = (state->current_pointer-1) & CMD_COUNT;
+               if (strcmp(state->cmd_buf[state->current_pointer], state->debug_buf)) {
+                       state->current_pointer = (state->current_pointer+1) & CMD_COUNT;
+                       memset(state->cmd_buf[state->current_pointer], 0, DEBUG_MAX);
+                       strcpy(state->cmd_buf[state->current_pointer], state->debug_buf);
+               }
+               memset(state->debug_buf, 0, DEBUG_MAX);
+               state->current_pointer = (state->current_pointer+1) & CMD_COUNT;
+               state->back_pointer = state->current_pointer;
+       }
 }
 
+static char cmd_buf[][16] = {
+               {"pc"},
+               {"regs"},
+               {"allregs"},
+               {"bt"},
+               {"reboot"},
+               {"irqs"},
+               {"kmsg"},
+#ifdef CONFIG_RK29_LAST_LOG
+               {"last_kmsg"},
+#endif
+               {"version"},
+               {"sleep"},
+               {"nosleep"},
+               {"console"},
+               {"cpu"},
+               {"ps"},
+               {"sysrq"},
+               {"reset"},
+#ifdef CONFIG_KGDB
+               {"kgdb"},
+#endif
+};
+
 static void debug_help(struct fiq_debugger_state *state)
 {
        debug_printf(state,     "FIQ Debugger commands:\n"
@@ -618,6 +708,9 @@ static void debug_help(struct fiq_debugger_state *state)
                                " irqs          Interupt status\n"
                                " kmsg          Kernel log\n"
                                " version       Kernel version\n");
+#ifdef CONFIG_RK29_LAST_LOG
+       debug_printf(state,     " last_kmsg     Last kernel log\n");
+#endif
        debug_printf(state,     " sleep         Allow sleep while in FIQ\n"
                                " nosleep       Disable sleep while in FIQ\n"
                                " console       Switch terminal to console\n"
@@ -646,6 +739,22 @@ 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);
+#ifdef CONFIG_PLAT_RK
+       else {
+               struct cpumask cpumask;
+
+               if (!cpu_online(cpu)) {
+                       debug_printf(state, "cpu %d offline\n", cpu);
+                       return;
+               }
+
+               cpumask_clear(&cpumask);
+               cpumask_set_cpu(cpu, &cpumask);
+
+               irq_set_affinity(state->fiq, &cpumask);
+               irq_set_affinity(state->uart_irq, &cpumask);
+       }
+#endif
        state->current_cpu = cpu;
 }
 
@@ -680,6 +789,10 @@ static bool debug_fiq_exec(struct fiq_debugger_state *state,
                dump_irqs(state);
        } else if (!strcmp(cmd, "kmsg")) {
                dump_kernel_log(state);
+#ifdef CONFIG_RK29_LAST_LOG
+       } else if (!strcmp(cmd, "last_kmsg")) {
+               dump_last_kernel_log(state);
+#endif
        } else if (!strcmp(cmd, "version")) {
                debug_printf(state, "%s\n", linux_banner);
        } else if (!strcmp(cmd, "sleep")) {
@@ -808,6 +921,109 @@ static int debug_getc(struct fiq_debugger_state *state)
        return state->pdata->uart_getc(state->pdev);
 }
 
+
+static int debug_cmd_check_back(struct fiq_debugger_state *state, char c)
+{
+       char *s;
+       int i = 0;
+       if (c == 'A') {
+               state->back_pointer = (state->back_pointer-1) & CMD_COUNT;
+               if (state->back_pointer != state->current_pointer) {
+                       s = state->cmd_buf[state->back_pointer];
+                       if (*s != 0) {
+                               for(i = 0; i < strlen(state->debug_buf)-1; i++) {
+                                       state->pdata->uart_putc(state->pdev, 8);
+                                       state->pdata->uart_putc(state->pdev, ' ');
+                                       state->pdata->uart_putc(state->pdev, 8);
+                               }
+                               memset(state->debug_buf, 0, DEBUG_MAX);
+                               strcpy(state->debug_buf, s);
+                               state->debug_count = strlen(state->debug_buf);
+                               debug_printf(state, state->debug_buf);
+                       } else {
+                               state->back_pointer = (state->back_pointer+1) & CMD_COUNT;
+                       }
+
+               } else {
+                       state->back_pointer = (state->back_pointer+1) & CMD_COUNT;
+               }
+       } else if (c == 'B') {
+
+               if (state->back_pointer != state->current_pointer) {
+                       state->back_pointer = (state->back_pointer+1) & CMD_COUNT;
+                       if(state->back_pointer == state->current_pointer){
+                               goto cmd_clear;
+                       } else {
+                               s = state->cmd_buf[state->back_pointer];
+                               if (*s != 0) {
+                                       for(i = 0; i < strlen(state->debug_buf)-1; i++) {
+                                               state->pdata->uart_putc(state->pdev, 8);
+                                               state->pdata->uart_putc(state->pdev, ' ');
+                                               state->pdata->uart_putc(state->pdev, 8);
+                                       }
+                                       memset(state->debug_buf, 0, DEBUG_MAX);
+                                       strcpy(state->debug_buf, s);
+                                       state->debug_count = strlen(state->debug_buf);
+                                       debug_printf(state, state->debug_buf);
+                               }
+                       }
+               } else {
+cmd_clear:
+                       for(i = 0; i < strlen(state->debug_buf)-1; i++) {
+                               state->pdata->uart_putc(state->pdev, 8);
+                               state->pdata->uart_putc(state->pdev, ' ');
+                               state->pdata->uart_putc(state->pdev, 8);
+                       }
+                       memset(state->debug_buf, 0, DEBUG_MAX);
+                       state->debug_count = 0;
+               }
+       }
+       return 0;
+}
+
+static void debug_cmd_tab(struct fiq_debugger_state *state)
+{
+       int i,j;
+       int count = 0;
+
+       for (i = 0; i < ARRAY_SIZE(cmd_buf); i++) {
+               cmd_buf[i][15] = 1;
+       }
+
+       for (j = 1; j <= strlen(state->debug_buf); j++) {
+               count = 0;
+               for (i = 0; i < ARRAY_SIZE(cmd_buf); i++) {
+                       if (cmd_buf[i][15] == 1) {
+                               if (strncmp(state->debug_buf, cmd_buf[i], j)) {
+                                       cmd_buf[i][15] = 0;
+                               } else {
+                                       count++;
+                               }
+                       }
+               }
+               if (count == 0)
+                       break;
+       }
+
+       if (count == 1) {
+               for (i = 0; i < ARRAY_SIZE(cmd_buf); i++) {
+                       if (cmd_buf[i][15] == 1)
+                               break;
+               }
+
+               for(j = 0; j < strlen(state->debug_buf); j++) {
+                       state->pdata->uart_putc(state->pdev, 8);
+                       state->pdata->uart_putc(state->pdev, ' ');
+                       state->pdata->uart_putc(state->pdev, 8);
+               }
+               memset(state->debug_buf, 0, DEBUG_MAX);
+               strcpy(state->debug_buf, cmd_buf[i]);
+               state->debug_count = strlen(state->debug_buf);
+               debug_printf(state, state->debug_buf);
+
+       }
+}
+
 static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state,
                        int this_cpu, void *regs, void *svc_sp)
 {
@@ -845,14 +1061,29 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state,
                        }
                } else if (c == FIQ_DEBUGGER_BREAK) {
                        state->console_enable = false;
-                       debug_puts(state, "fiq debugger mode\n");
+                       debug_puts(state, "\nwelcome to fiq debugger mode\n");
+                       debug_puts(state, "Enter ? to get command help\n");
                        state->debug_count = 0;
+                       state->back_pointer = CMD_COUNT;
+                       state->current_pointer = CMD_COUNT;
+                       memset(state->cmd_buf, 0, (CMD_COUNT+1)*DEBUG_MAX);
                        debug_prompt(state);
 #ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
                } else if (state->console_enable && state->tty_rbuf) {
                        fiq_debugger_ringbuf_push(state->tty_rbuf, c);
                        signal_helper = true;
 #endif
+               } else if (last_c == '[' && (c == 'A' || c == 'B' || c == 'C' || c == 'D')) {
+                       if (state->debug_count > 0) {
+                               state->debug_count--;
+                               state->pdata->uart_putc(state->pdev, 8);
+                               state->pdata->uart_putc(state->pdev, ' ');
+                               state->pdata->uart_putc(state->pdev, 8);
+                       }
+                       debug_cmd_check_back(state, c);
+                       //tab
+               } else if (c == 9) {
+                       debug_cmd_tab(state);
                } else if ((c >= ' ') && (c < 127)) {
                        if (state->debug_count < (DEBUG_MAX - 1)) {
                                state->debug_buf[state->debug_count++] = c;
@@ -876,6 +1107,17 @@ static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state,
                                signal_helper |=
                                        debug_fiq_exec(state, state->debug_buf,
                                                       regs, svc_sp);
+                               if (signal_helper == false) {
+                                       state->current_pointer = (state->current_pointer-1) & CMD_COUNT;
+                                       if (strcmp(state->cmd_buf[state->current_pointer], state->debug_buf)) {
+                                               state->current_pointer = (state->current_pointer+1) & CMD_COUNT;
+                                               memset(state->cmd_buf[state->current_pointer], 0, DEBUG_MAX);
+                                               strcpy(state->cmd_buf[state->current_pointer], state->debug_buf);
+                                       }
+                                       memset(state->debug_buf, 0, DEBUG_MAX);
+                                       state->current_pointer = (state->current_pointer+1) & CMD_COUNT;
+                                       state->back_pointer = state->current_pointer;
+                               }
                        } else {
                                debug_prompt(state);
                        }
@@ -904,6 +1146,21 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
        unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
        bool need_irq;
 
+       /* RK2928 USB-UART function, otg dp/dm default in uart status;
+        * connect with otg cable&usb device, dp/dm will be hi-z status 
+        * and make uart controller enter infinite fiq loop 
+        */
+#ifdef CONFIG_RK_USB_UART
+#ifdef CONFIG_ARCH_RK2928
+       if(!(readl_relaxed(RK2928_GRF_BASE + 0x014c) & (1<<10))){//id low          
+               writel_relaxed(0x34000000, RK2928_GRF_BASE + 0x190);   //enter usb phy    
+       }
+#elif defined(CONFIG_ARCH_RK3188)
+       if(!(readl_relaxed(RK30_GRF_BASE + 0x00ac) & (1 << 13))){//id low          
+               writel_relaxed((0x0300 << 16), RK30_GRF_BASE + 0x010c);   //enter usb phy    
+       }
+#endif
+#endif
        need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp);
        if (need_irq)
                debug_force_irq(state);
@@ -1279,7 +1536,10 @@ static int fiq_debugger_probe(struct platform_device *pdev)
                        pr_err("%s: could not install fiq handler\n", __func__);
                        goto err_register_fiq;
                }
-
+               //set state->fiq to secure state, so fiq is avalable
+               gic_set_irq_secure(irq_get_irq_data(state->fiq));
+               //set state->fiq priority a little higher than other interrupts (normal is 0xa0)
+               gic_set_irq_priority(irq_get_irq_data(state->fiq), 0x90);
                pdata->fiq_enable(pdev, state->fiq, 1);
        } else {
                ret = request_irq(state->uart_irq, debug_uart_irq,
index 4930e8f7abc2aaa415d4a1f2fe1efbba7ac8c265..81548b26b079017ded99eb96f891f69cb1cee59a 100644 (file)
@@ -34,6 +34,10 @@ CONFIG_ARCH_ROCKCHIP=y
 CONFIG_ARM_ERRATA_720789=y
 CONFIG_PL310_ERRATA_753970=y
 CONFIG_ARM_ERRATA_754322=y
+CONFIG_FIQ_DEBUGGER=y
+CONFIG_FIQ_DEBUGGER_NO_SLEEP=y
+CONFIG_FIQ_DEBUGGER_CONSOLE=y
+CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE=y
 CONFIG_SMP=y
 CONFIG_SCHED_MC=y
 CONFIG_PREEMPT=y
@@ -258,7 +262,6 @@ CONFIG_INPUT_UINPUT=y
 # CONFIG_VT is not set
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_ROCKCHIP=y
-CONFIG_SERIAL_ROCKCHIP_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
 CONFIG_SPI=y
index 7cb3156ff2163ea5517d34aa0846b64a9e5a79cb..1a6b65bd130532afee5f4b1cf17868d98db485f2 100644 (file)
@@ -1,3 +1,4 @@
 obj-y += common.o
 obj-y += rk3188.o
 obj-$(CONFIG_SMP) += platsmp.o
+obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o
index 9d8dc8906385bc53f1888f2f92c783a3561dfadf..7bbfa61c669ea76f46cf4f877d385116d1b309ce 100644 (file)
@@ -49,7 +49,7 @@ static const char * const rk3188_dt_compat[] = {
 };
 
 DT_MACHINE_START(RK3188_DT, "Rockchip RK3188 (Flattened Device Tree)")
-       .nr_irqs        = 32*10,
+       //.nr_irqs        = 32*10,
        .smp            = smp_ops(rockchip_smp_ops),
        .map_io         = rk3188_dt_map_io,
        .init_machine   = rk3188_dt_init,
diff --git a/arch/arm/mach-rockchip/rk_fiq_debugger.c b/arch/arm/mach-rockchip/rk_fiq_debugger.c
new file mode 100644 (file)
index 0000000..7e8c925
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * arch/arm/plat-rk/rk_fiq_debugger.c
+ *
+ * Serial Debugger Interface for Rockchip
+ *
+ * Copyright (C) 2012 ROCKCHIP, Inc.
+ * Copyright (C) 2008 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 <stdarg.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/serial_reg.h>
+#include <linux/slab.h>
+#include <linux/stacktrace.h>
+#include <linux/uaccess.h>
+#include <linux/kfifo.h>
+#include <linux/kthread.h>
+#include <asm/fiq_debugger.h>
+#include <linux/irqchip/arm-gic.h>
+#include "rk_fiq_debugger.h"
+
+struct rk_fiq_debugger {
+       struct fiq_debugger_pdata pdata;
+       void __iomem *debug_port_base;
+       bool break_seen;
+#ifdef CONFIG_RK_CONSOLE_THREAD
+       struct task_struct *console_task;
+#endif
+};
+
+static inline void rk_fiq_write(struct rk_fiq_debugger *t,
+       unsigned int val, unsigned int off)
+{
+       __raw_writeb(val, t->debug_port_base + off * 4);
+}
+
+static inline unsigned int rk_fiq_read(struct rk_fiq_debugger *t,
+       unsigned int off)
+{
+       return __raw_readb(t->debug_port_base + off * 4);
+}
+
+static inline unsigned int rk_fiq_read_lsr(struct rk_fiq_debugger *t)
+{
+       unsigned int lsr;
+
+       lsr = rk_fiq_read(t, UART_LSR);
+       if (lsr & UART_LSR_BI)
+               t->break_seen = true;
+
+       return lsr;
+}
+
+static int debug_port_init(struct platform_device *pdev)
+{
+       struct rk_fiq_debugger *t;
+       t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
+
+       if (rk_fiq_read(t, UART_LSR) & UART_LSR_DR)
+               (void)rk_fiq_read(t, UART_RX);
+       /* enable rx and lsr interrupt */
+       rk_fiq_write(t, UART_IER_RLSI | UART_IER_RDI, UART_IER);
+       /* interrupt on every character when receive,but we can enable fifo for TX
+       I found that if we enable the RX fifo, some problem may vanish such as when
+       you continuously input characters in the command line the uart irq may be disable
+       because of the uart irq is served when CPU is at IRQ exception,but it is
+       found unregistered, so it is disable.
+       hhb@rock-chips.com */
+       rk_fiq_write(t, 0xc1, UART_FCR);
+
+       return 0;
+}
+
+static int debug_getc(struct platform_device *pdev)
+{
+       unsigned int lsr;
+       struct rk_fiq_debugger *t;
+       t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
+
+       lsr = rk_fiq_read_lsr(t);
+
+       if (lsr & UART_LSR_BI || t->break_seen) {
+               t->break_seen = false;
+               return FIQ_DEBUGGER_BREAK;
+       }
+
+       if (lsr & UART_LSR_DR)
+               return rk_fiq_read(t, UART_RX);
+
+       return FIQ_DEBUGGER_NO_CHAR;
+}
+
+static void debug_putc(struct platform_device *pdev, unsigned int c)
+{
+       struct rk_fiq_debugger *t;
+       t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
+
+//     while (!(rk_fiq_read_lsr(t) & UART_LSR_THRE))
+//             cpu_relax();
+       //enable TX FIFO
+       while (!(rk_fiq_read(t, 0x1F) & 0x02))
+               cpu_relax();
+       rk_fiq_write(t, c, UART_TX);
+}
+
+static void debug_flush(struct platform_device *pdev)
+{
+       struct rk_fiq_debugger *t;
+       t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
+
+       while (!(rk_fiq_read_lsr(t) & UART_LSR_TEMT))
+               cpu_relax();
+}
+
+#ifdef CONFIG_RK_CONSOLE_THREAD
+static DEFINE_KFIFO(fifo, unsigned char, SZ_64K);
+
+static int console_thread(void *data)
+{
+       struct platform_device *pdev = data;
+       struct rk_fiq_debugger *t;
+       unsigned char c;
+       t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
+
+       while (1) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               schedule();
+               if (kthread_should_stop())
+                       break;
+               set_current_state(TASK_RUNNING);
+               while (kfifo_get(&fifo, &c))
+                       debug_putc(pdev, c);
+               debug_flush(pdev);
+       }
+
+       return 0;
+}
+
+static void console_write(struct platform_device *pdev, const char *s, unsigned int count)
+{
+       unsigned char c, r = '\r';
+       static bool oops = false;
+       struct rk_fiq_debugger *t;
+       t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
+
+       if (oops_in_progress || oops) {
+               debug_flush(pdev);
+               while (kfifo_get(&fifo, &c))
+                       debug_putc(pdev, c);
+               while (count--) {
+                       if (*s == '\n') {
+                               debug_putc(pdev, r);
+                       }
+                       debug_putc(pdev, *s++);
+               }
+               debug_flush(pdev);
+               oops = true;
+               return;
+       }
+
+       while (count--) {
+               if (*s == '\n') {
+                       kfifo_put(&fifo, &r);
+               }
+               kfifo_put(&fifo, s++);
+       }
+       wake_up_process(t->console_task);
+}
+#endif
+
+
+static void fiq_enable(struct platform_device *pdev, unsigned int irq, bool on)
+{
+       if (on)
+               enable_irq(irq);
+       else
+               disable_irq(irq);
+}
+
+static int rk_fiq_debugger_id;
+
+void rk_serial_debug_init(void __iomem *base, int irq, int signal_irq, int wakeup_irq)
+{
+       struct rk_fiq_debugger *t = NULL;
+       struct platform_device *pdev = NULL;
+       struct resource *res = NULL;
+       int res_count = 0;
+
+       if (!base) {
+               pr_err("Invalid fiq debugger uart base\n");
+               return;
+       }
+
+       t = kzalloc(sizeof(struct rk_fiq_debugger), GFP_KERNEL);
+       if (!t) {
+               pr_err("Failed to allocate for fiq debugger\n");
+               return;
+       }
+
+       t->pdata.uart_init = debug_port_init;
+       t->pdata.uart_getc = debug_getc;
+       t->pdata.uart_putc = debug_putc;
+#ifndef CONFIG_RK_CONSOLE_THREAD
+       t->pdata.uart_flush = debug_flush;
+#endif
+       t->pdata.fiq_enable = fiq_enable;
+       t->pdata.force_irq = NULL;  //force_irq;
+       t->debug_port_base = base;
+
+       res = kzalloc(sizeof(struct resource) * 3, GFP_KERNEL);
+       if (!res) {
+               pr_err("Failed to alloc fiq debugger resources\n");
+               goto out2;
+       }
+
+       pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
+       if (!pdev) {
+               pr_err("Failed to alloc fiq debugger platform device\n");
+               goto out3;
+       };
+
+       if (irq > 0) {
+               res[0].flags = IORESOURCE_IRQ;
+               res[0].start = irq;
+               res[0].end = irq;
+               res[0].name = "fiq";
+               res_count++;
+       }
+
+       if (signal_irq > 0) {
+               res[1].flags = IORESOURCE_IRQ;
+               res[1].start = signal_irq;
+               res[1].end = signal_irq;
+               res[1].name = "signal";
+               res_count++;
+       }
+
+       if (wakeup_irq > 0) {
+               res[2].flags = IORESOURCE_IRQ;
+               res[2].start = wakeup_irq;
+               res[2].end = wakeup_irq;
+               res[2].name = "wakeup";
+               res_count++;
+       }
+
+#ifdef CONFIG_RK_CONSOLE_THREAD
+       t->console_task = kthread_create(console_thread, pdev, "kconsole");
+       if (!IS_ERR(t->console_task)) {
+               struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+               t->pdata.console_write = console_write;
+               sched_setscheduler_nocheck(t->console_task, SCHED_FIFO, &param);
+       }
+#endif
+
+       pdev->name = "fiq_debugger";
+       pdev->id = rk_fiq_debugger_id++;
+       pdev->dev.platform_data = &t->pdata;
+       pdev->resource = res;
+       pdev->num_resources = res_count;
+       if (platform_device_register(pdev)) {
+               pr_err("Failed to register fiq debugger\n");
+               goto out4;
+       }
+       return;
+
+out4:
+       kfree(pdev);
+out3:
+       kfree(res);
+out2:
+       kfree(t);
+}
+
+static int __init rk_fiq_debugger_init(void) {
+
+       void __iomem *base;
+       u32 out_values[6] = {0};
+       struct device_node *from = NULL;
+       unsigned int i = 0, id = 0, serial_id = 0, ok = 0;
+       u32 irq = 32, signal_irq = 0, wake_irq = 0;
+       
+       from = of_find_node_by_name(from, "ttyFIQ0");
+       
+       if(!from) {
+               printk("ttyFIQ0 is missing in device tree!\n");
+               return -ENODEV;
+       }
+               
+       if(of_property_read_u32(from, "id", &id)) {
+               return -EINVAL; 
+       }
+
+       if(of_property_read_u32(from, "signal_irq", &signal_irq)) {
+               signal_irq = -1;
+       }
+
+       if(of_property_read_u32(from, "wake_irq", &wake_irq)) {
+               wake_irq = -1;
+       }
+       
+       from = NULL;
+       for(i = 0; i < 5; i++) {
+               from = of_find_node_by_name(from, "serial");
+               if(from && !of_property_read_u32(from, "id", &serial_id)) {
+                       if(id == serial_id) {
+                               ok = 1;
+                               break;
+                       }
+               }
+       }
+       
+       if(ok != 1)
+               return -EINVAL;
+
+       if(of_property_read_u32_array(from, "interrupts", out_values, 3))
+               return -EINVAL;
+       irq += *(out_values + 1);
+       base = of_iomap(from, 0);
+       if(base)
+               rk_serial_debug_init(base, irq, signal_irq, wake_irq);
+       return 0;
+}
+
+postcore_initcall_sync(rk_fiq_debugger_init);
diff --git a/arch/arm/mach-rockchip/rk_fiq_debugger.h b/arch/arm/mach-rockchip/rk_fiq_debugger.h
new file mode 100644 (file)
index 0000000..5c85c07
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __PLAT_RK_FIQ_DEBUGGER_H
+#define __PLAT_RK_FIQ_DEBUGGER_H
+
+#ifdef CONFIG_FIQ_DEBUGGER
+void rk_serial_debug_init(void __iomem *base, int irq, int signal_irq, int wakeup_irq);
+#else
+static inline void rk_serial_debug_init(void __iomem *base, int irq, int signal_irq, int wakeup_irq)
+{
+}
+#endif
+
+#endif
index 65bc83747f6664a3c37c6bb8c109d2ed2de93df6..48eefabac3d58a68b50a01538be8cde6620c8e17 100644 (file)
@@ -235,13 +235,42 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 
 static int gic_retrigger(struct irq_data *d)
 {
+       u32 mask = 1 << (gic_irq(d) % 32);
+
        if (gic_arch_extn.irq_retrigger)
                return gic_arch_extn.irq_retrigger(d);
 
+#ifdef CONFIG_FIQ_DEBUGGER
+       /* set irq pending to retrigger to cpu */
+       writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_PENDING_SET + (gic_irq(d) / 32) * 4);
+#endif
        /* the genirq layer expects 0 if we can't retrigger in hardware */
        return 0;
 }
 
+#ifdef CONFIG_FIQ_DEBUGGER
+/*
+ *     ICDISR each bit   0 -- Secure   1--Non-Secure
+ */
+void gic_set_irq_secure(struct irq_data *d)
+{
+       u32 mask = 0;
+       void __iomem *base = gic_dist_base(d);
+
+       //raw_spin_lock(&irq_controller_lock);
+       base += GIC_DIST_IGROUP + ((gic_irq(d) / 32) * 4);
+       mask = readl_relaxed(base);
+       mask &= ~(1 << (gic_irq(d) % 32));
+       writel_relaxed(mask, base);
+       //raw_spin_unlock(&irq_controller_lock);
+}
+
+void gic_set_irq_priority(struct irq_data *d, u8 pri)
+{
+       writeb_relaxed(pri, gic_dist_base(d) + GIC_DIST_PRI + gic_irq(d));
+}
+#endif
+
 #ifdef CONFIG_SMP
 static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
                            bool force)
@@ -411,7 +440,17 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
        for (i = 32; i < gic_irqs; i += 32)
                writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
 
+#ifdef CONFIG_FIQ_DEBUGGER
+       // set all the interrupt to non-secure state
+       for (i = 0; i < gic_irqs; i += 32) {
+               writel_relaxed(0xffffffff, base + GIC_DIST_IGROUP + i * 4 / 32);
+       }
+       
+       dsb();
+       writel_relaxed(0x3, base + GIC_DIST_CTRL);
+#else
        writel_relaxed(1, base + GIC_DIST_CTRL);
+#endif
 }
 
 static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
@@ -450,7 +489,11 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
                writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
 
        writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
+#ifdef CONFIG_FIQ_DEBUGGER
+       writel_relaxed(0x0f, base + GIC_CPU_CTRL);
+#else
        writel_relaxed(1, base + GIC_CPU_CTRL);
+#endif
 }
 
 void gic_cpu_if_down(void)
@@ -669,8 +712,12 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
        dsb();
 
        /* this always happens on GIC0 */
+#ifdef CONFIG_FIQ_DEBUGGER
+       /* enable non-secure SGI for GIC with security extensions */
+       writel_relaxed(map << 16 | irq | 0x8000, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+#else
        writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-
+#endif
        raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
 }
 #endif
@@ -851,8 +898,14 @@ static int gic_irq_domain_xlate(struct irq_domain *d,
 static int __cpuinit gic_secondary_init(struct notifier_block *nfb,
                                        unsigned long action, void *hcpu)
 {
-       if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
+       if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) {
                gic_cpu_init(&gic_data[0]);
+#ifdef CONFIG_FIQ_DEBUGGER
+               /*set SGI to none secure state*/
+               writel_relaxed(0xffffffff, gic_data_dist_base(&gic_data[0]) + GIC_DIST_IGROUP);
+               writel_relaxed(0xf, gic_data_cpu_base(&gic_data[0]) + GIC_CPU_CTRL);
+#endif
+       }
        return NOTIFY_OK;
 }