add fiq debugger

This commit is contained in:
hhb
2013-12-03 21:41:29 +08:00
parent 2ec82dc352
commit 1ff10f8f5b
9 changed files with 692 additions and 16 deletions

View File

@@ -9,7 +9,11 @@
};
chosen {
bootargs ="console=ttyS2,115200 androidboot.console=ttyS2";
};
ttyFIQ0 {
id = <2>;
};
};
@@ -17,10 +21,6 @@
status = "okay";
};
&uart2 {
status = "okay";
};
&uart3 {
status = "okay";
};

View File

@@ -416,4 +416,11 @@
pinctrl-0 = <&uart3_xfer &uart3_cts &uart3_rts>;
status = "disabled";
};
ttyFIQ0 {
id = <2>;
signal_irq = <112>;
wake_irq = <0>;
status = "disabled";
};
};

View File

@@ -43,7 +43,14 @@
#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,9 +232,32 @@ 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)
{
switch (cpsr & MODE_MASK) {
@@ -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,

View 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

View 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

View 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,

View File

@@ -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);

View File

@@ -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

View 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;
}