From 4f5728987f4f9f7845688482aa2b7f2127768165 Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Sun, 22 Feb 2009 15:49:28 +0100 Subject: arm: add uart dcc support Serial driver via the EmbeddedICE macrocell's DCC channel using co-processor 14. It does include a timeout to ensure that the system does not totally freeze when there is nothing connected to read. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD --- common/devices.c | 3 + drivers/serial/Makefile | 1 + drivers/serial/arm_dcc.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++ include/devices.h | 3 + lib_arm/board.c | 3 + 5 files changed, 236 insertions(+) create mode 100644 drivers/serial/arm_dcc.c diff --git a/common/devices.c b/common/devices.c index 38f1bbc..ba53c9b 100644 --- a/common/devices.c +++ b/common/devices.c @@ -215,6 +215,9 @@ int devices_init (void) /* Initialize the list */ INIT_LIST_HEAD(&(devs.list)); +#ifdef CONFIG_ARM_DCC_MULTI + drv_arm_dcc_init (); +#endif #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); #endif diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 0f980ab..d0efd73 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk LIB := $(obj)libserial.a +COBJS-$(CONFIG_ARM_DCC) += arm_dcc.o COBJS-$(CONFIG_ATMEL_USART) += atmel_usart.o COBJS-$(CONFIG_MCFUART) += mcfuart.o COBJS-$(CONFIG_NS9750_UART) += ns9750_serial.o diff --git a/drivers/serial/arm_dcc.c b/drivers/serial/arm_dcc.c new file mode 100644 index 0000000..5a7fb6b --- /dev/null +++ b/drivers/serial/arm_dcc.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2004-2007 ARM Limited. + * Copyright (C) 2008 Jean-Christophe PLAGNIOL-VILLARD + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * As a special exception, if other files instantiate templates or use macros + * or inline functions from this file, or you compile this file and link it + * with other works to produce a work based on this file, this file does not + * by itself cause the resulting work to be covered by the GNU General Public + * License. However the source code for this file must still be made available + * in accordance with section (3) of the GNU General Public License. + + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + */ + +#include +#include + +#define DCC_ARM9_RBIT (1 << 0) +#define DCC_ARM9_WBIT (1 << 1) +#define DCC_ARM11_RBIT (1 << 30) +#define DCC_ARM11_WBIT (1 << 29) + +#define read_core_id(x) do { \ + __asm__ ("mrc p15, 0, %0, c0, c0, 0\n" : "=r" (x)); \ + x = (x >> 4) & 0xFFF; \ + } while (0); + +/* + * ARM9 + */ +#define write_arm9_dcc(x) \ + __asm__ volatile ("mcr p14, 0, %0, c1, c0, 0\n" : : "r" (x)) + +#define read_arm9_dcc(x) \ + __asm__ volatile ("mrc p14, 0, %0, c1, c0, 0\n" : "=r" (x)) + +#define status_arm9_dcc(x) \ + __asm__ volatile ("mrc p14, 0, %0, c0, c0, 0\n" : "=r" (x)) + +#define can_read_arm9_dcc(x) do { \ + status_arm9_dcc(x); \ + x &= DCC_ARM9_RBIT; \ + } while (0); + +#define can_write_arm9_dcc(x) do { \ + status_arm9_dcc(x); \ + x &= DCC_ARM9_WBIT; \ + x = (x == 0); \ + } while (0); + +/* + * ARM11 + */ +#define write_arm11_dcc(x) \ + __asm__ volatile ("mcr p14, 0, %0, c0, c5, 0\n" : : "r" (x)) + +#define read_arm11_dcc(x) \ + __asm__ volatile ("mrc p14, 0, %0, c0, c5, 0\n" : "=r" (x)) + +#define status_arm11_dcc(x) \ + __asm__ volatile ("mrc p14, 0, %0, c0, c1, 0\n" : "=r" (x)) + +#define can_read_arm11_dcc(x) do { \ + status_arm11_dcc(x); \ + x &= DCC_ARM11_RBIT; \ + } while (0); + +#define can_write_arm11_dcc(x) do { \ + status_arm11_dcc(x); \ + x &= DCC_ARM11_WBIT; \ + x = (x == 0); \ + } while (0); + +#define TIMEOUT_COUNT 0x4000000 + +static enum { + arm9_and_earlier, + arm11_and_later +} arm_type = arm9_and_earlier; + +#ifndef CONFIG_ARM_DCC_MULTI +#define arm_dcc_init serial_init +void serial_setbrg(void) {} +#define arm_dcc_getc serial_getc +#define arm_dcc_putc serial_putc +#define arm_dcc_puts serial_puts +#define arm_dcc_tstc serial_tstc +#endif + +int arm_dcc_init(void) +{ + register unsigned int id; + + read_core_id(id); + + if (id >= 0xb00) + arm_type = arm11_and_later; + else + arm_type = arm9_and_earlier; + + return 0; +} + +int arm_dcc_getc(void) +{ + int ch; + register unsigned int reg; + + switch (arm_type) { + case arm11_and_later: + do { + can_read_arm11_dcc(reg); + } while (!reg); + read_arm11_dcc(ch); + break; + + case arm9_and_earlier: + default: + do { + can_read_arm9_dcc(reg); + } while (!reg); + read_arm9_dcc(ch); + break; + } + + return ch; +} + +void arm_dcc_putc(char ch) +{ + register unsigned int reg; + unsigned int timeout_count = TIMEOUT_COUNT; + + switch (arm_type) { + case arm11_and_later: + while (--timeout_count) { + can_write_arm11_dcc(reg); + if (reg) + break; + } + if (timeout_count == 0) + return; + else + write_arm11_dcc(ch); + break; + + case arm9_and_earlier: + default: + while (--timeout_count) { + can_write_arm9_dcc(reg); + if (reg) + break; + } + if (timeout_count == 0) + return; + else + write_arm9_dcc(ch); + break; + } +} + +void arm_dcc_puts(const char *s) +{ + while (*s) + arm_dcc_putc(*s++); +} + +int arm_dcc_tstc(void) +{ + register unsigned int reg; + + switch (arm_type) { + case arm11_and_later: + can_read_arm11_dcc(reg); + break; + case arm9_and_earlier: + default: + can_read_arm9_dcc(reg); + break; + } + + return reg; +} + +#ifdef CONFIG_ARM_DCC_MULTI +static device_t arm_dcc_dev; + +int drv_arm_dcc_init(void) +{ + int rc; + + /* Device initialization */ + memset(&arm_dcc_dev, 0, sizeof(arm_dcc_dev)); + + strcpy(arm_dcc_dev.name, "dcc"); + arm_dcc_dev.ext = 0; /* No extensions */ + arm_dcc_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_OUTPUT; + arm_dcc_dev.tstc = arm_dcc_tstc; /* 'tstc' function */ + arm_dcc_dev.getc = arm_dcc_getc; /* 'getc' function */ + arm_dcc_dev.putc = arm_dcc_putc; /* 'putc' function */ + arm_dcc_dev.puts = arm_dcc_puts; /* 'puts' function */ + + rc = device_register(&arm_dcc_dev); + + if (rc == 0) { + arm_dcc_init(); + return 1; + } + + return 0; +} +#endif diff --git a/include/devices.h b/include/devices.h index 84c4514..3a9881b 100644 --- a/include/devices.h +++ b/include/devices.h @@ -98,6 +98,9 @@ struct list_head* device_get_list(void); device_t* device_get_by_name(char* name); device_t* device_clone(device_t *dev); +#ifdef CONFIG_ARM_DCC_MULTI +int drv_arm_dcc_init(void); +#endif #ifdef CONFIG_LCD int drv_lcd_init (void); #endif diff --git a/lib_arm/board.c b/lib_arm/board.c index f125d38..09eaaf2 100644 --- a/lib_arm/board.c +++ b/lib_arm/board.c @@ -145,6 +145,9 @@ void inline yellow_LED_off(void)__attribute__((weak, alias("__yellow_LED_off"))) * but let's get it working (again) first... */ +#if defined(CONFIG_ARM_DCC) && !defined(CONFIG_BAUDRATE) +#define CONFIG_BAUDRATE 115200 +#endif static int init_baudrate (void) { char tmp[64]; /* long enough for environment variables */ -- cgit v1.1