From 461cb80c16e4e266ab6207a00767b59212148086 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 4 Oct 2010 18:32:15 -0700 Subject: [PATCH] [ARM] tegra: Add fiq debugger Change-Id: Ic625e20c0a9a147ae39153f18d328f2181b81318 Signed-off-by: Colin Cross --- arch/arm/mach-tegra/Kconfig | 7 + arch/arm/mach-tegra/Makefile | 1 + .../include/mach/tegra_fiq_debugger.h | 30 +++ arch/arm/mach-tegra/tegra_fiq_debugger.c | 208 ++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 arch/arm/mach-tegra/include/mach/tegra_fiq_debugger.h create mode 100644 arch/arm/mach-tegra/tegra_fiq_debugger.c diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 398af59d7e3e..0bd7b41592be 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -66,6 +66,13 @@ config TEGRA_PWM help Enable support for the Tegra PWM controller(s). +config TEGRA_FIQ_DEBUGGER + bool "Enable the FIQ serial debugger on Tegra" + default y + select FIQ_DEBUGGER + help + Enables the FIQ serial debugger on Tegra" + endif config TEGRA_IOVMM_GART diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile index bc049fbe80c8..2d486ad0ffc4 100644 --- a/arch/arm/mach-tegra/Makefile +++ b/arch/arm/mach-tegra/Makefile @@ -13,6 +13,7 @@ obj-y += fuse.o obj-y += tegra_i2s_audio.o obj-$(CONFIG_USB_SUPPORT) += usb_phy.o obj-$(CONFIG_FIQ) += fiq.o +obj-$(CONFIG_TEGRA_FIQ_DEBUGGER) += tegra_fiq_debugger.o obj-$(CONFIG_TEGRA_PWM) += pwm.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clock.o diff --git a/arch/arm/mach-tegra/include/mach/tegra_fiq_debugger.h b/arch/arm/mach-tegra/include/mach/tegra_fiq_debugger.h new file mode 100644 index 000000000000..4d1a0b54f2ae --- /dev/null +++ b/arch/arm/mach-tegra/include/mach/tegra_fiq_debugger.h @@ -0,0 +1,30 @@ +/* + * linux/arch/arm/mach-tegra/include/mach/tegra_fiq_debugger.h + * + * 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 __MACH_TEGRA_FIQ_DEBUGGER_H +#define __MACH_TEGRA_FIQ_DEBUGGER_H + +#ifdef CONFIG_TEGRA_FIQ_DEBUGGER +void tegra_serial_debug_init(unsigned int base, int irq, + struct clk *clk, int signal_irq, int wakeup_irq); +#else +static inline void tegra_serial_debug_init(unsigned int base, int irq, + struct clk *clk, int signal_irq, int wakeup_irq) +{ +} +#endif + +#endif diff --git a/arch/arm/mach-tegra/tegra_fiq_debugger.c b/arch/arm/mach-tegra/tegra_fiq_debugger.c new file mode 100644 index 000000000000..29e3119b0edd --- /dev/null +++ b/arch/arm/mach-tegra/tegra_fiq_debugger.c @@ -0,0 +1,208 @@ +/* + * arch/arm/mach-tegra/fiq_debugger.c + * + * Serial Debugger Interface for Tegra + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +struct tegra_fiq_debugger { + struct fiq_debugger_pdata pdata; + void __iomem *debug_port_base; + bool break_seen; +}; + +static inline void tegra_write(struct tegra_fiq_debugger *t, + unsigned int val, unsigned int off) +{ + __raw_writeb(val, t->debug_port_base + off * 4); +} + +static inline unsigned int tegra_read(struct tegra_fiq_debugger *t, + unsigned int off) +{ + return __raw_readb(t->debug_port_base + off * 4); +} + +static inline unsigned int tegra_read_lsr(struct tegra_fiq_debugger *t) +{ + unsigned int lsr; + + lsr = tegra_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 tegra_fiq_debugger *t; + t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata); + + if (tegra_read(t, UART_LSR) & UART_LSR_DR) + (void)tegra_read(t, UART_RX); + /* enable rx and lsr interrupt */ + tegra_write(t, UART_IER_RLSI | UART_IER_RDI, UART_IER); + /* interrupt on every character */ + tegra_write(t, 0, UART_IIR); + + return 0; +} + +static int debug_getc(struct platform_device *pdev) +{ + unsigned int lsr; + struct tegra_fiq_debugger *t; + t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata); + + lsr = tegra_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 tegra_read(t, UART_RX); + + return FIQ_DEBUGGER_NO_CHAR; +} + +static void debug_putc(struct platform_device *pdev, unsigned int c) +{ + struct tegra_fiq_debugger *t; + t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata); + + while (!(tegra_read_lsr(t) & UART_LSR_THRE)) + cpu_relax(); + + tegra_write(t, c, UART_TX); +} + +static void debug_flush(struct platform_device *pdev) +{ + struct tegra_fiq_debugger *t; + t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata); + + while (!(tegra_read_lsr(t) & UART_LSR_TEMT)) + cpu_relax(); +} + +static void fiq_enable(struct platform_device *pdev, unsigned int irq, bool on) +{ + if (on) + tegra_fiq_enable(irq); + else + tegra_fiq_disable(irq); +} + +static int tegra_fiq_debugger_id; + +void tegra_serial_debug_init(unsigned int base, int irq, + struct clk *clk, int signal_irq, int wakeup_irq) +{ + struct tegra_fiq_debugger *t; + struct platform_device *pdev; + struct resource *res; + int res_count; + + t = kzalloc(sizeof(struct tegra_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; + t->pdata.uart_flush = debug_flush; + t->pdata.fiq_enable = fiq_enable; + + t->debug_port_base = ioremap(base, PAGE_SIZE); + if (!t->debug_port_base) { + pr_err("Failed to ioremap for fiq debugger\n"); + goto out1; + } + + 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; + }; + + res[0].flags = IORESOURCE_IRQ; + res[0].start = irq; + res[0].end = irq; + res[0].name = "fiq"; + + res[1].flags = IORESOURCE_IRQ; + res[1].start = signal_irq; + res[1].end = signal_irq; + res[1].name = "signal"; + res_count = 2; + + 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++; + } + + pdev->name = "fiq_debugger"; + pdev->id = tegra_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: + iounmap(t->debug_port_base); +out1: + kfree(t); +} -- 2.34.1