diff options
Diffstat (limited to 'arch/arm/mach-s5pv210/dev-fiqdbg.c')
-rw-r--r-- | arch/arm/mach-s5pv210/dev-fiqdbg.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/arch/arm/mach-s5pv210/dev-fiqdbg.c b/arch/arm/mach-s5pv210/dev-fiqdbg.c new file mode 100644 index 0000000..16ef49b --- /dev/null +++ b/arch/arm/mach-s5pv210/dev-fiqdbg.c @@ -0,0 +1,161 @@ +/* linux/arch/arm/mach-s5pv210/dev-fiqdbg.c + * + * 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. + */ + +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/irq.h> +#include <linux/sysdev.h> + +#include <asm/hardware/vic.h> +#include <asm/fiq_debugger.h> + +#include <mach/irqs.h> +#include <mach/map.h> +#include <plat/regs-serial.h> + +static void *s5pv210_fiqdbg_get_base(struct platform_device *pdev) +{ + return S5P_VA_UART0 + S3C_UART_OFFSET * pdev->id; +} + +static unsigned int s5pv210_fiqdbg_tx_empty(void *base) +{ + unsigned long ufstat = readl(base + S3C2410_UFSTAT); + + return !(ufstat & (S5PV210_UFSTAT_TXMASK | S5PV210_UFSTAT_TXFULL)); +} + +static void s5pv210_fiqdbg_wait_for_tx_empty(void *base) +{ + unsigned int tmout = 10000; + + while (true) { + if (s5pv210_fiqdbg_tx_empty(base)) + return; + if (--tmout == 0) + break; + udelay(1); + } +} + +static int s5pv210_fiqdbg_uart_getc(struct platform_device *pdev) +{ + void *base = s5pv210_fiqdbg_get_base(pdev); + unsigned int ufstat; + + if (readl(base + S3C2410_UERSTAT) & S3C2410_UERSTAT_BREAK) + return FIQ_DEBUGGER_BREAK; + + ufstat = readl(base + S3C2410_UFSTAT); + if (!(ufstat & (S5PV210_UFSTAT_RXMASK | S5PV210_UFSTAT_RXFULL))) + return FIQ_DEBUGGER_NO_CHAR; + return readb(base + S3C2410_URXH); +} + +static void s5pv210_fiqdbg_uart_putc(struct platform_device *pdev, + unsigned int c) +{ + void *base = s5pv210_fiqdbg_get_base(pdev); + s5pv210_fiqdbg_wait_for_tx_empty(base); + writeb(c, base + S3C2410_UTXH); + if (c == 10) { + s5pv210_fiqdbg_wait_for_tx_empty(base); + writeb(13, base + S3C2410_UTXH); + } + s5pv210_fiqdbg_wait_for_tx_empty(base); +} + +static void fiq_enable(struct platform_device *pdev, + unsigned int fiq, bool enabled) +{ + struct irq_chip *chip = irq_get_chip(fiq); + struct irq_data *d = irq_get_irq_data(fiq); + + vic_set_fiq(fiq, enabled); + if (enabled) + chip->irq_unmask(d); + else + chip->irq_mask(d); +} + +static void fiq_ack(struct platform_device *pdev, unsigned int fiq) +{ + void *base = s5pv210_fiqdbg_get_base(pdev); + writel(0x3, base + S5P_UINTP); +} + +static int s5pv210_fiqdbg_uart_init(struct platform_device *pdev) +{ + void *base = s5pv210_fiqdbg_get_base(pdev); + + writel(S3C2410_UCON_TXILEVEL | + S3C2410_UCON_RXILEVEL | + S3C2410_UCON_TXIRQMODE | + S3C2410_UCON_RXIRQMODE | + S3C2410_UCON_RXFIFO_TOI | + S3C2443_UCON_RXERR_IRQEN, base + S3C2410_UCON); + writel(S3C2410_LCON_CS8, base + S3C2410_ULCON); + writel(S3C2410_UFCON_FIFOMODE | + S5PV210_UFCON_TXTRIG4 | + S5PV210_UFCON_RXTRIG4 | + S3C2410_UFCON_RESETRX, base + S3C2410_UFCON); + writel(0, base + S3C2410_UMCON); + /* 115200 */ + writel(35, base + S3C2410_UBRDIV); + writel(0x808, base + S3C2443_DIVSLOT); + writel(0xc, base + S5P_UINTM); + writel(0xf, base + S5P_UINTP); + + return 0; +} + +static struct fiq_debugger_pdata s5pv210_fiqdbg_pdata = { + .uart_init = s5pv210_fiqdbg_uart_init, + .uart_resume = s5pv210_fiqdbg_uart_init, + .uart_getc = s5pv210_fiqdbg_uart_getc, + .uart_putc = s5pv210_fiqdbg_uart_putc, + .fiq_enable = fiq_enable, + .fiq_ack = fiq_ack, +}; + +#define DEFINE_FIQDBG_UART(uart) \ +static struct resource s5pv210_fiqdbg_uart##uart##_resource[] = { \ + { \ + .start = IRQ_UART##uart, \ + .end = IRQ_UART##uart, \ + .name = "fiq", \ + .flags = IORESOURCE_IRQ, \ + }, \ + { \ + .start = IRQ_VIC_END-uart, \ + .end = IRQ_VIC_END-uart, \ + .name = "signal", \ + .flags = IORESOURCE_IRQ, \ + }, \ +}; \ +struct platform_device s5pv210_device_fiqdbg_uart##uart = { \ + .name = "fiq_debugger", \ + .id = uart, \ + .num_resources = ARRAY_SIZE(s5pv210_fiqdbg_uart##uart##_resource), \ + .resource = s5pv210_fiqdbg_uart##uart##_resource, \ + .dev = { \ + .platform_data = &s5pv210_fiqdbg_pdata, \ + }, \ +} + +DEFINE_FIQDBG_UART(0); +DEFINE_FIQDBG_UART(1); +DEFINE_FIQDBG_UART(2); +DEFINE_FIQDBG_UART(3); |