};
chosen {
- bootargs ="console=ttyS2,115200 androidboot.console=ttyS2";
+
};
-};
-&uart0 {
- status = "okay";
+ ttyFIQ0 {
+ id = <2>;
+ };
};
-&uart2 {
+&uart0 {
status = "okay";
};
pinctrl-0 = <&uart3_xfer &uart3_cts &uart3_rts>;
status = "disabled";
};
+
+ ttyFIQ0 {
+ id = <2>;
+ signal_irq = <112>;
+ wake_irq = <0>;
+ status = "disabled";
+ };
};
#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
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;
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) {}
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)
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)
{
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");
(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 {
/* 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"
" 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"
{
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;
}
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")) {
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)
{
}
} 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;
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);
}
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);
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,
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
# 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
obj-y += common.o
obj-y += rk3188.o
obj-$(CONFIG_SMP) += platsmp.o
+obj-$(CONFIG_FIQ_DEBUGGER) += rk_fiq_debugger.o
};
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,
--- /dev/null
+/*
+ * 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, ¶m);
+ }
+#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);
--- /dev/null
+#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
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)
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)
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)
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
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;
}