summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/adi_gpio2.c440
-rw-r--r--drivers/net/bfin_mac.c2
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial_bfin.c411
-rw-r--r--drivers/spi/bfin_spi.c105
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/bfin_wdt.c26
8 files changed, 883 insertions, 104 deletions
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 830e8e691a..f77c1ec1ef 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -48,6 +48,7 @@ COBJS-$(CONFIG_DB8500_GPIO) += db8500_gpio.o
COBJS-$(CONFIG_BCM2835_GPIO) += bcm2835_gpio.o
COBJS-$(CONFIG_S3C2440_GPIO) += s3c2440_gpio.o
COBJS-$(CONFIG_XILINX_GPIO) += xilinx_gpio.o
+COBJS-$(CONFIG_ADI_GPIO2) += adi_gpio2.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/gpio/adi_gpio2.c b/drivers/gpio/adi_gpio2.c
new file mode 100644
index 0000000000..7a034eba12
--- /dev/null
+++ b/drivers/gpio/adi_gpio2.c
@@ -0,0 +1,440 @@
+/*
+ * ADI GPIO2 Abstraction Layer
+ * Support BF54x, BF60x and future processors.
+ *
+ * Copyright 2008-2013 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+
+static struct gpio_port_t * const gpio_array[] = {
+ (struct gpio_port_t *)PORTA_FER,
+ (struct gpio_port_t *)PORTB_FER,
+ (struct gpio_port_t *)PORTC_FER,
+ (struct gpio_port_t *)PORTD_FER,
+ (struct gpio_port_t *)PORTE_FER,
+ (struct gpio_port_t *)PORTF_FER,
+ (struct gpio_port_t *)PORTG_FER,
+#if defined(CONFIG_BF54x)
+ (struct gpio_port_t *)PORTH_FER,
+ (struct gpio_port_t *)PORTI_FER,
+ (struct gpio_port_t *)PORTJ_FER,
+#endif
+};
+
+#define RESOURCE_LABEL_SIZE 16
+
+static struct str_ident {
+ char name[RESOURCE_LABEL_SIZE];
+} str_ident[MAX_RESOURCES];
+
+static void gpio_error(unsigned gpio)
+{
+ printf("adi_gpio2: GPIO %d wasn't requested!\n", gpio);
+}
+
+static void set_label(unsigned short ident, const char *label)
+{
+ if (label) {
+ strncpy(str_ident[ident].name, label,
+ RESOURCE_LABEL_SIZE);
+ str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0;
+ }
+}
+
+static char *get_label(unsigned short ident)
+{
+ return *str_ident[ident].name ? str_ident[ident].name : "UNKNOWN";
+}
+
+static int cmp_label(unsigned short ident, const char *label)
+{
+ if (label == NULL)
+ printf("adi_gpio2: please provide none-null label\n");
+
+ if (label)
+ return strcmp(str_ident[ident].name, label);
+ else
+ return -EINVAL;
+}
+
+#define map_entry(m, i) reserved_##m##_map[gpio_bank(i)]
+#define is_reserved(m, i, e) (map_entry(m, i) & gpio_bit(i))
+#define reserve(m, i) (map_entry(m, i) |= gpio_bit(i))
+#define unreserve(m, i) (map_entry(m, i) &= ~gpio_bit(i))
+#define DECLARE_RESERVED_MAP(m, c) unsigned short reserved_##m##_map[c]
+
+static DECLARE_RESERVED_MAP(gpio, GPIO_BANK_NUM);
+static DECLARE_RESERVED_MAP(peri, gpio_bank(MAX_RESOURCES));
+
+inline int check_gpio(unsigned gpio)
+{
+#if defined(CONFIG_BF54x)
+ if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 ||
+ gpio == GPIO_PH14 || gpio == GPIO_PH15 ||
+ gpio == GPIO_PJ14 || gpio == GPIO_PJ15)
+ return -EINVAL;
+#endif
+ if (gpio >= MAX_GPIOS)
+ return -EINVAL;
+ return 0;
+}
+
+static void port_setup(unsigned gpio, unsigned short usage)
+{
+#if defined(CONFIG_BF54x)
+ if (usage == GPIO_USAGE)
+ gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio);
+ else
+ gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio);
+#else
+ if (usage == GPIO_USAGE)
+ gpio_array[gpio_bank(gpio)]->port_fer_clear = gpio_bit(gpio);
+ else
+ gpio_array[gpio_bank(gpio)]->port_fer_set = gpio_bit(gpio);
+#endif
+ SSYNC();
+}
+
+inline void portmux_setup(unsigned short per)
+{
+ u32 pmux;
+ u16 ident = P_IDENT(per);
+ u16 function = P_FUNCT2MUX(per);
+
+ pmux = gpio_array[gpio_bank(ident)]->port_mux;
+
+ pmux &= ~(0x3 << (2 * gpio_sub_n(ident)));
+ pmux |= (function & 0x3) << (2 * gpio_sub_n(ident));
+
+ gpio_array[gpio_bank(ident)]->port_mux = pmux;
+}
+
+inline u16 get_portmux(unsigned short per)
+{
+ u32 pmux;
+ u16 ident = P_IDENT(per);
+
+ pmux = gpio_array[gpio_bank(ident)]->port_mux;
+
+ return pmux >> (2 * gpio_sub_n(ident)) & 0x3;
+}
+
+unsigned short get_gpio_dir(unsigned gpio)
+{
+ return 0x01 &
+ (gpio_array[gpio_bank(gpio)]->dir_clear >> gpio_sub_n(gpio));
+}
+
+/***********************************************************
+*
+* FUNCTIONS: Peripheral Resource Allocation
+* and PortMux Setup
+*
+* INPUTS/OUTPUTS:
+* per Peripheral Identifier
+* label String
+*
+* DESCRIPTION: Peripheral Resource Allocation and Setup API
+**************************************************************/
+
+int peripheral_request(unsigned short per, const char *label)
+{
+ unsigned short ident = P_IDENT(per);
+
+ /*
+ * Don't cares are pins with only one dedicated function
+ */
+
+ if (per & P_DONTCARE)
+ return 0;
+
+ if (!(per & P_DEFINED))
+ return -ENODEV;
+
+ BUG_ON(ident >= MAX_RESOURCES);
+
+ /* If a pin can be muxed as either GPIO or peripheral, make
+ * sure it is not already a GPIO pin when we request it.
+ */
+ if (unlikely(!check_gpio(ident) && is_reserved(gpio, ident, 1))) {
+ printf("%s: Peripheral %d is already reserved as GPIO by %s!\n",
+ __func__, ident, get_label(ident));
+ return -EBUSY;
+ }
+
+ if (unlikely(is_reserved(peri, ident, 1))) {
+ /*
+ * Pin functions like AMC address strobes my
+ * be requested and used by several drivers
+ */
+
+ if (!((per & P_MAYSHARE) &&
+ get_portmux(per) == P_FUNCT2MUX(per))) {
+ /*
+ * Allow that the identical pin function can
+ * be requested from the same driver twice
+ */
+
+ if (cmp_label(ident, label) == 0)
+ goto anyway;
+
+ printf("%s: Peripheral %d function %d is already "
+ "reserved by %s!\n", __func__, ident,
+ P_FUNCT2MUX(per), get_label(ident));
+ return -EBUSY;
+ }
+ }
+
+ anyway:
+ reserve(peri, ident);
+
+ portmux_setup(per);
+ port_setup(ident, PERIPHERAL_USAGE);
+
+ set_label(ident, label);
+
+ return 0;
+}
+
+int peripheral_request_list(const unsigned short per[], const char *label)
+{
+ u16 cnt;
+ int ret;
+
+ for (cnt = 0; per[cnt] != 0; cnt++) {
+ ret = peripheral_request(per[cnt], label);
+
+ if (ret < 0) {
+ for (; cnt > 0; cnt--)
+ peripheral_free(per[cnt - 1]);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void peripheral_free(unsigned short per)
+{
+ unsigned short ident = P_IDENT(per);
+
+ if (per & P_DONTCARE)
+ return;
+
+ if (!(per & P_DEFINED))
+ return;
+
+ if (unlikely(!is_reserved(peri, ident, 0)))
+ return;
+
+ if (!(per & P_MAYSHARE))
+ port_setup(ident, GPIO_USAGE);
+
+ unreserve(peri, ident);
+
+ set_label(ident, "free");
+}
+
+void peripheral_free_list(const unsigned short per[])
+{
+ u16 cnt;
+ for (cnt = 0; per[cnt] != 0; cnt++)
+ peripheral_free(per[cnt]);
+}
+
+/***********************************************************
+*
+* FUNCTIONS: GPIO Driver
+*
+* INPUTS/OUTPUTS:
+* gpio PIO Number between 0 and MAX_GPIOS
+* label String
+*
+* DESCRIPTION: GPIO Driver API
+**************************************************************/
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ if (check_gpio(gpio) < 0)
+ return -EINVAL;
+
+ /*
+ * Allow that the identical GPIO can
+ * be requested from the same driver twice
+ * Do nothing and return -
+ */
+
+ if (cmp_label(gpio, label) == 0)
+ return 0;
+
+ if (unlikely(is_reserved(gpio, gpio, 1))) {
+ printf("adi_gpio2: GPIO %d is already reserved by %s!\n",
+ gpio, get_label(gpio));
+ return -EBUSY;
+ }
+ if (unlikely(is_reserved(peri, gpio, 1))) {
+ printf("adi_gpio2: GPIO %d is already reserved as Peripheral "
+ "by %s!\n", gpio, get_label(gpio));
+ return -EBUSY;
+ }
+
+ reserve(gpio, gpio);
+ set_label(gpio, label);
+
+ port_setup(gpio, GPIO_USAGE);
+
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ if (check_gpio(gpio) < 0)
+ return -1;
+
+ if (unlikely(!is_reserved(gpio, gpio, 0))) {
+ gpio_error(gpio);
+ return -1;
+ }
+
+ unreserve(gpio, gpio);
+
+ set_label(gpio, "free");
+
+ return 0;
+}
+
+#ifdef ADI_SPECIAL_GPIO_BANKS
+static DECLARE_RESERVED_MAP(special_gpio, gpio_bank(MAX_RESOURCES));
+
+int special_gpio_request(unsigned gpio, const char *label)
+{
+ /*
+ * Allow that the identical GPIO can
+ * be requested from the same driver twice
+ * Do nothing and return -
+ */
+
+ if (cmp_label(gpio, label) == 0)
+ return 0;
+
+ if (unlikely(is_reserved(special_gpio, gpio, 1))) {
+ printf("adi_gpio2: GPIO %d is already reserved by %s!\n",
+ gpio, get_label(gpio));
+ return -EBUSY;
+ }
+ if (unlikely(is_reserved(peri, gpio, 1))) {
+ printf("adi_gpio2: GPIO %d is already reserved as Peripheral "
+ "by %s!\n", gpio, get_label(gpio));
+
+ return -EBUSY;
+ }
+
+ reserve(special_gpio, gpio);
+ reserve(peri, gpio);
+
+ set_label(gpio, label);
+ port_setup(gpio, GPIO_USAGE);
+
+ return 0;
+}
+
+void special_gpio_free(unsigned gpio)
+{
+ if (unlikely(!is_reserved(special_gpio, gpio, 0))) {
+ gpio_error(gpio);
+ return;
+ }
+
+ reserve(special_gpio, gpio);
+ reserve(peri, gpio);
+ set_label(gpio, "free");
+}
+#endif
+
+static inline void __gpio_direction_input(unsigned gpio)
+{
+ gpio_array[gpio_bank(gpio)]->dir_clear = gpio_bit(gpio);
+#if defined(CONFIG_BF54x)
+ gpio_array[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
+#else
+ gpio_array[gpio_bank(gpio)]->inen_set = gpio_bit(gpio);
+#endif
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ unsigned long flags;
+
+ if (!is_reserved(gpio, gpio, 0)) {
+ gpio_error(gpio);
+ return -EINVAL;
+ }
+
+ local_irq_save(flags);
+ __gpio_direction_input(gpio);
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+int gpio_set_value(unsigned gpio, int arg)
+{
+ if (arg)
+ gpio_array[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
+ else
+ gpio_array[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
+
+ return 0;
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ unsigned long flags;
+
+ if (!is_reserved(gpio, gpio, 0)) {
+ gpio_error(gpio);
+ return -EINVAL;
+ }
+
+ local_irq_save(flags);
+
+#if defined(CONFIG_BF54x)
+ gpio_array[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
+#else
+ gpio_array[gpio_bank(gpio)]->inen_clear = gpio_bit(gpio);
+#endif
+ gpio_set_value(gpio, value);
+ gpio_array[gpio_bank(gpio)]->dir_set = gpio_bit(gpio);
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ return 1 & (gpio_array[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
+}
+
+void gpio_labels(void)
+{
+ int c, gpio;
+
+ for (c = 0; c < MAX_RESOURCES; c++) {
+ gpio = is_reserved(gpio, c, 1);
+ if (!check_gpio(c) && gpio)
+ printf("GPIO_%d:\t%s\tGPIO %s\n", c, get_label(c),
+ get_gpio_dir(c) ? "OUTPUT" : "INPUT");
+ else if (is_reserved(peri, c, 1))
+ printf("GPIO_%d:\t%s\tPeripheral\n", c, get_label(c));
+ else
+ continue;
+ }
+}
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index c63398ebf8..0ffd59d497 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -122,8 +122,6 @@ static int bfin_EMAC_send(struct eth_device *dev, void *packet, int length)
{
int i;
int result = 0;
- unsigned int *buf;
- buf = (unsigned int *)packet;
if (length <= 0) {
printf("Ethernet: bad packet size: %d\n", length);
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index fbc4e97e98..442b7ea0df 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -52,6 +52,7 @@ COBJS-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o
COBJS-$(CONFIG_SANDBOX_SERIAL) += sandbox.o
COBJS-$(CONFIG_SCIF_CONSOLE) += serial_sh.o
COBJS-$(CONFIG_ZYNQ_SERIAL) += serial_zynq.o
+COBJS-$(CONFIG_BFIN_SERIAL) += serial_bfin.o
ifndef CONFIG_SPL_BUILD
COBJS-$(CONFIG_USB_TTY) += usbtty.o
diff --git a/drivers/serial/serial_bfin.c b/drivers/serial/serial_bfin.c
new file mode 100644
index 0000000000..0443b8427a
--- /dev/null
+++ b/drivers/serial/serial_bfin.c
@@ -0,0 +1,411 @@
+/*
+ * U-boot - serial.c Blackfin Serial Driver
+ *
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ *
+ * Copyright (c) 2003 Bas Vermeulen <bas@buyways.nl>,
+ * BuyWays B.V. (www.buyways.nl)
+ *
+ * Based heavily on:
+ * blkfinserial.c: Serial driver for BlackFin DSP internal USRTs.
+ * Copyright(c) 2003 Metrowerks <mwaddel@metrowerks.com>
+ * Copyright(c) 2001 Tony Z. Kou <tonyko@arcturusnetworks.com>
+ * Copyright(c) 2001-2002 Arcturus Networks Inc. <www.arcturusnetworks.com>
+ *
+ * Based on code from 68328 version serial driver imlpementation which was:
+ * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu>
+ * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
+ * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org>
+ * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>
+ *
+ * (C) Copyright 2000-2004
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/* Anomaly notes:
+ * 05000086 - we don't support autobaud
+ * 05000099 - we only use DR bit, so losing others is not a problem
+ * 05000100 - we don't use the UART_IIR register
+ * 05000215 - we poll the uart (no dma/interrupts)
+ * 05000225 - no workaround possible, but this shouldnt cause errors ...
+ * 05000230 - we tweak the baud rate calculation slightly
+ * 05000231 - we always use 1 stop bit
+ * 05000309 - we always enable the uart before we modify it in anyway
+ * 05000350 - we always enable the uart regardless of boot mode
+ * 05000363 - we don't support break signals, so don't generate one
+ */
+
+#include <common.h>
+#include <post.h>
+#include <watchdog.h>
+#include <serial.h>
+#include <linux/compiler.h>
+#include <asm/blackfin.h>
+#include <asm/serial.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_UART_CONSOLE
+
+#ifdef CONFIG_DEBUG_SERIAL
+static uart_lsr_t cached_lsr[256];
+static uart_lsr_t cached_rbr[256];
+static size_t cache_count;
+
+/* The LSR is read-to-clear on some parts, so we have to make sure status
+ * bits aren't inadvertently lost when doing various tests. This also
+ * works around anomaly 05000099 at the same time by keeping a cumulative
+ * tally of all the status bits.
+ */
+static uart_lsr_t uart_lsr_save;
+static uart_lsr_t uart_lsr_read(uint32_t uart_base)
+{
+ uart_lsr_t lsr = _lsr_read(pUART);
+ uart_lsr_save |= (lsr & (OE|PE|FE|BI));
+ return lsr | uart_lsr_save;
+}
+/* Just do the clear for everyone since it can't hurt. */
+static void uart_lsr_clear(uint32_t uart_base)
+{
+ uart_lsr_save = 0;
+ _lsr_write(pUART, -1);
+}
+#else
+/* When debugging is disabled, we only care about the DR bit, so if other
+ * bits get set/cleared, we don't really care since we don't read them
+ * anyways (and thus anomaly 05000099 is irrelevant).
+ */
+static inline uart_lsr_t uart_lsr_read(uint32_t uart_base)
+{
+ return _lsr_read(pUART);
+}
+static void uart_lsr_clear(uint32_t uart_base)
+{
+ _lsr_write(pUART, -1);
+}
+#endif
+
+static void uart_putc(uint32_t uart_base, const char c)
+{
+ /* send a \r for compatibility */
+ if (c == '\n')
+ serial_putc('\r');
+
+ WATCHDOG_RESET();
+
+ /* wait for the hardware fifo to clear up */
+ while (!(uart_lsr_read(uart_base) & THRE))
+ continue;
+
+ /* queue the character for transmission */
+ bfin_write(&pUART->thr, c);
+ SSYNC();
+
+ WATCHDOG_RESET();
+}
+
+static int uart_tstc(uint32_t uart_base)
+{
+ WATCHDOG_RESET();
+ return (uart_lsr_read(uart_base) & DR) ? 1 : 0;
+}
+
+static int uart_getc(uint32_t uart_base)
+{
+ uint16_t uart_rbr_val;
+
+ /* wait for data ! */
+ while (!uart_tstc(uart_base))
+ continue;
+
+ /* grab the new byte */
+ uart_rbr_val = bfin_read(&pUART->rbr);
+
+#ifdef CONFIG_DEBUG_SERIAL
+ /* grab & clear the LSR */
+ uart_lsr_t uart_lsr_val = uart_lsr_read(uart_base);
+
+ cached_lsr[cache_count] = uart_lsr_val;
+ cached_rbr[cache_count] = uart_rbr_val;
+ cache_count = (cache_count + 1) % ARRAY_SIZE(cached_lsr);
+
+ if (uart_lsr_val & (OE|PE|FE|BI)) {
+ printf("\n[SERIAL ERROR]\n");
+ do {
+ --cache_count;
+ printf("\t%3zu: RBR=0x%02x LSR=0x%02x\n", cache_count,
+ cached_rbr[cache_count], cached_lsr[cache_count]);
+ } while (cache_count > 0);
+ return -1;
+ }
+#endif
+ uart_lsr_clear(uart_base);
+
+ return uart_rbr_val;
+}
+
+#if CONFIG_POST & CONFIG_SYS_POST_UART
+# define LOOP(x) x
+#else
+# define LOOP(x)
+#endif
+
+#if BFIN_UART_HW_VER < 4
+
+LOOP(
+static void uart_loop(uint32_t uart_base, int state)
+{
+ u16 mcr;
+
+ /* Drain the TX fifo first so bytes don't come back */
+ while (!(uart_lsr_read(uart_base) & TEMT))
+ continue;
+
+ mcr = bfin_read(&pUART->mcr);
+ if (state)
+ mcr |= LOOP_ENA | MRTS;
+ else
+ mcr &= ~(LOOP_ENA | MRTS);
+ bfin_write(&pUART->mcr, mcr);
+}
+)
+
+#else
+
+LOOP(
+static void uart_loop(uint32_t uart_base, int state)
+{
+ u32 control;
+
+ /* Drain the TX fifo first so bytes don't come back */
+ while (!(uart_lsr_read(uart_base) & TEMT))
+ continue;
+
+ control = bfin_read(&pUART->control);
+ if (state)
+ control |= LOOP_ENA | MRTS;
+ else
+ control &= ~(LOOP_ENA | MRTS);
+ bfin_write(&pUART->control, control);
+}
+)
+
+#endif
+
+static inline void __serial_set_baud(uint32_t uart_base, uint32_t baud)
+{
+#ifdef CONFIG_DEBUG_EARLY_SERIAL
+ serial_early_set_baud(uart_base, baud);
+#else
+ uint16_t divisor = (get_uart_clk() + (baud * 8)) / (baud * 16)
+ - ANOMALY_05000230;
+
+ /* Program the divisor to get the baud rate we want */
+ serial_set_divisor(uart_base, divisor);
+#endif
+}
+
+static void uart_puts(uint32_t uart_base, const char *s)
+{
+ while (*s)
+ uart_putc(uart_base, *s++);
+}
+
+#define DECL_BFIN_UART(n) \
+static int uart##n##_init(void) \
+{ \
+ const unsigned short pins[] = { _P_UART(n, RX), _P_UART(n, TX), 0, }; \
+ peripheral_request_list(pins, "bfin-uart"); \
+ uart_init(MMR_UART(n)); \
+ __serial_set_baud(MMR_UART(n), gd->baudrate); \
+ uart_lsr_clear(MMR_UART(n)); \
+ return 0; \
+} \
+\
+static int uart##n##_uninit(void) \
+{ \
+ return serial_early_uninit(MMR_UART(n)); \
+} \
+\
+static void uart##n##_setbrg(void) \
+{ \
+ __serial_set_baud(MMR_UART(n), gd->baudrate); \
+} \
+\
+static int uart##n##_getc(void) \
+{ \
+ return uart_getc(MMR_UART(n)); \
+} \
+\
+static int uart##n##_tstc(void) \
+{ \
+ return uart_tstc(MMR_UART(n)); \
+} \
+\
+static void uart##n##_putc(const char c) \
+{ \
+ uart_putc(MMR_UART(n), c); \
+} \
+\
+static void uart##n##_puts(const char *s) \
+{ \
+ uart_puts(MMR_UART(n), s); \
+} \
+\
+LOOP( \
+static void uart##n##_loop(int state) \
+{ \
+ uart_loop(MMR_UART(n), state); \
+} \
+) \
+\
+struct serial_device bfin_serial##n##_device = { \
+ .name = "bfin_uart"#n, \
+ .start = uart##n##_init, \
+ .stop = uart##n##_uninit, \
+ .setbrg = uart##n##_setbrg, \
+ .getc = uart##n##_getc, \
+ .tstc = uart##n##_tstc, \
+ .putc = uart##n##_putc, \
+ .puts = uart##n##_puts, \
+ LOOP(.loop = uart##n##_loop) \
+};
+
+#ifdef UART0_RBR
+DECL_BFIN_UART(0)
+#endif
+#ifdef UART1_RBR
+DECL_BFIN_UART(1)
+#endif
+#ifdef UART2_RBR
+DECL_BFIN_UART(2)
+#endif
+#ifdef UART3_RBR
+DECL_BFIN_UART(3)
+#endif
+
+__weak struct serial_device *default_serial_console(void)
+{
+#if CONFIG_UART_CONSOLE == 0
+ return &bfin_serial0_device;
+#elif CONFIG_UART_CONSOLE == 1
+ return &bfin_serial1_device;
+#elif CONFIG_UART_CONSOLE == 2
+ return &bfin_serial2_device;
+#elif CONFIG_UART_CONSOLE == 3
+ return &bfin_serial3_device;
+#endif
+}
+
+void bfin_serial_initialize(void)
+{
+#ifdef UART0_RBR
+ serial_register(&bfin_serial0_device);
+#endif
+#ifdef UART1_RBR
+ serial_register(&bfin_serial1_device);
+#endif
+#ifdef UART2_RBR
+ serial_register(&bfin_serial2_device);
+#endif
+#ifdef UART3_RBR
+ serial_register(&bfin_serial3_device);
+#endif
+}
+
+#ifdef CONFIG_DEBUG_EARLY_SERIAL
+inline void uart_early_putc(uint32_t uart_base, const char c)
+{
+ /* send a \r for compatibility */
+ if (c == '\n')
+ uart_early_putc(uart_base, '\r');
+
+ /* wait for the hardware fifo to clear up */
+ while (!(_lsr_read(pUART) & THRE))
+ continue;
+
+ /* queue the character for transmission */
+ bfin_write(&pUART->thr, c);
+ SSYNC();
+}
+
+void uart_early_puts(const char *s)
+{
+ while (*s)
+ uart_early_putc(UART_BASE, *s++);
+}
+
+/* Symbol for our assembly to call. */
+void _serial_early_set_baud(uint32_t baud)
+{
+ serial_early_set_baud(UART_BASE, baud);
+}
+
+/* Symbol for our assembly to call. */
+void _serial_early_init(void)
+{
+ serial_early_init(UART_BASE);
+}
+#endif
+
+#elif defined(CONFIG_UART_MEM)
+
+char serial_logbuf[CONFIG_UART_MEM];
+char *serial_logbuf_head = serial_logbuf;
+
+int serial_mem_init(void)
+{
+ serial_logbuf_head = serial_logbuf;
+ return 0;
+}
+
+void serial_mem_setbrg(void)
+{
+}
+
+int serial_mem_tstc(void)
+{
+ return 0;
+}
+
+int serial_mem_getc(void)
+{
+ return 0;
+}
+
+void serial_mem_putc(const char c)
+{
+ *serial_logbuf_head = c;
+ if (++serial_logbuf_head == serial_logbuf + CONFIG_UART_MEM)
+ serial_logbuf_head = serial_logbuf;
+}
+
+void serial_mem_puts(const char *s)
+{
+ while (*s)
+ serial_putc(*s++);
+}
+
+struct serial_device bfin_serial_mem_device = {
+ .name = "bfin_uart_mem",
+ .start = serial_mem_init,
+ .setbrg = serial_mem_setbrg,
+ .getc = serial_mem_getc,
+ .tstc = serial_mem_tstc,
+ .putc = serial_mem_putc,
+ .puts = serial_mem_puts,
+};
+
+
+__weak struct serial_device *default_serial_console(void)
+{
+ return &bfin_serial_mem_device;
+}
+
+void bfin_serial_initialize(void)
+{
+ serial_register(&bfin_serial_mem_device);
+}
+#endif /* CONFIG_UART_MEM */
diff --git a/drivers/spi/bfin_spi.c b/drivers/spi/bfin_spi.c
index ab2e8b998b..a9a4d92c3e 100644
--- a/drivers/spi/bfin_spi.c
+++ b/drivers/spi/bfin_spi.c
@@ -13,7 +13,6 @@
#include <spi.h>
#include <asm/blackfin.h>
-#include <asm/dma.h>
#include <asm/gpio.h>
#include <asm/portmux.h>
#include <asm/mach-common/bits/spi.h>
@@ -242,109 +241,15 @@ void spi_release_bus(struct spi_slave *slave)
SSYNC();
}
-#ifdef __ADSPBF54x__
-# define SPI_DMA_BASE DMA4_NEXT_DESC_PTR
-#elif defined(__ADSPBF533__) || defined(__ADSPBF532__) || defined(__ADSPBF531__) || \
- defined(__ADSPBF538__) || defined(__ADSPBF539__)
-# define SPI_DMA_BASE DMA5_NEXT_DESC_PTR
-#elif defined(__ADSPBF561__)
-# define SPI_DMA_BASE DMA2_4_NEXT_DESC_PTR
-#elif defined(__ADSPBF537__) || defined(__ADSPBF536__) || defined(__ADSPBF534__) || \
- defined(__ADSPBF52x__) || defined(__ADSPBF51x__)
-# define SPI_DMA_BASE DMA7_NEXT_DESC_PTR
-# elif defined(__ADSPBF50x__)
-# define SPI_DMA_BASE DMA6_NEXT_DESC_PTR
-#else
-# error "Please provide SPI DMA channel defines"
-#endif
-static volatile struct dma_register *dma = (void *)SPI_DMA_BASE;
-
#ifndef CONFIG_BFIN_SPI_IDLE_VAL
# define CONFIG_BFIN_SPI_IDLE_VAL 0xff
#endif
-#ifdef CONFIG_BFIN_SPI_NO_DMA
-# define SPI_DMA 0
-#else
-# define SPI_DMA 1
-#endif
-
-static int spi_dma_xfer(struct bfin_spi_slave *bss, const u8 *tx, u8 *rx,
- uint bytes)
-{
- int ret = -1;
- u16 ndsize, spi_config, dma_config;
- struct dmasg dmasg[2];
- const u8 *buf;
-
- if (tx) {
- debug("%s: doing half duplex TX\n", __func__);
- buf = tx;
- spi_config = TDBR_DMA;
- dma_config = 0;
- } else {
- debug("%s: doing half duplex RX\n", __func__);
- buf = rx;
- spi_config = RDBR_DMA;
- dma_config = WNR;
- }
-
- dmasg[0].start_addr = (unsigned long)buf;
- dmasg[0].x_modify = 1;
- dma_config |= WDSIZE_8 | DMAEN;
- if (bytes <= 65536) {
- blackfin_dcache_flush_invalidate_range(buf, buf + bytes);
- ndsize = NDSIZE_5;
- dmasg[0].cfg = NDSIZE_0 | dma_config | FLOW_STOP | DI_EN;
- dmasg[0].x_count = bytes;
- } else {
- blackfin_dcache_flush_invalidate_range(buf, buf + 65536 - 1);
- ndsize = NDSIZE_7;
- dmasg[0].cfg = NDSIZE_5 | dma_config | FLOW_ARRAY | DMA2D;
- dmasg[0].x_count = 0; /* 2^16 */
- dmasg[0].y_count = bytes >> 16; /* count / 2^16 */
- dmasg[0].y_modify = 1;
- dmasg[1].start_addr = (unsigned long)(buf + (bytes & ~0xFFFF));
- dmasg[1].cfg = NDSIZE_0 | dma_config | FLOW_STOP | DI_EN;
- dmasg[1].x_count = bytes & 0xFFFF; /* count % 2^16 */
- dmasg[1].x_modify = 1;
- }
-
- dma->cfg = 0;
- dma->irq_status = DMA_DONE | DMA_ERR;
- dma->curr_desc_ptr = dmasg;
- write_SPI_CTL(bss, (bss->ctl & ~TDBR_CORE));
- write_SPI_STAT(bss, -1);
- SSYNC();
-
- write_SPI_TDBR(bss, CONFIG_BFIN_SPI_IDLE_VAL);
- dma->cfg = ndsize | FLOW_ARRAY | DMAEN;
- write_SPI_CTL(bss, (bss->ctl & ~TDBR_CORE) | spi_config);
- SSYNC();
-
- /*
- * We already invalidated the first 64k,
- * now while we just wait invalidate the remaining part.
- * Its not likely that the DMA is going to overtake
- */
- if (bytes > 65536)
- blackfin_dcache_flush_invalidate_range(buf + 65536, buf + bytes);
-
- while (!(dma->irq_status & DMA_DONE))
- if (ctrlc())
- goto done;
-
- dma->cfg = 0;
-
- ret = 0;
- done:
- write_SPI_CTL(bss, bss->ctl);
- return ret;
-}
-
static int spi_pio_xfer(struct bfin_spi_slave *bss, const u8 *tx, u8 *rx,
uint bytes)
{
+ /* discard invalid data and clear RXS */
+ read_SPI_RDBR(bss);
/* todo: take advantage of hardware fifos */
while (bytes--) {
u8 value = (tx ? *tx++ : CONFIG_BFIN_SPI_IDLE_VAL);
@@ -393,11 +298,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
if (flags & SPI_XFER_BEGIN)
spi_cs_activate(slave);
- /* TX DMA doesn't work quite right */
- if (SPI_DMA && bytes > 6 && (!tx /*|| !rx*/))
- ret = spi_dma_xfer(bss, tx, rx, bytes);
- else
- ret = spi_pio_xfer(bss, tx, rx, bytes);
+ ret = spi_pio_xfer(bss, tx, rx, bytes);
done:
if (flags & SPI_XFER_END)
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 13e7c37686..d57578df6c 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -33,6 +33,7 @@ endif
COBJS-$(CONFIG_TNETV107X_WATCHDOG) += tnetv107x_wdt.o
COBJS-$(CONFIG_S5P) += s5p_wdt.o
COBJS-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o
+COBJS-$(CONFIG_BFIN_WATCHDOG) += bfin_wdt.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
new file mode 100644
index 0000000000..7a6756b2e5
--- /dev/null
+++ b/drivers/watchdog/bfin_wdt.c
@@ -0,0 +1,26 @@
+/*
+ * watchdog.c - driver for Blackfin on-chip watchdog
+ *
+ * Copyright (c) 2007-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <asm/blackfin.h>
+#include <asm/mach-common/bits/watchdog.h>
+
+void hw_watchdog_reset(void)
+{
+ bfin_write_WDOG_STAT(0);
+}
+
+void hw_watchdog_init(void)
+{
+ bfin_write_WDOG_CTL(WDDIS);
+ SSYNC();
+ bfin_write_WDOG_CNT(CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000 * get_sclk());
+ hw_watchdog_reset();
+ bfin_write_WDOG_CTL(WDEN);
+}