summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/adi_gpio2.c440
-rw-r--r--drivers/gpio/xilinx_gpio.c364
-rw-r--r--drivers/i2c/omap24xx_i2c.c490
-rw-r--r--drivers/mmc/Makefile6
-rw-r--r--drivers/mmc/davinci_mmc.c5
-rw-r--r--drivers/mmc/fsl_esdhc.c5
-rw-r--r--drivers/mmc/ftsdc010_esdhc.c687
-rw-r--r--drivers/mmc/ftsdc010_mci.c377
-rw-r--r--drivers/mmc/mmc.c137
-rw-r--r--drivers/mmc/mv_sdhci.c3
-rw-r--r--drivers/mmc/omap_hsmmc.c20
-rw-r--r--drivers/mmc/s5p_sdhci.c3
-rw-r--r--drivers/mmc/spear_sdhci.c44
-rw-r--r--drivers/mmc/spl_mmc.c137
-rw-r--r--drivers/mtd/cfi_flash.c23
-rw-r--r--drivers/mtd/spi/spansion.c2
-rw-r--r--drivers/net/bfin_mac.c2
-rw-r--r--drivers/net/fec_mxc.c4
-rw-r--r--drivers/net/fm/Makefile1
-rw-r--r--drivers/net/fm/b4860.c6
-rw-r--r--drivers/net/fm/eth.c2
-rw-r--r--drivers/net/fm/fm.h2
-rw-r--r--drivers/net/fm/init.c31
-rw-r--r--drivers/net/fm/t4240.c14
-rw-r--r--drivers/net/phy/teranetics.c16
-rw-r--r--drivers/net/phy/vitesse.c67
-rw-r--r--drivers/net/smc911x.h4
-rw-r--r--drivers/power/palmas.c133
-rw-r--r--drivers/serial/Makefile2
-rw-r--r--drivers/serial/ns16550.c5
-rw-r--r--drivers/serial/serial.c2
-rw-r--r--drivers/serial/serial_bfin.c411
-rw-r--r--drivers/serial/serial_lpuart.c132
-rw-r--r--drivers/serial/serial_ns16550.c5
-rw-r--r--drivers/spi/bfin_spi.c105
-rw-r--r--drivers/usb/eth/smsc95xx.c1
-rw-r--r--drivers/usb/host/ehci-hcd.c75
-rw-r--r--drivers/usb/host/ohci-at91.c18
-rw-r--r--drivers/usb/musb/omap3.c4
-rw-r--r--drivers/video/mxsfb.c5
-rw-r--r--drivers/watchdog/Makefile3
-rw-r--r--drivers/watchdog/bfin_wdt.c26
43 files changed, 2560 insertions, 1261 deletions
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 9df1e26..f77c1ec 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -47,6 +47,8 @@ COBJS-$(CONFIG_OMAP_GPIO) += omap_gpio.o
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 0000000..7a034eb
--- /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/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c
new file mode 100644
index 0000000..37fb0c5
--- /dev/null
+++ b/drivers/gpio/xilinx_gpio.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2013 Xilinx, Michal Simek
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <linux/list.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+
+static LIST_HEAD(gpio_list);
+
+enum gpio_direction {
+ GPIO_DIRECTION_OUT = 0,
+ GPIO_DIRECTION_IN = 1,
+};
+
+/* Gpio simple map */
+struct gpio_regs {
+ u32 gpiodata;
+ u32 gpiodir;
+};
+
+#define GPIO_NAME_SIZE 10
+
+struct gpio_names {
+ char name[GPIO_NAME_SIZE];
+};
+
+/* Initialized, rxbd_current, rx_first_buf must be 0 after init */
+struct xilinx_gpio_priv {
+ struct gpio_regs *regs;
+ u32 gpio_min;
+ u32 gpio_max;
+ u32 gpiodata_store;
+ char name[GPIO_NAME_SIZE];
+ struct list_head list;
+ struct gpio_names *gpio_name;
+};
+
+/* Store number of allocated gpio pins */
+static u32 xilinx_gpio_max;
+
+/* Get associated gpio controller */
+static struct xilinx_gpio_priv *gpio_get_controller(unsigned gpio)
+{
+ struct list_head *entry;
+ struct xilinx_gpio_priv *priv = NULL;
+
+ list_for_each(entry, &gpio_list) {
+ priv = list_entry(entry, struct xilinx_gpio_priv, list);
+ if (gpio >= priv->gpio_min && gpio <= priv->gpio_max) {
+ debug("%s: reg: %x, min-max: %d-%d\n", __func__,
+ (u32)priv->regs, priv->gpio_min, priv->gpio_max);
+ return priv;
+ }
+ }
+ puts("!!!Can't get gpio controller!!!\n");
+ return NULL;
+}
+
+/* Get gpio pin name if used/setup */
+static char *get_name(unsigned gpio)
+{
+ u32 gpio_priv;
+ struct xilinx_gpio_priv *priv;
+
+ debug("%s\n", __func__);
+
+ priv = gpio_get_controller(gpio);
+ if (priv) {
+ gpio_priv = gpio - priv->gpio_min;
+
+ return *priv->gpio_name[gpio_priv].name ?
+ priv->gpio_name[gpio_priv].name : "UNKNOWN";
+ }
+ return "UNKNOWN";
+}
+
+/* Get output value */
+static int gpio_get_output_value(unsigned gpio)
+{
+ u32 val, gpio_priv;
+ struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);
+
+ if (priv) {
+ gpio_priv = gpio - priv->gpio_min;
+ val = !!(priv->gpiodata_store & (1 << gpio_priv));
+ debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__,
+ (u32)priv->regs, gpio_priv, val);
+
+ return val;
+ }
+ return -1;
+}
+
+/* Get input value */
+static int gpio_get_input_value(unsigned gpio)
+{
+ u32 val, gpio_priv;
+ struct gpio_regs *regs;
+ struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);
+
+ if (priv) {
+ regs = priv->regs;
+ gpio_priv = gpio - priv->gpio_min;
+ val = readl(&regs->gpiodata);
+ val = !!(val & (1 << gpio_priv));
+ debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__,
+ (u32)priv->regs, gpio_priv, val);
+
+ return val;
+ }
+ return -1;
+}
+
+/* Set gpio direction */
+static int gpio_set_direction(unsigned gpio, enum gpio_direction direction)
+{
+ u32 val, gpio_priv;
+ struct gpio_regs *regs;
+ struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);
+
+ if (priv) {
+ regs = priv->regs;
+ val = readl(&regs->gpiodir);
+
+ gpio_priv = gpio - priv->gpio_min;
+ if (direction == GPIO_DIRECTION_OUT)
+ val &= ~(1 << gpio_priv);
+ else
+ val |= 1 << gpio_priv;
+
+ writel(val, &regs->gpiodir);
+ debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__,
+ (u32)priv->regs, gpio_priv, val);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+/* Get gpio direction */
+static int gpio_get_direction(unsigned gpio)
+{
+ u32 val, gpio_priv;
+ struct gpio_regs *regs;
+ struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);
+
+ if (priv) {
+ regs = priv->regs;
+ gpio_priv = gpio - priv->gpio_min;
+ val = readl(&regs->gpiodir);
+ val = !!(val & (1 << gpio_priv));
+ debug("%s: reg: %x, gpio_no: %d, dir: %d\n", __func__,
+ (u32)priv->regs, gpio_priv, val);
+
+ return val;
+ }
+
+ return -1;
+}
+
+/*
+ * Get input value
+ * for example gpio setup to output only can't get input value
+ * which is breaking gpio toggle command
+ */
+int gpio_get_value(unsigned gpio)
+{
+ u32 val;
+
+ if (gpio_get_direction(gpio) == GPIO_DIRECTION_OUT)
+ val = gpio_get_output_value(gpio);
+ else
+ val = gpio_get_input_value(gpio);
+
+ return val;
+}
+
+/* Set output value */
+static int gpio_set_output_value(unsigned gpio, int value)
+{
+ u32 val, gpio_priv;
+ struct gpio_regs *regs;
+ struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);
+
+ if (priv) {
+ regs = priv->regs;
+ gpio_priv = gpio - priv->gpio_min;
+ val = priv->gpiodata_store;
+ if (value)
+ val |= 1 << gpio_priv;
+ else
+ val &= ~(1 << gpio_priv);
+
+ writel(val, &regs->gpiodata);
+ debug("%s: reg: %x, gpio_no: %d, output_val: %d\n", __func__,
+ (u32)priv->regs, gpio_priv, val);
+ priv->gpiodata_store = val;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+int gpio_set_value(unsigned gpio, int value)
+{
+ if (gpio_get_direction(gpio) == GPIO_DIRECTION_OUT)
+ return gpio_set_output_value(gpio, value);
+
+ return -1;
+}
+
+/* Set GPIO as input */
+int gpio_direction_input(unsigned gpio)
+{
+ debug("%s\n", __func__);
+ return gpio_set_direction(gpio, GPIO_DIRECTION_IN);
+}
+
+/* Setup GPIO as output and set output value */
+int gpio_direction_output(unsigned gpio, int value)
+{
+ int ret = gpio_set_direction(gpio, GPIO_DIRECTION_OUT);
+
+ debug("%s\n", __func__);
+
+ if (ret < 0)
+ return ret;
+
+ return gpio_set_output_value(gpio, value);
+}
+
+/* Show gpio status */
+void gpio_info(void)
+{
+ unsigned gpio;
+
+ struct list_head *entry;
+ struct xilinx_gpio_priv *priv = NULL;
+
+ list_for_each(entry, &gpio_list) {
+ priv = list_entry(entry, struct xilinx_gpio_priv, list);
+ printf("\n%s: %s/%x (%d-%d)\n", __func__, priv->name,
+ (u32)priv->regs, priv->gpio_min, priv->gpio_max);
+
+ for (gpio = priv->gpio_min; gpio <= priv->gpio_max; gpio++) {
+ printf("GPIO_%d:\t%s is an ", gpio, get_name(gpio));
+ if (gpio_get_direction(gpio) == GPIO_DIRECTION_OUT)
+ printf("OUTPUT value = %d\n",
+ gpio_get_output_value(gpio));
+ else
+ printf("INPUT value = %d\n",
+ gpio_get_input_value(gpio));
+ }
+ }
+}
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ u32 gpio_priv;
+ struct xilinx_gpio_priv *priv;
+
+ if (gpio >= xilinx_gpio_max)
+ return -EINVAL;
+
+ priv = gpio_get_controller(gpio);
+ if (priv) {
+ gpio_priv = gpio - priv->gpio_min;
+
+ if (label != NULL) {
+ strncpy(priv->gpio_name[gpio_priv].name, label,
+ GPIO_NAME_SIZE);
+ priv->gpio_name[gpio_priv].name[GPIO_NAME_SIZE - 1] =
+ '\0';
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+int gpio_free(unsigned gpio)
+{
+ u32 gpio_priv;
+ struct xilinx_gpio_priv *priv;
+
+ if (gpio >= xilinx_gpio_max)
+ return -EINVAL;
+
+ priv = gpio_get_controller(gpio);
+ if (priv) {
+ gpio_priv = gpio - priv->gpio_min;
+ priv->gpio_name[gpio_priv].name[0] = '\0';
+
+ /* Do nothing here */
+ return 0;
+ }
+
+ return -1;
+}
+
+int gpio_alloc(u32 baseaddr, const char *name, u32 gpio_no)
+{
+ struct xilinx_gpio_priv *priv;
+
+ priv = calloc(1, sizeof(struct xilinx_gpio_priv));
+
+ /* Setup gpio name */
+ if (name != NULL) {
+ strncpy(priv->name, name, GPIO_NAME_SIZE);
+ priv->name[GPIO_NAME_SIZE - 1] = '\0';
+ }
+ priv->regs = (struct gpio_regs *)baseaddr;
+
+ priv->gpio_min = xilinx_gpio_max;
+ xilinx_gpio_max = priv->gpio_min + gpio_no;
+ priv->gpio_max = xilinx_gpio_max - 1;
+
+ priv->gpio_name = calloc(gpio_no, sizeof(struct gpio_names));
+
+ INIT_LIST_HEAD(&priv->list);
+ list_add_tail(&priv->list, &gpio_list);
+
+ printf("%s: Add %s (%d-%d)\n", __func__, name,
+ priv->gpio_min, priv->gpio_max);
+
+ /* Return the first gpio allocated for this device */
+ return priv->gpio_min;
+}
+
+/* Dual channel gpio is one IP with two independent channels */
+int gpio_alloc_dual(u32 baseaddr, const char *name, u32 gpio_no0, u32 gpio_no1)
+{
+ int ret;
+
+ ret = gpio_alloc(baseaddr, name, gpio_no0);
+ gpio_alloc(baseaddr + 8, strcat((char *)name, "_1"), gpio_no1);
+
+ /* Return the first gpio allocated for this device */
+ return ret;
+}
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 54e9b15..ef38d71 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -18,6 +18,20 @@
*
* Adapted for OMAP2420 I2C, r-woodruff2@ti.com
*
+ * Copyright (c) 2013 Lubomir Popov <lpopov@mm-sol.com>, MM Solutions
+ * New i2c_read, i2c_write and i2c_probe functions, tested on OMAP4
+ * (4430/60/70), OMAP5 (5430) and AM335X (3359); should work on older
+ * OMAPs and derivatives as well. The only anticipated exception would
+ * be the OMAP2420, which shall require driver modification.
+ * - Rewritten i2c_read to operate correctly with all types of chips
+ * (old function could not read consistent data from some I2C slaves).
+ * - Optimized i2c_write.
+ * - New i2c_probe, performs write access vs read. The old probe could
+ * hang the system under certain conditions (e.g. unconfigured pads).
+ * - The read/write/probe functions try to identify unconfigured bus.
+ * - Status functions now read irqstatus_raw as per TRM guidelines
+ * (except for OMAP243X and OMAP34XX).
+ * - Driver now supports up to I2C5 (OMAP5).
*/
#include <common.h>
@@ -31,8 +45,11 @@ DECLARE_GLOBAL_DATA_PTR;
#define I2C_TIMEOUT 1000
+/* Absolutely safe for status update at 100 kHz I2C: */
+#define I2C_WAIT 200
+
static int wait_for_bb(void);
-static u16 wait_for_pin(void);
+static u16 wait_for_event(void);
static void flush_fifo(void);
/*
@@ -137,10 +154,14 @@ void i2c_init(int speed, int slaveadd)
/* own address */
writew(slaveadd, &i2c_base->oa);
writew(I2C_CON_EN, &i2c_base->con);
-
- /* have to enable intrrupts or OMAP i2c module doesn't work */
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
+ /*
+ * Have to enable interrupts for OMAP2/3, these IPs don't have
+ * an 'irqstatus_raw' register and we shall have to poll 'stat'
+ */
writew(I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE |
- I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
+ I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie);
+#endif
udelay(1000);
flush_fifo();
writew(0xFFFF, &i2c_base->stat);
@@ -150,88 +171,6 @@ void i2c_init(int speed, int slaveadd)
bus_initialized[current_bus] = 1;
}
-static int i2c_read_byte(u8 devaddr, u16 regoffset, u8 alen, u8 *value)
-{
- int i2c_error = 0;
- u16 status;
- int i = 2 - alen;
- u8 tmpbuf[2] = {(regoffset) >> 8, regoffset & 0xff};
- u16 w;
-
- /* wait until bus not busy */
- if (wait_for_bb())
- return 1;
-
- /* one byte only */
- writew(alen, &i2c_base->cnt);
- /* set slave address */
- writew(devaddr, &i2c_base->sa);
- /* no stop bit needed here */
- writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
- I2C_CON_TRX, &i2c_base->con);
-
- /* send register offset */
- while (1) {
- status = wait_for_pin();
- if (status == 0 || status & I2C_STAT_NACK) {
- i2c_error = 1;
- goto read_exit;
- }
- if (status & I2C_STAT_XRDY) {
- w = tmpbuf[i++];
-#if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
- defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
- defined(CONFIG_OMAP54XX))
- w |= tmpbuf[i++] << 8;
-#endif
- writew(w, &i2c_base->data);
- writew(I2C_STAT_XRDY, &i2c_base->stat);
- }
- if (status & I2C_STAT_ARDY) {
- writew(I2C_STAT_ARDY, &i2c_base->stat);
- break;
- }
- }
-
- /* set slave address */
- writew(devaddr, &i2c_base->sa);
- /* read one byte from slave */
- writew(1, &i2c_base->cnt);
- /* need stop bit here */
- writew(I2C_CON_EN | I2C_CON_MST |
- I2C_CON_STT | I2C_CON_STP,
- &i2c_base->con);
-
- /* receive data */
- while (1) {
- status = wait_for_pin();
- if (status == 0 || status & I2C_STAT_NACK) {
- i2c_error = 1;
- goto read_exit;
- }
- if (status & I2C_STAT_RRDY) {
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
- defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
- defined(CONFIG_OMAP54XX)
- *value = readb(&i2c_base->data);
-#else
- *value = readw(&i2c_base->data);
-#endif
- writew(I2C_STAT_RRDY, &i2c_base->stat);
- }
- if (status & I2C_STAT_ARDY) {
- writew(I2C_STAT_ARDY, &i2c_base->stat);
- break;
- }
- }
-
-read_exit:
- flush_fifo();
- writew(0xFFFF, &i2c_base->stat);
- writew(0, &i2c_base->cnt);
- return i2c_error;
-}
-
static void flush_fifo(void)
{ u16 stat;
@@ -241,13 +180,7 @@ static void flush_fifo(void)
while (1) {
stat = readw(&i2c_base->stat);
if (stat == I2C_STAT_RRDY) {
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
- defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
- defined(CONFIG_OMAP54XX)
readb(&i2c_base->data);
-#else
- readw(&i2c_base->data);
-#endif
writew(I2C_STAT_RRDY, &i2c_base->stat);
udelay(1000);
} else
@@ -255,6 +188,10 @@ static void flush_fifo(void)
}
}
+/*
+ * i2c_probe: Use write access. Allows to identify addresses that are
+ * write-only (like the config register of dual-port EEPROMs)
+ */
int i2c_probe(uchar chip)
{
u16 status;
@@ -263,61 +200,81 @@ int i2c_probe(uchar chip)
if (chip == readw(&i2c_base->oa))
return res;
- /* wait until bus not busy */
+ /* Wait until bus is free */
if (wait_for_bb())
return res;
- /* try to read one byte */
- writew(1, &i2c_base->cnt);
- /* set slave address */
+ /* No data transfer, slave addr only */
+ writew(0, &i2c_base->cnt);
+ /* Set slave address */
writew(chip, &i2c_base->sa);
- /* stop bit needed here */
- writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con);
-
- while (1) {
- status = wait_for_pin();
- if (status == 0 || status & I2C_STAT_AL) {
- res = 1;
- goto probe_exit;
- }
- if (status & I2C_STAT_NACK) {
- res = 1;
- writew(0xff, &i2c_base->stat);
- writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con);
-
- if (wait_for_bb())
- res = 1;
-
- break;
- }
- if (status & I2C_STAT_ARDY) {
- writew(I2C_STAT_ARDY, &i2c_base->stat);
- break;
- }
- if (status & I2C_STAT_RRDY) {
- res = 0;
-#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
- defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
- defined(CONFIG_OMAP54XX)
- readb(&i2c_base->data);
-#else
- readw(&i2c_base->data);
-#endif
- writew(I2C_STAT_RRDY, &i2c_base->stat);
- }
+ /* Stop bit needed here */
+ writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
+ I2C_CON_STP, &i2c_base->con);
+
+ status = wait_for_event();
+
+ if ((status & ~I2C_STAT_XRDY) == 0 || (status & I2C_STAT_AL)) {
+ /*
+ * With current high-level command implementation, notifying
+ * the user shall flood the console with 127 messages. If
+ * silent exit is desired upon unconfigured bus, remove the
+ * following 'if' section:
+ */
+ if (status == I2C_STAT_XRDY)
+ printf("i2c_probe: pads on bus %d probably not configured (status=0x%x)\n",
+ current_bus, status);
+
+ goto pr_exit;
}
-probe_exit:
+ /* Check for ACK (!NAK) */
+ if (!(status & I2C_STAT_NACK)) {
+ res = 0; /* Device found */
+ udelay(I2C_WAIT); /* Required by AM335X in SPL */
+ /* Abort transfer (force idle state) */
+ writew(I2C_CON_MST | I2C_CON_TRX, &i2c_base->con); /* Reset */
+ udelay(1000);
+ writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_TRX |
+ I2C_CON_STP, &i2c_base->con); /* STP */
+ }
+pr_exit:
flush_fifo();
- /* don't allow any more data in... we don't want it. */
- writew(0, &i2c_base->cnt);
writew(0xFFFF, &i2c_base->stat);
+ writew(0, &i2c_base->cnt);
return res;
}
+/*
+ * i2c_read: Function now uses a single I2C read transaction with bulk transfer
+ * of the requested number of bytes (note that the 'i2c md' command
+ * limits this to 16 bytes anyway). If CONFIG_I2C_REPEATED_START is
+ * defined in the board config header, this transaction shall be with
+ * Repeated Start (Sr) between the address and data phases; otherwise
+ * Stop-Start (P-S) shall be used (some I2C chips do require a P-S).
+ * The address (reg offset) may be 0, 1 or 2 bytes long.
+ * Function now reads correctly from chips that return more than one
+ * byte of data per addressed register (like TI temperature sensors),
+ * or that do not need a register address at all (such as some clock
+ * distributors).
+ */
int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
- int i;
+ int i2c_error = 0;
+ u16 status;
+
+ if (alen < 0) {
+ puts("I2C read: addr len < 0\n");
+ return 1;
+ }
+ if (len < 0) {
+ puts("I2C read: data len < 0\n");
+ return 1;
+ }
+ if (buffer == NULL) {
+ puts("I2C read: NULL pointer passed\n");
+ return 1;
+ }
if (alen > 2) {
printf("I2C read: addr len %d not supported\n", alen);
@@ -329,24 +286,122 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
return 1;
}
- for (i = 0; i < len; i++) {
- if (i2c_read_byte(chip, addr + i, alen, &buffer[i])) {
- puts("I2C read: I/O error\n");
- i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
- return 1;
+ /* Wait until bus not busy */
+ if (wait_for_bb())
+ return 1;
+
+ /* Zero, one or two bytes reg address (offset) */
+ writew(alen, &i2c_base->cnt);
+ /* Set slave address */
+ writew(chip, &i2c_base->sa);
+
+ if (alen) {
+ /* Must write reg offset first */
+#ifdef CONFIG_I2C_REPEATED_START
+ /* No stop bit, use Repeated Start (Sr) */
+ writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
+ I2C_CON_TRX, &i2c_base->con);
+#else
+ /* Stop - Start (P-S) */
+ writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP |
+ I2C_CON_TRX, &i2c_base->con);
+#endif
+ /* Send register offset */
+ while (1) {
+ status = wait_for_event();
+ /* Try to identify bus that is not padconf'd for I2C */
+ if (status == I2C_STAT_XRDY) {
+ i2c_error = 2;
+ printf("i2c_read (addr phase): pads on bus %d probably not configured (status=0x%x)\n",
+ current_bus, status);
+ goto rd_exit;
+ }
+ if (status == 0 || status & I2C_STAT_NACK) {
+ i2c_error = 1;
+ printf("i2c_read: error waiting for addr ACK (status=0x%x)\n",
+ status);
+ goto rd_exit;
+ }
+ if (alen) {
+ if (status & I2C_STAT_XRDY) {
+ alen--;
+ /* Do we have to use byte access? */
+ writeb((addr >> (8 * alen)) & 0xff,
+ &i2c_base->data);
+ writew(I2C_STAT_XRDY, &i2c_base->stat);
+ }
+ }
+ if (status & I2C_STAT_ARDY) {
+ writew(I2C_STAT_ARDY, &i2c_base->stat);
+ break;
+ }
}
}
+ /* Set slave address */
+ writew(chip, &i2c_base->sa);
+ /* Read len bytes from slave */
+ writew(len, &i2c_base->cnt);
+ /* Need stop bit here */
+ writew(I2C_CON_EN | I2C_CON_MST |
+ I2C_CON_STT | I2C_CON_STP,
+ &i2c_base->con);
- return 0;
+ /* Receive data */
+ while (1) {
+ status = wait_for_event();
+ /*
+ * Try to identify bus that is not padconf'd for I2C. This
+ * state could be left over from previous transactions if
+ * the address phase is skipped due to alen=0.
+ */
+ if (status == I2C_STAT_XRDY) {
+ i2c_error = 2;
+ printf("i2c_read (data phase): pads on bus %d probably not configured (status=0x%x)\n",
+ current_bus, status);
+ goto rd_exit;
+ }
+ if (status == 0 || status & I2C_STAT_NACK) {
+ i2c_error = 1;
+ goto rd_exit;
+ }
+ if (status & I2C_STAT_RRDY) {
+ *buffer++ = readb(&i2c_base->data);
+ writew(I2C_STAT_RRDY, &i2c_base->stat);
+ }
+ if (status & I2C_STAT_ARDY) {
+ writew(I2C_STAT_ARDY, &i2c_base->stat);
+ break;
+ }
+ }
+
+rd_exit:
+ flush_fifo();
+ writew(0xFFFF, &i2c_base->stat);
+ writew(0, &i2c_base->cnt);
+ return i2c_error;
}
+/* i2c_write: Address (reg offset) may be 0, 1 or 2 bytes long. */
int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
{
int i;
u16 status;
int i2c_error = 0;
- u16 w;
- u8 tmpbuf[2] = {addr >> 8, addr & 0xff};
+
+ if (alen < 0) {
+ puts("I2C write: addr len < 0\n");
+ return 1;
+ }
+
+ if (len < 0) {
+ puts("I2C write: data len < 0\n");
+ return 1;
+ }
+
+ if (buffer == NULL) {
+ puts("I2C write: NULL pointer passed\n");
+ return 1;
+ }
if (alen > 2) {
printf("I2C write: addr len %d not supported\n", alen);
@@ -355,92 +410,137 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
if (addr + len > (1 << 16)) {
printf("I2C write: address 0x%x + 0x%x out of range\n",
- addr, len);
+ addr, len);
return 1;
}
- /* wait until bus not busy */
+ /* Wait until bus not busy */
if (wait_for_bb())
return 1;
- /* start address phase - will write regoffset + len bytes data */
- /* TODO consider case when !CONFIG_OMAP243X/34XX/44XX */
+ /* Start address phase - will write regoffset + len bytes data */
writew(alen + len, &i2c_base->cnt);
- /* set slave address */
+ /* Set slave address */
writew(chip, &i2c_base->sa);
- /* stop bit needed here */
+ /* Stop bit needed here */
writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
- I2C_CON_STP, &i2c_base->con);
-
- /* Send address and data */
- for (i = -alen; i < len; i++) {
- status = wait_for_pin();
-
+ I2C_CON_STP, &i2c_base->con);
+
+ while (alen) {
+ /* Must write reg offset (one or two bytes) */
+ status = wait_for_event();
+ /* Try to identify bus that is not padconf'd for I2C */
+ if (status == I2C_STAT_XRDY) {
+ i2c_error = 2;
+ printf("i2c_write: pads on bus %d probably not configured (status=0x%x)\n",
+ current_bus, status);
+ goto wr_exit;
+ }
if (status == 0 || status & I2C_STAT_NACK) {
i2c_error = 1;
- printf("i2c error waiting for data ACK (status=0x%x)\n",
- status);
- goto write_exit;
+ printf("i2c_write: error waiting for addr ACK (status=0x%x)\n",
+ status);
+ goto wr_exit;
}
-
if (status & I2C_STAT_XRDY) {
- w = (i < 0) ? tmpbuf[2+i] : buffer[i];
-#if !(defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
- defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX) || \
- defined(CONFIG_OMAP54XX))
- w |= ((++i < 0) ? tmpbuf[2+i] : buffer[i]) << 8;
-#endif
- writew(w, &i2c_base->data);
+ alen--;
+ writeb((addr >> (8 * alen)) & 0xff, &i2c_base->data);
+ writew(I2C_STAT_XRDY, &i2c_base->stat);
+ } else {
+ i2c_error = 1;
+ printf("i2c_write: bus not ready for addr Tx (status=0x%x)\n",
+ status);
+ goto wr_exit;
+ }
+ }
+ /* Address phase is over, now write data */
+ for (i = 0; i < len; i++) {
+ status = wait_for_event();
+ if (status == 0 || status & I2C_STAT_NACK) {
+ i2c_error = 1;
+ printf("i2c_write: error waiting for data ACK (status=0x%x)\n",
+ status);
+ goto wr_exit;
+ }
+ if (status & I2C_STAT_XRDY) {
+ writeb(buffer[i], &i2c_base->data);
writew(I2C_STAT_XRDY, &i2c_base->stat);
} else {
i2c_error = 1;
- printf("i2c bus not ready for Tx (i=%d)\n", i);
- goto write_exit;
+ printf("i2c_write: bus not ready for data Tx (i=%d)\n",
+ i);
+ goto wr_exit;
}
}
-write_exit:
+wr_exit:
flush_fifo();
writew(0xFFFF, &i2c_base->stat);
+ writew(0, &i2c_base->cnt);
return i2c_error;
}
+/*
+ * Wait for the bus to be free by checking the Bus Busy (BB)
+ * bit to become clear
+ */
static int wait_for_bb(void)
{
int timeout = I2C_TIMEOUT;
u16 stat;
writew(0xFFFF, &i2c_base->stat); /* clear current interrupts...*/
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
while ((stat = readw(&i2c_base->stat) & I2C_STAT_BB) && timeout--) {
+#else
+ /* Read RAW status */
+ while ((stat = readw(&i2c_base->irqstatus_raw) &
+ I2C_STAT_BB) && timeout--) {
+#endif
writew(stat, &i2c_base->stat);
- udelay(1000);
+ udelay(I2C_WAIT);
}
if (timeout <= 0) {
- printf("timed out in wait_for_bb: I2C_STAT=%x\n",
- readw(&i2c_base->stat));
+ printf("Timed out in wait_for_bb: status=%04x\n",
+ stat);
return 1;
}
writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/
return 0;
}
-static u16 wait_for_pin(void)
+/*
+ * Wait for the I2C controller to complete current action
+ * and update status
+ */
+static u16 wait_for_event(void)
{
u16 status;
int timeout = I2C_TIMEOUT;
do {
- udelay(1000);
+ udelay(I2C_WAIT);
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX)
status = readw(&i2c_base->stat);
+#else
+ /* Read RAW status */
+ status = readw(&i2c_base->irqstatus_raw);
+#endif
} while (!(status &
(I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
I2C_STAT_AL)) && timeout--);
if (timeout <= 0) {
- printf("timed out in wait_for_pin: I2C_STAT=%x\n",
- readw(&i2c_base->stat));
+ printf("Timed out in wait_for_event: status=%04x\n",
+ status);
+ /*
+ * If status is still 0 here, probably the bus pads have
+ * not been configured for I2C, and/or pull-ups are missing.
+ */
+ printf("Check if pads/pull-ups of bus %d are properly configured\n",
+ current_bus);
writew(0xFFFF, &i2c_base->stat);
status = 0;
}
@@ -450,28 +550,36 @@ static u16 wait_for_pin(void)
int i2c_set_bus_num(unsigned int bus)
{
- if ((bus < 0) || (bus >= I2C_BUS_MAX)) {
- printf("Bad bus: %d\n", bus);
+ if (bus >= I2C_BUS_MAX) {
+ printf("Bad bus: %x\n", bus);
return -1;
}
-#if I2C_BUS_MAX == 4
- if (bus == 3)
- i2c_base = (struct i2c *)I2C_BASE4;
- else
- if (bus == 2)
+ switch (bus) {
+ default:
+ bus = 0; /* Fall through */
+ case 0:
+ i2c_base = (struct i2c *)I2C_BASE1;
+ break;
+ case 1:
+ i2c_base = (struct i2c *)I2C_BASE2;
+ break;
+#if (I2C_BUS_MAX > 2)
+ case 2:
i2c_base = (struct i2c *)I2C_BASE3;
- else
+ break;
+#if (I2C_BUS_MAX > 3)
+ case 3:
+ i2c_base = (struct i2c *)I2C_BASE4;
+ break;
+#if (I2C_BUS_MAX > 4)
+ case 4:
+ i2c_base = (struct i2c *)I2C_BASE5;
+ break;
#endif
-#if I2C_BUS_MAX == 3
- if (bus == 2)
- i2c_base = (struct i2c *)I2C_BASE3;
- else
#endif
- if (bus == 1)
- i2c_base = (struct i2c *)I2C_BASE2;
- else
- i2c_base = (struct i2c *)I2C_BASE1;
+#endif
+ }
current_bus = bus;
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 7cd4281..24648a2 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -25,14 +25,11 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libmmc.o
-ifdef CONFIG_SPL_BUILD
-COBJS-$(CONFIG_SPL_MMC_SUPPORT) += spl_mmc.o
-endif
COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
-COBJS-$(CONFIG_FTSDC010) += ftsdc010_esdhc.o
+COBJS-$(CONFIG_FTSDC010) += ftsdc010_mci.o
COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
COBJS-$(CONFIG_MMC_SPI) += mmc_spi.o
@@ -46,6 +43,7 @@ COBJS-$(CONFIG_SDHCI) += sdhci.o
COBJS-$(CONFIG_BCM2835_SDHCI) += bcm2835_sdhci.o
COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o
+COBJS-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o
COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
COBJS-$(CONFIG_DWMMC) += dw_mmc.o
COBJS-$(CONFIG_EXYNOS_DWMMC) += exynos_dw_mmc.o
diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c
index e2379e3..5aa2184 100644
--- a/drivers/mmc/davinci_mmc.c
+++ b/drivers/mmc/davinci_mmc.c
@@ -285,8 +285,11 @@ dmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
*/
if (bytes_left > fifo_bytes)
dmmc_wait_fifo_status(regs, 0x4a);
- else if (bytes_left == fifo_bytes)
+ else if (bytes_left == fifo_bytes) {
dmmc_wait_fifo_status(regs, 0x40);
+ if (cmd->cmdidx == MMC_CMD_SEND_EXT_CSD)
+ udelay(600);
+ }
for (i = 0; bytes_left && (i < fifo_words); i++) {
cmddata = get_val(&regs->mmcdrr);
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index e945c0a..861f4b9 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -178,7 +178,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data)
int timeout;
struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv;
struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base;
-#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO
+#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO
uint wml_value;
wml_value = data->blocksize/4;
@@ -601,8 +601,7 @@ int fsl_esdhc_mmc_init(bd_t *bis)
{
struct fsl_esdhc_cfg *cfg;
- cfg = malloc(sizeof(struct fsl_esdhc_cfg));
- memset(cfg, 0, sizeof(struct fsl_esdhc_cfg));
+ cfg = calloc(sizeof(struct fsl_esdhc_cfg), 1);
cfg->esdhc_base = CONFIG_SYS_FSL_ESDHC_ADDR;
cfg->sdhc_clk = gd->arch.sdhc_clk;
return fsl_esdhc_initialize(bis, cfg);
diff --git a/drivers/mmc/ftsdc010_esdhc.c b/drivers/mmc/ftsdc010_esdhc.c
deleted file mode 100644
index 42f0e0c..0000000
--- a/drivers/mmc/ftsdc010_esdhc.c
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * Copyright (C) 2011 Andes Technology Corporation
- * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * 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
- */
-
-#include <config.h>
-#include <common.h>
-#include <mmc.h>
-
-#include <asm/io.h>
-#include <faraday/ftsdc010.h>
-
-/*
- * supported mmc hosts
- * setting the number CONFIG_FTSDC010_NUMBER in your configuration file.
- */
-static struct mmc ftsdc010_dev[CONFIG_FTSDC010_NUMBER];
-static struct mmc_host ftsdc010_host[CONFIG_FTSDC010_NUMBER];
-
-static struct ftsdc010_mmc *ftsdc010_get_base_mmc(int dev_index)
-{
- return (struct ftsdc010_mmc *)CONFIG_FTSDC010_BASE + dev_index;
-}
-
-#ifdef DEBUG
-static void ftsdc010_dump_reg(struct mmc_host *host)
-{
- debug("cmd: %08x\n", readl(&host->reg->cmd));
- debug("argu: %08x\n", readl(&host->reg->argu));
- debug("rsp0: %08x\n", readl(&host->reg->rsp0));
- debug("rsp1: %08x\n", readl(&host->reg->rsp1));
- debug("rsp2: %08x\n", readl(&host->reg->rsp2));
- debug("rsp3: %08x\n", readl(&host->reg->rsp3));
- debug("rsp_cmd: %08x\n", readl(&host->reg->rsp_cmd));
- debug("dcr: %08x\n", readl(&host->reg->dcr));
- debug("dtr: %08x\n", readl(&host->reg->dtr));
- debug("dlr: %08x\n", readl(&host->reg->dlr));
- debug("status: %08x\n", readl(&host->reg->status));
- debug("clr: %08x\n", readl(&host->reg->clr));
- debug("int_mask: %08x\n", readl(&host->reg->int_mask));
- debug("pcr: %08x\n", readl(&host->reg->pcr));
- debug("ccr: %08x\n", readl(&host->reg->ccr));
- debug("bwr: %08x\n", readl(&host->reg->bwr));
- debug("dwr: %08x\n", readl(&host->reg->dwr));
- debug("feature: %08x\n", readl(&host->reg->feature));
- debug("rev: %08x\n", readl(&host->reg->rev));
-}
-#endif
-
-static unsigned int enable_imask(struct ftsdc010_mmc *reg, unsigned int imask)
-{
- unsigned int newmask;
-
- newmask = readl(&reg->int_mask);
- newmask |= imask;
-
- writel(newmask, &reg->int_mask);
-
- return newmask;
-}
-
-static void ftsdc010_pio_read(struct mmc_host *host, char *buf, unsigned int size)
-{
- unsigned int fifo;
- unsigned int fifo_words;
- unsigned int *ptr;
- unsigned int status;
- unsigned int retry = 0;
-
- /* get_data_buffer */
- ptr = (unsigned int *)buf;
-
- while (size) {
- status = readl(&host->reg->status);
- debug("%s: size: %08x\n", __func__, size);
-
- if (status & FTSDC010_STATUS_FIFO_ORUN) {
-
- debug("%s: FIFO OVERRUN: sta: %08x\n",
- __func__, status);
-
- fifo = host->fifo_len > size ?
- size : host->fifo_len;
-
- size -= fifo;
-
- fifo_words = fifo >> 2;
-
- while (fifo_words--)
- *ptr++ = readl(&host->reg->dwr);
-
- /*
- * for adding some delays for SD card to put
- * data into FIFO again
- */
- udelay(4*FTSDC010_DELAY_UNIT);
-
-#ifdef CONFIG_FTSDC010_SDIO
- /* sdio allow non-power-of-2 blksz */
- if (fifo & 3) {
- unsigned int n = fifo & 3;
- unsigned int data = readl(&host->reg->dwr);
-
- unsigned char *p = (unsigned char *)ptr;
-
- while (n--) {
- *p++ = data;
- data >>= 8;
- }
- }
-#endif
- } else {
- udelay(1);
- if (++retry >= FTSDC010_PIO_RETRY) {
- debug("%s: PIO_RETRY timeout\n", __func__);
- return;
- }
- }
- }
-}
-
-static void ftsdc010_pio_write(struct mmc_host *host, const char *buf,
- unsigned int size)
-{
- unsigned int fifo;
- unsigned int *ptr;
- unsigned int status;
- unsigned int retry = 0;
-
- /* get data buffer */
- ptr = (unsigned int *)buf;
-
- while (size) {
- status = readl(&host->reg->status);
-
- if (status & FTSDC010_STATUS_FIFO_URUN) {
- fifo = host->fifo_len > size ?
- size : host->fifo_len;
-
- size -= fifo;
-
- fifo = (fifo + 3) >> 2;
-
- while (fifo--) {
- writel(*ptr, &host->reg->dwr);
- ptr++;
- }
- } else {
- udelay(1);
- if (++retry >= FTSDC010_PIO_RETRY) {
- debug("%s: PIO_RETRY timeout\n", __func__);
- return;
- }
- }
- }
-}
-
-static int ftsdc010_check_rsp(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int sta, clear;
-
- sta = readl(&host->reg->status);
- debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
-
- /* check RSP TIMEOUT or FAIL */
- if (sta & FTSDC010_STATUS_RSP_TIMEOUT) {
- /* RSP TIMEOUT */
- debug("%s: RSP timeout: sta: %08x\n", __func__, sta);
-
- clear |= FTSDC010_CLR_RSP_TIMEOUT;
- writel(clear, &host->reg->clr);
-
- return TIMEOUT;
- } else if (sta & FTSDC010_STATUS_RSP_CRC_FAIL) {
- /* clear response fail bit */
- debug("%s: RSP CRC FAIL: sta: %08x\n", __func__, sta);
-
- clear |= FTSDC010_CLR_RSP_CRC_FAIL;
- writel(clear, &host->reg->clr);
-
- return COMM_ERR;
- } else if (sta & FTSDC010_STATUS_RSP_CRC_OK) {
-
- /* clear response CRC OK bit */
- clear |= FTSDC010_CLR_RSP_CRC_OK;
- }
-
- writel(clear, &host->reg->clr);
- return 0;
-}
-
-static int ftsdc010_check_data(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int sta, clear;
-
- sta = readl(&host->reg->status);
- debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
-
- /* check DATA TIMEOUT or FAIL */
- if (data) {
-
- /* Transfer Complete */
- if (sta & FTSDC010_STATUS_DATA_END)
- clear |= FTSDC010_STATUS_DATA_END;
-
- /* Data CRC_OK */
- if (sta & FTSDC010_STATUS_DATA_CRC_OK)
- clear |= FTSDC010_STATUS_DATA_CRC_OK;
-
- /* DATA TIMEOUT or DATA CRC FAIL */
- if (sta & FTSDC010_STATUS_DATA_TIMEOUT) {
- /* DATA TIMEOUT */
- debug("%s: DATA TIMEOUT: sta: %08x\n", __func__, sta);
-
- clear |= FTSDC010_STATUS_DATA_TIMEOUT;
- writel(clear, &host->reg->clr);
-
- return TIMEOUT;
- } else if (sta & FTSDC010_STATUS_DATA_CRC_FAIL) {
- /* DATA CRC FAIL */
- debug("%s: DATA CRC FAIL: sta: %08x\n", __func__, sta);
-
- clear |= FTSDC010_STATUS_DATA_CRC_FAIL;
- writel(clear, &host->reg->clr);
-
- return COMM_ERR;
- }
- writel(clear, &host->reg->clr);
- }
- return 0;
-}
-
-static int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- struct mmc_host *host = mmc->priv;
-
-#ifdef CONFIG_FTSDC010_SDIO
- unsigned int scon;
-#endif
- unsigned int ccon;
- unsigned int mask, tmpmask;
- unsigned int ret;
- unsigned int sta, i;
-
- ret = 0;
-
- if (data)
- mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
- else if (cmd->resp_type & MMC_RSP_PRESENT)
- mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
- else
- mask = FTSDC010_INT_MASK_CMD_SEND;
-
- /* write argu reg */
- debug("%s: argu: %08x\n", __func__, host->reg->argu);
- writel(cmd->cmdarg, &host->reg->argu);
-
- /* setup commnad */
- ccon = FTSDC010_CMD_IDX(cmd->cmdidx);
-
- /* setup command flags */
- ccon |= FTSDC010_CMD_CMD_EN;
-
- /*
- * This hardware didn't support specific commands for mapping
- * MMC_RSP_BUSY and MMC_RSP_OPCODE. Hence we don't deal with it.
- */
- if (cmd->resp_type & MMC_RSP_PRESENT) {
- ccon |= FTSDC010_CMD_NEED_RSP;
- mask |= FTSDC010_INT_MASK_RSP_CRC_OK |
- FTSDC010_INT_MASK_RSP_CRC_FAIL;
- }
-
- if (cmd->resp_type & MMC_RSP_136)
- ccon |= FTSDC010_CMD_LONG_RSP;
-
- /* In Linux driver, MMC_CMD_APP_CMD is checked in last_opcode */
- if (host->last_opcode == MMC_CMD_APP_CMD)
- ccon |= FTSDC010_CMD_APP_CMD;
-
-#ifdef CONFIG_FTSDC010_SDIO
- scon = readl(&host->reg->sdio_ctrl1);
- if (host->card_type == MMC_TYPE_SDIO)
- scon |= FTSDC010_SDIO_CTRL1_SDIO_ENABLE;
- else
- scon &= ~FTSDC010_SDIO_CTRL1_SDIO_ENABLE;
- writel(scon, &host->reg->sdio_ctrl1);
-#endif
-
- /* record last opcode for specifing the command type to hardware */
- host->last_opcode = cmd->cmdidx;
-
- /* write int_mask reg */
- tmpmask = readl(&host->reg->int_mask);
- tmpmask |= mask;
- writel(tmpmask, &host->reg->int_mask);
-
- /* write cmd reg */
- debug("%s: ccon: %08x\n", __func__, ccon);
- writel(ccon, &host->reg->cmd);
-
- /* check CMD_SEND */
- for (i = 0; i < FTSDC010_CMD_RETRY; i++) {
- /*
- * If we read status register too fast
- * will lead hardware error and the RSP_TIMEOUT
- * flag will be raised incorrectly.
- */
- udelay(16*FTSDC010_DELAY_UNIT);
- sta = readl(&host->reg->status);
-
- /* Command Complete */
- /*
- * Note:
- * Do not clear FTSDC010_CLR_CMD_SEND flag.
- * (by writing FTSDC010_CLR_CMD_SEND bit to clear register)
- * It will make the driver becomes very slow.
- * If the operation hasn't been finished, hardware will
- * clear this bit automatically.
- * In origin, the driver will clear this flag if there is
- * no data need to be read.
- */
- if (sta & FTSDC010_STATUS_CMD_SEND)
- break;
- }
-
- if (i > FTSDC010_CMD_RETRY) {
- printf("%s: send command timeout\n", __func__);
- return TIMEOUT;
- }
-
- /* check rsp status */
- ret = ftsdc010_check_rsp(mmc, cmd, data);
- if (ret)
- return ret;
-
- /* read response if we have RSP_OK */
- if (ccon & FTSDC010_CMD_LONG_RSP) {
- cmd->response[0] = readl(&host->reg->rsp3);
- cmd->response[1] = readl(&host->reg->rsp2);
- cmd->response[2] = readl(&host->reg->rsp1);
- cmd->response[3] = readl(&host->reg->rsp0);
- } else {
- cmd->response[0] = readl(&host->reg->rsp0);
- }
-
- /* read/write data */
- if (data && (data->flags & MMC_DATA_READ)) {
- ftsdc010_pio_read(host, data->dest,
- data->blocksize * data->blocks);
- } else if (data && (data->flags & MMC_DATA_WRITE)) {
- ftsdc010_pio_write(host, data->src,
- data->blocksize * data->blocks);
- }
-
- /* check data status */
- if (data) {
- ret = ftsdc010_check_data(mmc, cmd, data);
- if (ret)
- return ret;
- }
-
- udelay(FTSDC010_DELAY_UNIT);
- return ret;
-}
-
-static unsigned int cal_blksz(unsigned int blksz)
-{
- unsigned int blksztwo = 0;
-
- while (blksz >>= 1)
- blksztwo++;
-
- return blksztwo;
-}
-
-static int ftsdc010_setup_data(struct mmc *mmc, struct mmc_data *data)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int dcon, newmask;
-
- /* configure data transfer paramter */
- if (!data)
- return 0;
-
- if (((data->blocksize - 1) & data->blocksize) != 0) {
- printf("%s: can't do non-power-of 2 sized block transfers"
- " (blksz %d)\n", __func__, data->blocksize);
- return -1;
- }
-
- /*
- * We cannot deal with unaligned blocks with more than
- * one block being transfered.
- */
- if ((data->blocksize <= 2) && (data->blocks > 1)) {
- printf("%s: can't do non-word sized block transfers"
- " (blksz %d)\n", __func__, data->blocksize);
- return -1;
- }
-
- /* data length */
- dcon = data->blocksize * data->blocks;
- writel(dcon, &host->reg->dlr);
-
- /* write data control */
- dcon = cal_blksz(data->blocksize);
-
- /* add to IMASK register */
- newmask = (FTSDC010_STATUS_RSP_CRC_FAIL | FTSDC010_STATUS_DATA_TIMEOUT);
-
- /*
- * enable UNDERRUN will trigger interrupt immediatedly
- * So setup it when rsp is received successfully
- */
- if (data->flags & MMC_DATA_WRITE) {
- dcon |= FTSDC010_DCR_DATA_WRITE;
- } else {
- dcon &= ~FTSDC010_DCR_DATA_WRITE;
- newmask |= FTSDC010_STATUS_FIFO_ORUN;
- }
- enable_imask(host->reg, newmask);
-
-#ifdef CONFIG_FTSDC010_SDIO
- /* always reset fifo since last transfer may fail */
- dcon |= FTSDC010_DCR_FIFO_RST;
-
- if (data->blocks > 1)
- dcon |= FTSDC010_SDIO_CTRL1_SDIO_BLK_MODE;
-#endif
-
- /* enable data transfer which will be pended until cmd is send */
- dcon |= FTSDC010_DCR_DATA_EN;
- writel(dcon, &host->reg->dcr);
-
- return 0;
-}
-
-static int ftsdc010_send_request(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- int ret;
-
- if (data) {
- ret = ftsdc010_setup_data(mmc, data);
-
- if (ret) {
- printf("%s: setup data error\n", __func__);
- return -1;
- }
-
- if ((data->flags & MMC_DATA_BOTH_DIR) == MMC_DATA_BOTH_DIR) {
- printf("%s: data is both direction\n", __func__);
- return -1;
- }
- }
-
- /* Send command */
- ret = ftsdc010_send_cmd(mmc, cmd, data);
- return ret;
-}
-
-static int ftsdc010_card_detect(struct mmc *mmc)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int sta;
-
- sta = readl(&host->reg->status);
- debug("%s: card status: %08x\n", __func__, sta);
-
- return (sta & FTSDC010_STATUS_CARD_DETECT) ? 0 : 1;
-}
-
-static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
- struct mmc_data *data)
-{
- int ret;
-
- if (ftsdc010_card_detect(mmc) == 0) {
- printf("%s: no medium present\n", __func__);
- return -1;
- } else {
- ret = ftsdc010_send_request(mmc, cmd, data);
- return ret;
- }
-}
-
-static void ftsdc010_set_clk(struct mmc *mmc)
-{
- struct mmc_host *host = mmc->priv;
- unsigned char clk_div;
- unsigned int real_rate;
- unsigned int clock;
-
- debug("%s: mmc_set_clock: %x\n", __func__, mmc->clock);
- clock = readl(&host->reg->ccr);
-
- if (mmc->clock == 0) {
- real_rate = 0;
- clock |= FTSDC010_CCR_CLK_DIS;
- } else {
- debug("%s, mmc->clock: %08x, origin clock: %08x\n",
- __func__, mmc->clock, clock);
-
- for (clk_div = 0; clk_div <= 127; clk_div++) {
- real_rate = (CONFIG_SYS_CLK_FREQ / 2) /
- (2 * (clk_div + 1));
-
- if (real_rate <= mmc->clock)
- break;
- }
-
- debug("%s: computed real_rate: %x, clk_div: %x\n",
- __func__, real_rate, clk_div);
-
- if (clk_div > 127)
- debug("%s: no match clock rate, %x\n",
- __func__, mmc->clock);
-
- clock = (clock & ~FTSDC010_CCR_CLK_DIV(0x7f)) |
- FTSDC010_CCR_CLK_DIV(clk_div);
-
- clock &= ~FTSDC010_CCR_CLK_DIS;
- }
-
- debug("%s, set clock: %08x\n", __func__, clock);
- writel(clock, &host->reg->ccr);
-}
-
-static void ftsdc010_set_ios(struct mmc *mmc)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int power;
- unsigned long val;
- unsigned int bus_width;
-
- debug("%s: bus_width: %x, clock: %d\n",
- __func__, mmc->bus_width, mmc->clock);
-
- /* set pcr: power on */
- power = readl(&host->reg->pcr);
- power |= FTSDC010_PCR_POWER_ON;
- writel(power, &host->reg->pcr);
-
- if (mmc->clock)
- ftsdc010_set_clk(mmc);
-
- /* set bwr: bus width reg */
- bus_width = readl(&host->reg->bwr);
- bus_width &= ~(FTSDC010_BWR_WIDE_8_BUS | FTSDC010_BWR_WIDE_4_BUS |
- FTSDC010_BWR_SINGLE_BUS);
-
- if (mmc->bus_width == 8)
- bus_width |= FTSDC010_BWR_WIDE_8_BUS;
- else if (mmc->bus_width == 4)
- bus_width |= FTSDC010_BWR_WIDE_4_BUS;
- else
- bus_width |= FTSDC010_BWR_SINGLE_BUS;
-
- writel(bus_width, &host->reg->bwr);
-
- /* set fifo depth */
- val = readl(&host->reg->feature);
- host->fifo_len = FTSDC010_FEATURE_FIFO_DEPTH(val) * 4; /* 4 bytes */
-
- /* set data timeout register */
- val = -1;
- writel(val, &host->reg->dtr);
-}
-
-static void ftsdc010_reset(struct mmc_host *host)
-{
- unsigned int timeout;
- unsigned int sta;
-
- /* Do SDC_RST: Software reset for all register */
- writel(FTSDC010_CMD_SDC_RST, &host->reg->cmd);
-
- host->clock = 0;
-
- /* this hardware has no reset finish flag to read */
- /* wait 100ms maximum */
- timeout = 100;
-
- /* hw clears the bit when it's done */
- while (readl(&host->reg->dtr) != 0) {
- if (timeout == 0) {
- printf("%s: reset timeout error\n", __func__);
- return;
- }
- timeout--;
- udelay(10*FTSDC010_DELAY_UNIT);
- }
-
- sta = readl(&host->reg->status);
- if (sta & FTSDC010_STATUS_CARD_CHANGE)
- writel(FTSDC010_CLR_CARD_CHANGE, &host->reg->clr);
-}
-
-static int ftsdc010_core_init(struct mmc *mmc)
-{
- struct mmc_host *host = mmc->priv;
- unsigned int mask;
- unsigned int major, minor, revision;
-
- /* get hardware version */
- host->version = readl(&host->reg->rev);
-
- major = FTSDC010_REV_MAJOR(host->version);
- minor = FTSDC010_REV_MINOR(host->version);
- revision = FTSDC010_REV_REVISION(host->version);
-
- printf("ftsdc010 hardware ver: %d_%d_r%d\n", major, minor, revision);
-
- /* Interrupt MASK register init - mask all */
- writel(0x0, &host->reg->int_mask);
-
- mask = FTSDC010_INT_MASK_CMD_SEND |
- FTSDC010_INT_MASK_DATA_END |
- FTSDC010_INT_MASK_CARD_CHANGE;
-#ifdef CONFIG_FTSDC010_SDIO
- mask |= FTSDC010_INT_MASK_CP_READY |
- FTSDC010_INT_MASK_CP_BUF_READY |
- FTSDC010_INT_MASK_PLAIN_TEXT_READY |
- FTSDC010_INT_MASK_SDIO_IRPT;
-#endif
-
- writel(mask, &host->reg->int_mask);
-
- return 0;
-}
-
-int ftsdc010_mmc_init(int dev_index)
-{
- struct mmc *mmc;
- struct mmc_host *host;
-
- mmc = &ftsdc010_dev[dev_index];
-
- sprintf(mmc->name, "FTSDC010 SD/MMC");
- mmc->priv = &ftsdc010_host[dev_index];
- mmc->send_cmd = ftsdc010_request;
- mmc->set_ios = ftsdc010_set_ios;
- mmc->init = ftsdc010_core_init;
- mmc->getcd = NULL;
- mmc->getwp = NULL;
-
- mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
-
- mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
-
- mmc->f_min = CONFIG_SYS_CLK_FREQ / 2 / (2*128);
- mmc->f_max = CONFIG_SYS_CLK_FREQ / 2 / 2;
-
- ftsdc010_host[dev_index].clock = 0;
- ftsdc010_host[dev_index].reg = ftsdc010_get_base_mmc(dev_index);
- mmc_register(mmc);
-
- /* reset mmc */
- host = (struct mmc_host *)mmc->priv;
- ftsdc010_reset(host);
-
- return 0;
-}
diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
new file mode 100644
index 0000000..562b14a
--- /dev/null
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -0,0 +1,377 @@
+/*
+ * Faraday MMC/SD Host Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+#include <faraday/ftsdc010.h>
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
+#define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
+
+struct ftsdc010_chip {
+ void __iomem *regs;
+ uint32_t wprot; /* write protected (locked) */
+ uint32_t rate; /* actual SD clock in Hz */
+ uint32_t sclk; /* FTSDC010 source clock in Hz */
+ uint32_t fifo; /* fifo depth in bytes */
+ uint32_t acmd;
+};
+
+static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
+{
+ struct ftsdc010_chip *chip = mmc->priv;
+ struct ftsdc010_mmc __iomem *regs = chip->regs;
+ int ret = TIMEOUT;
+ uint32_t ts, st;
+ uint32_t cmd = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
+ uint32_t arg = mmc_cmd->cmdarg;
+ uint32_t flags = mmc_cmd->resp_type;
+
+ cmd |= FTSDC010_CMD_CMD_EN;
+
+ if (chip->acmd) {
+ cmd |= FTSDC010_CMD_APP_CMD;
+ chip->acmd = 0;
+ }
+
+ if (flags & MMC_RSP_PRESENT)
+ cmd |= FTSDC010_CMD_NEED_RSP;
+
+ if (flags & MMC_RSP_136)
+ cmd |= FTSDC010_CMD_LONG_RSP;
+
+ writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
+ &regs->clr);
+ writel(arg, &regs->argu);
+ writel(cmd, &regs->cmd);
+
+ if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
+ for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+ if (readl(&regs->status) & FTSDC010_STATUS_CMD_SEND) {
+ writel(FTSDC010_STATUS_CMD_SEND, &regs->clr);
+ ret = 0;
+ break;
+ }
+ }
+ } else {
+ st = 0;
+ for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+ st = readl(&regs->status);
+ writel(st & FTSDC010_STATUS_RSP_MASK, &regs->clr);
+ if (st & FTSDC010_STATUS_RSP_MASK)
+ break;
+ }
+ if (st & FTSDC010_STATUS_RSP_CRC_OK) {
+ if (flags & MMC_RSP_136) {
+ mmc_cmd->response[0] = readl(&regs->rsp3);
+ mmc_cmd->response[1] = readl(&regs->rsp2);
+ mmc_cmd->response[2] = readl(&regs->rsp1);
+ mmc_cmd->response[3] = readl(&regs->rsp0);
+ } else {
+ mmc_cmd->response[0] = readl(&regs->rsp0);
+ }
+ ret = 0;
+ } else {
+ debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
+ mmc_cmd->cmdidx, st);
+ }
+ }
+
+ if (ret) {
+ debug("ftsdc010: cmd timeout (op code=%d)\n",
+ mmc_cmd->cmdidx);
+ } else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
+ chip->acmd = 1;
+ }
+
+ return ret;
+}
+
+static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
+{
+ struct ftsdc010_chip *chip = mmc->priv;
+ struct ftsdc010_mmc __iomem *regs = chip->regs;
+ uint32_t div;
+
+ for (div = 0; div < 0x7f; ++div) {
+ if (rate >= chip->sclk / (2 * (div + 1)))
+ break;
+ }
+ chip->rate = chip->sclk / (2 * (div + 1));
+
+ writel(FTSDC010_CCR_CLK_DIV(div), &regs->ccr);
+
+ if (IS_SD(mmc)) {
+ setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_SD);
+
+ if (chip->rate > 25000000)
+ setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
+ else
+ clrbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
+ }
+}
+
+static inline int ftsdc010_is_ro(struct mmc *mmc)
+{
+ struct ftsdc010_chip *chip = mmc->priv;
+ const uint8_t *csd = (const uint8_t *)mmc->csd;
+
+ return chip->wprot || (csd[1] & 0x30);
+}
+
+static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
+{
+ int ret = TIMEOUT;
+ uint32_t st, ts;
+
+ for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+ st = readl(&regs->status);
+ if (!(st & mask))
+ continue;
+ writel(st & mask, &regs->clr);
+ ret = 0;
+ break;
+ }
+
+ if (ret)
+ debug("ftsdc010: wait st(0x%x) timeout\n", mask);
+
+ return ret;
+}
+
+/*
+ * u-boot mmc api
+ */
+
+static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data)
+{
+ int ret = UNUSABLE_ERR;
+ uint32_t len = 0;
+ struct ftsdc010_chip *chip = mmc->priv;
+ struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+ if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
+ printf("ftsdc010: the card is write protected!\n");
+ return ret;
+ }
+
+ if (data) {
+ uint32_t dcr;
+
+ len = data->blocksize * data->blocks;
+
+ /* 1. data disable + fifo reset */
+ writel(FTSDC010_DCR_FIFO_RST, &regs->dcr);
+
+ /* 2. clear status register */
+ writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
+ | FTSDC010_STATUS_FIFO_ORUN, &regs->clr);
+
+ /* 3. data timeout (1 sec) */
+ writel(chip->rate, &regs->dtr);
+
+ /* 4. data length (bytes) */
+ writel(len, &regs->dlr);
+
+ /* 5. data enable */
+ dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
+ if (data->flags & MMC_DATA_WRITE)
+ dcr |= FTSDC010_DCR_DATA_WRITE;
+ writel(dcr, &regs->dcr);
+ }
+
+ ret = ftsdc010_send_cmd(mmc, cmd);
+ if (ret) {
+ printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
+ return ret;
+ }
+
+ if (!data)
+ return ret;
+
+ if (data->flags & MMC_DATA_WRITE) {
+ const uint8_t *buf = (const uint8_t *)data->src;
+
+ while (len > 0) {
+ int wlen;
+
+ /* wait for tx ready */
+ ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
+ if (ret)
+ break;
+
+ /* write bytes to ftsdc010 */
+ for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
+ writel(*(uint32_t *)buf, &regs->dwr);
+ buf += 4;
+ wlen += 4;
+ }
+
+ len -= wlen;
+ }
+
+ } else {
+ uint8_t *buf = (uint8_t *)data->dest;
+
+ while (len > 0) {
+ int rlen;
+
+ /* wait for rx ready */
+ ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
+ if (ret)
+ break;
+
+ /* fetch bytes from ftsdc010 */
+ for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
+ *(uint32_t *)buf = readl(&regs->dwr);
+ buf += 4;
+ rlen += 4;
+ }
+
+ len -= rlen;
+ }
+
+ }
+
+ if (!ret) {
+ ret = ftsdc010_wait(regs,
+ FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
+ }
+
+ return ret;
+}
+
+static void ftsdc010_set_ios(struct mmc *mmc)
+{
+ struct ftsdc010_chip *chip = mmc->priv;
+ struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+ ftsdc010_clkset(mmc, mmc->clock);
+
+ clrbits_le32(&regs->bwr, FTSDC010_BWR_MODE_MASK);
+ switch (mmc->bus_width) {
+ case 4:
+ setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_4BIT);
+ break;
+ case 8:
+ setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_8BIT);
+ break;
+ default:
+ setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_1BIT);
+ break;
+ }
+}
+
+static int ftsdc010_init(struct mmc *mmc)
+{
+ struct ftsdc010_chip *chip = mmc->priv;
+ struct ftsdc010_mmc __iomem *regs = chip->regs;
+ uint32_t ts;
+
+ if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
+ return NO_CARD_ERR;
+
+ if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
+ printf("ftsdc010: write protected\n");
+ chip->wprot = 1;
+ }
+
+ chip->fifo = (readl(&regs->feature) & 0xff) << 2;
+
+ /* 1. chip reset */
+ writel(FTSDC010_CMD_SDC_RST, &regs->cmd);
+ for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
+ if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST)
+ continue;
+ break;
+ }
+ if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST) {
+ printf("ftsdc010: reset failed\n");
+ return UNUSABLE_ERR;
+ }
+
+ /* 2. enter low speed mode (400k card detection) */
+ ftsdc010_clkset(mmc, 400000);
+
+ /* 3. interrupt disabled */
+ writel(0, &regs->int_mask);
+
+ return 0;
+}
+
+int ftsdc010_mmc_init(int devid)
+{
+ struct mmc *mmc;
+ struct ftsdc010_chip *chip;
+ struct ftsdc010_mmc __iomem *regs;
+#ifdef CONFIG_FTSDC010_BASE_LIST
+ uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
+
+ if (devid < 0 || devid >= ARRAY_SIZE(base_list))
+ return -1;
+ regs = (void __iomem *)base_list[devid];
+#else
+ regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
+#endif
+
+ mmc = malloc(sizeof(struct mmc));
+ if (!mmc)
+ return -ENOMEM;
+ memset(mmc, 0, sizeof(struct mmc));
+
+ chip = malloc(sizeof(struct ftsdc010_chip));
+ if (!chip) {
+ free(mmc);
+ return -ENOMEM;
+ }
+ memset(chip, 0, sizeof(struct ftsdc010_chip));
+
+ chip->regs = regs;
+ mmc->priv = chip;
+
+ sprintf(mmc->name, "ftsdc010");
+ mmc->send_cmd = ftsdc010_request;
+ mmc->set_ios = ftsdc010_set_ios;
+ mmc->init = ftsdc010_init;
+
+ mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
+ switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
+ case FTSDC010_BWR_CAPS_4BIT:
+ mmc->host_caps |= MMC_MODE_4BIT;
+ break;
+ case FTSDC010_BWR_CAPS_8BIT:
+ mmc->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
+ break;
+ default:
+ break;
+ }
+
+#ifdef CONFIG_SYS_CLK_FREQ
+ chip->sclk = CONFIG_SYS_CLK_FREQ;
+#else
+ chip->sclk = clk_get_rate("SDC");
+#endif
+
+ mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+ mmc->f_max = chip->sclk / 2;
+ mmc->f_min = chip->sclk / 0x100;
+ mmc->block_dev.part_type = PART_TYPE_DOS;
+
+ mmc_register(mmc);
+
+ return 0;
+}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 9c0652d..a492bbb 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -524,48 +524,70 @@ static int sd_send_op_cond(struct mmc *mmc)
return 0;
}
-static int mmc_send_op_cond(struct mmc *mmc)
+/* We pass in the cmd since otherwise the init seems to fail */
+static int mmc_send_op_cond_iter(struct mmc *mmc, struct mmc_cmd *cmd,
+ int use_arg)
{
- int timeout = 10000;
- struct mmc_cmd cmd;
int err;
+ cmd->cmdidx = MMC_CMD_SEND_OP_COND;
+ cmd->resp_type = MMC_RSP_R3;
+ cmd->cmdarg = 0;
+ if (use_arg && !mmc_host_is_spi(mmc)) {
+ cmd->cmdarg =
+ (mmc->voltages &
+ (mmc->op_cond_response & OCR_VOLTAGE_MASK)) |
+ (mmc->op_cond_response & OCR_ACCESS_MODE);
+
+ if (mmc->host_caps & MMC_MODE_HC)
+ cmd->cmdarg |= OCR_HCS;
+ }
+ err = mmc_send_cmd(mmc, cmd, NULL);
+ if (err)
+ return err;
+ mmc->op_cond_response = cmd->response[0];
+ return 0;
+}
+
+int mmc_send_op_cond(struct mmc *mmc)
+{
+ struct mmc_cmd cmd;
+ int err, i;
+
/* Some cards seem to need this */
mmc_go_idle(mmc);
/* Asking to the card its capabilities */
- cmd.cmdidx = MMC_CMD_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = 0;
-
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ mmc->op_cond_pending = 1;
+ for (i = 0; i < 2; i++) {
+ err = mmc_send_op_cond_iter(mmc, &cmd, i != 0);
+ if (err)
+ return err;
- if (err)
- return err;
+ /* exit if not busy (flag seems to be inverted) */
+ if (mmc->op_cond_response & OCR_BUSY)
+ return 0;
+ }
+ return IN_PROGRESS;
+}
- udelay(1000);
+int mmc_complete_op_cond(struct mmc *mmc)
+{
+ struct mmc_cmd cmd;
+ int timeout = 1000;
+ uint start;
+ int err;
+ mmc->op_cond_pending = 0;
+ start = get_timer(0);
do {
- cmd.cmdidx = MMC_CMD_SEND_OP_COND;
- cmd.resp_type = MMC_RSP_R3;
- cmd.cmdarg = (mmc_host_is_spi(mmc) ? 0 :
- (mmc->voltages &
- (cmd.response[0] & OCR_VOLTAGE_MASK)) |
- (cmd.response[0] & OCR_ACCESS_MODE));
-
- if (mmc->host_caps & MMC_MODE_HC)
- cmd.cmdarg |= OCR_HCS;
-
- err = mmc_send_cmd(mmc, &cmd, NULL);
-
+ err = mmc_send_op_cond_iter(mmc, &cmd, 1);
if (err)
return err;
-
- udelay(1000);
- } while (!(cmd.response[0] & OCR_BUSY) && timeout--);
-
- if (timeout <= 0)
- return UNUSABLE_ERR;
+ if (get_timer(start) > timeout)
+ return UNUSABLE_ERR;
+ udelay(100);
+ } while (!(mmc->op_cond_response & OCR_BUSY));
if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
@@ -1274,7 +1296,7 @@ block_dev_desc_t *mmc_get_dev(int dev)
}
#endif
-int mmc_init(struct mmc *mmc)
+int mmc_start_init(struct mmc *mmc)
{
int err;
@@ -1314,17 +1336,48 @@ int mmc_init(struct mmc *mmc)
if (err == TIMEOUT) {
err = mmc_send_op_cond(mmc);
- if (err) {
+ if (err && err != IN_PROGRESS) {
printf("Card did not respond to voltage select!\n");
return UNUSABLE_ERR;
}
}
- err = mmc_startup(mmc);
+ if (err == IN_PROGRESS)
+ mmc->init_in_progress = 1;
+
+ return err;
+}
+
+static int mmc_complete_init(struct mmc *mmc)
+{
+ int err = 0;
+
+ if (mmc->op_cond_pending)
+ err = mmc_complete_op_cond(mmc);
+
+ if (!err)
+ err = mmc_startup(mmc);
if (err)
mmc->has_init = 0;
else
mmc->has_init = 1;
+ mmc->init_in_progress = 0;
+ return err;
+}
+
+int mmc_init(struct mmc *mmc)
+{
+ int err = IN_PROGRESS;
+ unsigned start = get_timer(0);
+
+ if (mmc->has_init)
+ return 0;
+ if (!mmc->init_in_progress)
+ err = mmc_start_init(mmc);
+
+ if (!err || err == IN_PROGRESS)
+ err = mmc_complete_init(mmc);
+ debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
return err;
}
@@ -1362,6 +1415,25 @@ int get_mmc_num(void)
return cur_dev_num;
}
+void mmc_set_preinit(struct mmc *mmc, int preinit)
+{
+ mmc->preinit = preinit;
+}
+
+static void do_preinit(void)
+{
+ struct mmc *m;
+ struct list_head *entry;
+
+ list_for_each(entry, &mmc_devices) {
+ m = list_entry(entry, struct mmc, link);
+
+ if (m->preinit)
+ mmc_start_init(m);
+ }
+}
+
+
int mmc_initialize(bd_t *bis)
{
INIT_LIST_HEAD (&mmc_devices);
@@ -1372,6 +1444,7 @@ int mmc_initialize(bd_t *bis)
print_mmc_devices(',');
+ do_preinit();
return 0;
}
diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c
index 2fe34b6..63e1f90 100644
--- a/drivers/mmc/mv_sdhci.c
+++ b/drivers/mmc/mv_sdhci.c
@@ -51,6 +51,5 @@ int mv_sdh_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks)
host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
else
host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
- add_sdhci(host, max_clk, min_clk);
- return 0;
+ return add_sdhci(host, max_clk, min_clk);
}
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index afdfa88..975b2c5 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -113,23 +113,21 @@ static void omap5_pbias_config(struct mmc *mmc)
u32 value = 0;
value = readl((*ctrl)->control_pbias);
- value &= ~(SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ);
- value |= SDCARD_BIAS_HIZ_MODE;
+ value &= ~SDCARD_PWRDNZ;
+ writel(value, (*ctrl)->control_pbias);
+ udelay(10); /* wait 10 us */
+ value &= ~SDCARD_BIAS_PWRDNZ;
writel(value, (*ctrl)->control_pbias);
palmas_mmc1_poweron_ldo();
value = readl((*ctrl)->control_pbias);
- value &= ~SDCARD_BIAS_HIZ_MODE;
- value |= SDCARD_PBIASLITE_VMODE | SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ;
+ value |= SDCARD_BIAS_PWRDNZ;
writel(value, (*ctrl)->control_pbias);
-
- value = readl((*ctrl)->control_pbias);
- if (value & (1 << 23)) {
- value &= ~(SDCARD_PWRDNZ | SDCARD_BIAS_PWRDNZ);
- value |= SDCARD_BIAS_HIZ_MODE;
- writel(value, (*ctrl)->control_pbias);
- }
+ udelay(150); /* wait 150 us */
+ value |= SDCARD_PWRDNZ;
+ writel(value, (*ctrl)->control_pbias);
+ udelay(150); /* wait 150 us */
}
#endif
diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index dc49d37..e50ff92 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -94,6 +94,5 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width)
host->host_caps = MMC_MODE_HC;
- add_sdhci(host, 52000000, 400000);
- return 0;
+ return add_sdhci(host, 52000000, 400000);
}
diff --git a/drivers/mmc/spear_sdhci.c b/drivers/mmc/spear_sdhci.c
new file mode 100644
index 0000000..23f1f4b
--- /dev/null
+++ b/drivers/mmc/spear_sdhci.c
@@ -0,0 +1,44 @@
+/*
+ * (C) Copyright 2012
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <sdhci.h>
+
+int spear_sdhci_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks)
+{
+ struct sdhci_host *host = NULL;
+ host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
+ if (!host) {
+ printf("sdhci host malloc fail!\n");
+ return 1;
+ }
+
+ host->name = "sdhci";
+ host->ioaddr = (void *)regbase;
+ host->quirks = quirks;
+
+ if (quirks & SDHCI_QUIRK_REG32_RW)
+ host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
+ else
+ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+
+ add_sdhci(host, max_clk, min_clk);
+ return 0;
+}
diff --git a/drivers/mmc/spl_mmc.c b/drivers/mmc/spl_mmc.c
deleted file mode 100644
index 7efdcb8..0000000
--- a/drivers/mmc/spl_mmc.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * (C) Copyright 2010
- * Texas Instruments, <www.ti.com>
- *
- * Aneesh V <aneesh@ti.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * 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
- */
-#include <common.h>
-#include <spl.h>
-#include <asm/u-boot.h>
-#include <asm/utils.h>
-#include <mmc.h>
-#include <fat.h>
-#include <version.h>
-
-DECLARE_GLOBAL_DATA_PTR;
-
-static void mmc_load_image_raw(struct mmc *mmc)
-{
- unsigned long err;
- u32 image_size_sectors;
- struct image_header *header;
-
- header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
- sizeof(struct image_header));
-
- /* read image header to find the image size & load address */
- err = mmc->block_dev.block_read(0,
- CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR, 1,
- header);
-
- if (err == 0)
- goto end;
-
- spl_parse_image_header(header);
-
- /* convert size to sectors - round up */
- image_size_sectors = (spl_image.size + mmc->read_bl_len - 1) /
- mmc->read_bl_len;
-
- /* Read the header too to avoid extra memcpy */
- err = mmc->block_dev.block_read(0,
- CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,
- image_size_sectors, (void *)spl_image.load_addr);
-
-end:
- if (err == 0) {
- printf("spl: mmc blk read err - %lu\n", err);
- hang();
- }
-}
-
-#ifdef CONFIG_SPL_FAT_SUPPORT
-static void mmc_load_image_fat(struct mmc *mmc)
-{
- int err;
- struct image_header *header;
-
- header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
- sizeof(struct image_header));
-
- err = fat_register_device(&mmc->block_dev,
- CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION);
- if (err) {
- printf("spl: fat register err - %d\n", err);
- hang();
- }
-
- err = file_fat_read(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME,
- header, sizeof(struct image_header));
- if (err <= 0)
- goto end;
-
- spl_parse_image_header(header);
-
- err = file_fat_read(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME,
- (u8 *)spl_image.load_addr, 0);
-
-end:
- if (err <= 0) {
- printf("spl: error reading image %s, err - %d\n",
- CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, err);
- hang();
- }
-}
-#endif
-
-void spl_mmc_load_image(void)
-{
- struct mmc *mmc;
- int err;
- u32 boot_mode;
-
- mmc_initialize(gd->bd);
- /* We register only one device. So, the dev id is always 0 */
- mmc = find_mmc_device(0);
- if (!mmc) {
- puts("spl: mmc device not found!!\n");
- hang();
- }
-
- err = mmc_init(mmc);
- if (err) {
- printf("spl: mmc init failed: err - %d\n", err);
- hang();
- }
- boot_mode = spl_boot_mode();
- if (boot_mode == MMCSD_MODE_RAW) {
- debug("boot mode - RAW\n");
- mmc_load_image_raw(mmc);
-#ifdef CONFIG_SPL_FAT_SUPPORT
- } else if (boot_mode == MMCSD_MODE_FAT) {
- debug("boot mode - FAT\n");
- mmc_load_image_fat(mmc);
-#endif
- } else {
- puts("spl: wrong MMC boot mode\n");
- hang();
- }
-}
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 22d8440..25f8752 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -38,6 +38,7 @@
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/byteorder.h>
+#include <asm/unaligned.h>
#include <environment.h>
#include <mtd/cfi_flash.h>
#include <watchdog.h>
@@ -183,16 +184,16 @@ u64 flash_read64(void *addr)__attribute__((weak, alias("__flash_read64")));
flash_info_t *flash_get_info(ulong base)
{
int i;
- flash_info_t *info = NULL;
+ flash_info_t *info;
for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
- info = & flash_info[i];
+ info = &flash_info[i];
if (info->size && info->start[0] <= base &&
base <= info->start[0] + info->size - 1)
- break;
+ return info;
}
- return info;
+ return NULL;
}
#endif
@@ -1640,9 +1641,10 @@ static void cfi_reverse_geometry(struct cfi_qry *qry)
u32 tmp;
for (i = 0, j = qry->num_erase_regions - 1; i < j; i++, j--) {
- tmp = qry->erase_region_info[i];
- qry->erase_region_info[i] = qry->erase_region_info[j];
- qry->erase_region_info[j] = tmp;
+ tmp = get_unaligned(&(qry->erase_region_info[i]));
+ put_unaligned(get_unaligned(&(qry->erase_region_info[j])),
+ &(qry->erase_region_info[i]));
+ put_unaligned(tmp, &(qry->erase_region_info[j]));
}
}
@@ -2073,8 +2075,8 @@ ulong flash_get_size (phys_addr_t base, int banknum)
info->start[0] = (ulong)map_physmem(base, info->portwidth, MAP_NOCACHE);
if (flash_detect_cfi (info, &qry)) {
- info->vendor = le16_to_cpu(qry.p_id);
- info->ext_addr = le16_to_cpu(qry.p_adr);
+ info->vendor = le16_to_cpu(get_unaligned(&(qry.p_id)));
+ info->ext_addr = le16_to_cpu(get_unaligned(&(qry.p_adr)));
num_erase_regions = qry.num_erase_regions;
if (info->ext_addr) {
@@ -2163,7 +2165,8 @@ ulong flash_get_size (phys_addr_t base, int banknum)
break;
}
- tmp = le32_to_cpu(qry.erase_region_info[i]);
+ tmp = le32_to_cpu(get_unaligned(
+ &(qry.erase_region_info[i])));
debug("erase region %u: 0x%08lx\n", i, tmp);
erase_region_count = (tmp & 0xffff) + 1;
diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c
index bc558c4..dad30b5 100644
--- a/drivers/mtd/spi/spansion.c
+++ b/drivers/mtd/spi/spansion.c
@@ -94,7 +94,7 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = {
.idcode2 = 0x4d01,
.pages_per_sector = 256,
.nr_sectors = 256,
- .name = "S25FL129P_64K",
+ .name = "S25FL129P_64K/S25FL128S",
},
{
.idcode1 = 0x0219,
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index c63398e..0ffd59d 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/net/fec_mxc.c b/drivers/net/fec_mxc.c
index 4dbcdca..da95e28 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -516,9 +516,7 @@ static int fec_open(struct eth_device *edev)
#ifdef FEC_QUIRK_ENET_MAC
{
u32 ecr = readl(&fec->eth->ecntrl) & ~FEC_ECNTRL_SPEED;
- u32 rcr = (readl(&fec->eth->r_cntrl) &
- ~(FEC_RCNTRL_RMII | FEC_RCNTRL_RMII_10T)) |
- FEC_RCNTRL_RGMII | FEC_RCNTRL_MII_MODE;
+ u32 rcr = readl(&fec->eth->r_cntrl) & ~FEC_RCNTRL_RMII_10T;
if (speed == _1000BASET)
ecr |= FEC_ECNTRL_SPEED;
else if (speed != _100BASET)
diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile
index f191c79..9aaa828 100644
--- a/drivers/net/fm/Makefile
+++ b/drivers/net/fm/Makefile
@@ -46,6 +46,7 @@ COBJS-$(CONFIG_PPC_P4080) += p4080.o
COBJS-$(CONFIG_PPC_P5020) += p5020.o
COBJS-$(CONFIG_PPC_P5040) += p5040.o
COBJS-$(CONFIG_PPC_T4240) += t4240.o
+COBJS-$(CONFIG_PPC_T4160) += t4240.o
COBJS-$(CONFIG_PPC_B4420) += b4860.o
COBJS-$(CONFIG_PPC_B4860) += b4860.o
endif
diff --git a/drivers/net/fm/b4860.c b/drivers/net/fm/b4860.c
index 8cde7af..3b5defe 100644
--- a/drivers/net/fm/b4860.c
+++ b/drivers/net/fm/b4860.c
@@ -55,8 +55,10 @@ phy_interface_t fman_port_enet_if(enum fm_port port)
if (is_device_disabled(port))
return PHY_INTERFACE_MODE_NONE;
- if ((port == FM1_10GEC1 || port == FM1_10GEC2)
- && (is_serdes_configured(XAUI_FM1)))
+ /*B4860 has two 10Gig Mac*/
+ if ((port == FM1_10GEC1 || port == FM1_10GEC2) &&
+ ((is_serdes_configured(XAUI_FM1_MAC9)) ||
+ (is_serdes_configured(XAUI_FM1_MAC10))))
return PHY_INTERFACE_MODE_XGMII;
/* Fix me need to handle RGMII here first */
diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c
index 54b142f..9b139ee 100644
--- a/drivers/net/fm/eth.c
+++ b/drivers/net/fm/eth.c
@@ -568,6 +568,8 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg)
num = fm_eth->num;
#ifdef CONFIG_SYS_FMAN_V3
+ if (fm_eth->type == FM_ETH_10G_E)
+ num += 8;
base = &reg->memac[num].fm_memac;
phyregs = &reg->memac[num].fm_memac_mdio;
#else
diff --git a/drivers/net/fm/fm.h b/drivers/net/fm/fm.h
index 228df33..ba581e9 100644
--- a/drivers/net/fm/fm.h
+++ b/drivers/net/fm/fm.h
@@ -152,4 +152,6 @@ struct fm_eth {
#define MAX_RXBUF_LOG2 11
#define MAX_RXBUF_LEN (1 << MAX_RXBUF_LOG2)
+#define PORT_IS_ENABLED(port) fm_info[fm_port_to_index(port)].enabled
+
#endif /* __FM_H__ */
diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c
index ae389b8..5908c32 100644
--- a/drivers/net/fm/init.c
+++ b/drivers/net/fm/init.c
@@ -74,9 +74,15 @@ struct fm_eth_info fm_info[] = {
#if (CONFIG_SYS_NUM_FM1_10GEC >= 1)
FM_TGEC_INFO_INITIALIZER(1, 1),
#endif
+#if (CONFIG_SYS_NUM_FM1_10GEC >= 2)
+ FM_TGEC_INFO_INITIALIZER(1, 2),
+#endif
#if (CONFIG_SYS_NUM_FM2_10GEC >= 1)
FM_TGEC_INFO_INITIALIZER(2, 1),
#endif
+#if (CONFIG_SYS_NUM_FM2_10GEC >= 2)
+ FM_TGEC_INFO_INITIALIZER(2, 2),
+#endif
};
int fm_standard_init(bd_t *bis)
@@ -232,6 +238,26 @@ static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop)
return ;
}
+#ifdef CONFIG_SYS_FMAN_V3
+ /*
+ * Physically FM1_DTSEC9 and FM1_10GEC1 use the same dual-role MAC, when
+ * FM1_10GEC1 is enabled and FM1_DTSEC9 is disabled, ensure that the
+ * dual-role MAC is not disabled, ditto for other dual-role MACs.
+ */
+ if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) ||
+ ((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) ||
+ ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC9))) ||
+ ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC10)))
+#if (CONFIG_SYS_NUM_FMAN == 2)
+ ||
+ ((info->port == FM2_DTSEC9) && (PORT_IS_ENABLED(FM2_10GEC1))) ||
+ ((info->port == FM2_DTSEC10) && (PORT_IS_ENABLED(FM2_10GEC2))) ||
+ ((info->port == FM2_10GEC1) && (PORT_IS_ENABLED(FM2_DTSEC9))) ||
+ ((info->port == FM2_10GEC2) && (PORT_IS_ENABLED(FM2_DTSEC10)))
+#endif
+ )
+ return;
+#endif
/* board code might have caused offset to change */
off = fdt_node_offset_by_compat_reg(blob, prop, paddr);
@@ -249,10 +275,15 @@ void fdt_fixup_fman_ethernet(void *blob)
{
int i;
+#ifdef CONFIG_SYS_FMAN_V3
+ for (i = 0; i < ARRAY_SIZE(fm_info); i++)
+ ft_fixup_port(blob, &fm_info[i], "fsl,fman-memac");
+#else
for (i = 0; i < ARRAY_SIZE(fm_info); i++) {
if (fm_info[i].type == FM_ETH_1G_E)
ft_fixup_port(blob, &fm_info[i], "fsl,fman-1g-mac");
else
ft_fixup_port(blob, &fm_info[i], "fsl,fman-10g-mac");
}
+#endif
}
diff --git a/drivers/net/fm/t4240.c b/drivers/net/fm/t4240.c
index 48c530c..275395f 100644
--- a/drivers/net/fm/t4240.c
+++ b/drivers/net/fm/t4240.c
@@ -70,12 +70,18 @@ phy_interface_t fman_port_enet_if(enum fm_port port)
if (is_device_disabled(port))
return PHY_INTERFACE_MODE_NONE;
- if ((port == FM1_10GEC1 || port == FM1_10GEC2)
- && (is_serdes_configured(XAUI_FM1)))
+ if ((port == FM1_10GEC1 || port == FM1_10GEC2) &&
+ ((is_serdes_configured(XAUI_FM1_MAC9)) ||
+ (is_serdes_configured(XAUI_FM1_MAC10)) ||
+ (is_serdes_configured(XFI_FM1_MAC9)) ||
+ (is_serdes_configured(XFI_FM1_MAC10))))
return PHY_INTERFACE_MODE_XGMII;
- if ((port == FM2_10GEC1 || port == FM2_10GEC2)
- && (is_serdes_configured(XAUI_FM2)))
+ if ((port == FM2_10GEC1 || port == FM2_10GEC2) &&
+ ((is_serdes_configured(XAUI_FM2_MAC9)) ||
+ (is_serdes_configured(XAUI_FM2_MAC10)) ||
+ (is_serdes_configured(XFI_FM2_MAC9)) ||
+ (is_serdes_configured(XFI_FM2_MAC10))))
return PHY_INTERFACE_MODE_XGMII;
#define FSL_CORENET_RCWSR13_EC1 0x60000000 /* bits 417..418 */
diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c
index 78447b7..84ce736 100644
--- a/drivers/net/phy/teranetics.c
+++ b/drivers/net/phy/teranetics.c
@@ -34,9 +34,21 @@ int tn2020_config(struct phy_device *phydev)
unsigned short restart_an = (MDIO_AN_CTRL1_RESTART |
MDIO_AN_CTRL1_ENABLE |
MDIO_AN_CTRL1_XNP);
+ u8 phy_hwversion;
- phy_write(phydev, 30, 93, 2);
- phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an);
+ /*
+ * bit 15:12 of register 30.32 indicates PHY hardware
+ * version. It can be used to distinguish TN80xx from
+ * TN2020. TN2020 needs write 0x2 to 30.93, but TN80xx
+ * needs 0x1.
+ */
+ phy_hwversion = (phy_read(phydev, 30, 32) >> 12) & 0xf;
+ if (phy_hwversion <= 3) {
+ phy_write(phydev, 30, 93, 2);
+ phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an);
+ } else {
+ phy_write(phydev, 30, 93, 1);
+ }
}
return 0;
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 6c5cb99..c283d82 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -48,6 +48,19 @@
#define MIIM_VSC8601_SKEW_CTRL 0x1c
#define PHY_EXT_PAGE_ACCESS 0x1f
+#define PHY_EXT_PAGE_ACCESS_GENERAL 0x10
+#define PHY_EXT_PAGE_ACCESS_EXTENDED3 0x3
+
+/* Vitesse VSC8574 control register */
+#define MIIM_VSC8574_MAC_SERDES_CON 0x10
+#define MIIM_VSC8574_MAC_SERDES_ANEG 0x80
+#define MIIM_VSC8574_GENERAL18 0x12
+#define MIIM_VSC8574_GENERAL19 0x13
+
+/* Vitesse VSC8574 gerenal purpose register 18 */
+#define MIIM_VSC8574_18G_SGMII 0x80f0
+#define MIIM_VSC8574_18G_QSGMII 0x80e0
+#define MIIM_VSC8574_18G_CMDSTAT 0x8000
/* CIS8201 */
static int vitesse_config(struct phy_device *phydev)
@@ -145,6 +158,49 @@ static int vsc8601_config(struct phy_device *phydev)
return 0;
}
+static int vsc8574_config(struct phy_device *phydev)
+{
+ u32 val;
+ /* configure regiser 19G for MAC */
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
+ PHY_EXT_PAGE_ACCESS_GENERAL);
+
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19);
+ if (phydev->interface == PHY_INTERFACE_MODE_QSGMII) {
+ /* set bit 15:14 to '01' for QSGMII mode */
+ val = (val & 0x3fff) | (1 << 14);
+ phy_write(phydev, MDIO_DEVAD_NONE,
+ MIIM_VSC8574_GENERAL19, val);
+ /* Enable 4 ports MAC QSGMII */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
+ MIIM_VSC8574_18G_QSGMII);
+ } else {
+ /* set bit 15:14 to '00' for SGMII mode */
+ val = val & 0x3fff;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL19, val);
+ /* Enable 4 ports MAC SGMII */
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18,
+ MIIM_VSC8574_18G_SGMII);
+ }
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
+ /* When bit 15 is cleared the command has completed */
+ while (val & MIIM_VSC8574_18G_CMDSTAT)
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_GENERAL18);
+
+ /* Enable Serdes Auto-negotiation */
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
+ PHY_EXT_PAGE_ACCESS_EXTENDED3);
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON);
+ val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8574_MAC_SERDES_CON, val);
+
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
+
+ genphy_config_aneg(phydev);
+
+ return 0;
+}
+
static struct phy_driver VSC8211_driver = {
.name = "Vitesse VSC8211",
.uid = 0xfc4b0,
@@ -185,6 +241,16 @@ static struct phy_driver VSC8234_driver = {
.shutdown = &genphy_shutdown,
};
+static struct phy_driver VSC8574_driver = {
+ .name = "Vitesse VSC8574",
+ .uid = 0x704a0,
+ .mask = 0xffff0,
+ .features = PHY_GBIT_FEATURES,
+ .config = &vsc8574_config,
+ .startup = &vitesse_startup,
+ .shutdown = &genphy_shutdown,
+};
+
static struct phy_driver VSC8601_driver = {
.name = "Vitesse VSC8601",
.uid = 0x70420,
@@ -244,6 +310,7 @@ int phy_vitesse_init(void)
phy_register(&VSC8244_driver);
phy_register(&VSC8211_driver);
phy_register(&VSC8221_driver);
+ phy_register(&VSC8574_driver);
phy_register(&VSC8662_driver);
phy_register(&cis8201_driver);
phy_register(&cis8204_driver);
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index a290073..f63a069 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -484,7 +484,7 @@ static void smc911x_reset(struct eth_device *dev)
while (timeout-- &&
!(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY))
udelay(10);
- if (!timeout) {
+ if (timeout < 0) {
printf(DRIVERNAME
": timeout waiting for PM restore\n");
return;
@@ -500,7 +500,7 @@ static void smc911x_reset(struct eth_device *dev)
while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
udelay(10);
- if (!timeout) {
+ if (timeout < 0) {
printf(DRIVERNAME ": reset timeout\n");
return;
}
diff --git a/drivers/power/palmas.c b/drivers/power/palmas.c
index 09c832d..2d275a7 100644
--- a/drivers/power/palmas.c
+++ b/drivers/power/palmas.c
@@ -25,28 +25,137 @@
void palmas_init_settings(void)
{
- return;
+#ifdef CONFIG_PALMAS_SMPS7_FPWM
+ int err;
+ /*
+ * Set SMPS7 (1.8 V I/O supply on platforms with TWL6035/37) to
+ * forced PWM mode. This reduces noise (but affects efficiency).
+ */
+ u8 val = SMPS_MODE_SLP_FPWM | SMPS_MODE_ACT_FPWM;
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS7_CTRL, val);
+ if (err)
+ printf("palmas: could not force PWM for SMPS7: err = %d\n",
+ err);
+#endif
}
int palmas_mmc1_poweron_ldo(void)
{
u8 val = 0;
- /* set LDO9 TWL6035 to 3V */
- val = 0x2b; /* (3 -.9)*28 +1 */
-
- if (palmas_i2c_write_u8(0x48, LDO9_VOLTAGE, val)) {
- printf("twl6035: could not set LDO9 voltage.\n");
+#if defined(CONFIG_DRA7XX)
+ /*
+ * Currently valid for the dra7xx_evm board:
+ * Set TPS659038 LDO1 to 3.0 V
+ */
+ val = LDO_VOLT_3V0;
+ if (palmas_i2c_write_u8(TPS65903X_CHIP_P1, LDO1_VOLTAGE, val)) {
+ printf("tps65903x: could not set LDO1 voltage.\n");
+ return 1;
+ }
+ /* TURN ON LDO1 */
+ val = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ if (palmas_i2c_write_u8(TPS65903X_CHIP_P1, LDO1_CTRL, val)) {
+ printf("tps65903x: could not turn on LDO1.\n");
return 1;
}
+ return 0;
+#else
+ /*
+ * We assume that this is a OMAP543X + TWL603X board:
+ * Set TWL6035/37 LDO9 to 3.0 V
+ */
+ val = LDO_VOLT_3V0;
+ return twl603x_mmc1_set_ldo9(val);
+#endif
+}
- /* TURN ON LDO9 */
- val = LDO_ON | LDO_MODE_SLEEP | LDO_MODE_ACTIVE;
+/*
+ * On some OMAP5 + TWL603X hardware the SD card socket and LDO9_IN are
+ * powered by an external 3.3 V regulator, while the output of LDO9
+ * supplies VDDS_SDCARD for the OMAP5 interface only. This implies that
+ * LDO9 could be set to 'bypass' mode when required (e.g. for 3.3 V cards).
+ */
+int twl603x_mmc1_set_ldo9(u8 vsel)
+{
+ u8 cval = 0, vval = 0; /* Off by default */
+ int err;
- if (palmas_i2c_write_u8(0x48, LDO9_CTRL, val)) {
- printf("twl6035: could not turn on LDO9.\n");
- return 1;
+ if (vsel) {
+ /* Turn on */
+ if (vsel > LDO_VOLT_3V3) {
+ /* Put LDO9 in bypass */
+ cval = LDO9_BYP_EN | RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ vval = LDO_VOLT_3V3;
+ } else {
+ cval = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ vval = vsel & 0x3f;
+ }
+ }
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, LDO9_VOLTAGE, vval);
+ if (err) {
+ printf("twl603x: could not set LDO9 %s: err = %d\n",
+ vsel > LDO_VOLT_3V3 ? "bypass" : "voltage", err);
+ return err;
}
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, LDO9_CTRL, cval);
+ if (err)
+ printf("twl603x: could not turn %s LDO9: err = %d\n",
+ cval ? "on" : "off", err);
+ return err;
+}
- return 0;
+#ifdef CONFIG_PALMAS_AUDPWR
+/*
+ * Turn audio codec power and 32 kHz clock on/off. Use for
+ * testing OMAP543X + TWL603X + TWL604X boards only.
+ */
+int twl603x_audio_power(u8 on)
+{
+ u8 cval = 0, vval = 0, c32k = 0;
+ int err;
+
+ if (on) {
+ vval = SMPS_VOLT_2V1;
+ cval = SMPS_MODE_SLP_AUTO | SMPS_MODE_ACT_AUTO;
+ c32k = RSC_MODE_SLEEP | RSC_MODE_ACTIVE;
+ }
+ /* Set SMPS9 to 2.1 V (for TWL604x), or to 0 (off) */
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS9_VOLTAGE, vval);
+ if (err) {
+ printf("twl603x: could not set SMPS9 voltage: err = %d\n",
+ err);
+ return err;
+ }
+ /* Turn on or off SMPS9 */
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, SMPS9_CTRL, cval);
+ if (err) {
+ printf("twl603x: could not turn SMPS9 %s: err = %d\n",
+ cval ? "on" : "off", err);
+ return err;
+ }
+ /* Output 32 kHz clock on or off */
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, CLK32KGAUDIO_CTRL, c32k);
+ if (err)
+ printf("twl603x: could not turn CLK32KGAUDIO %s: err = %d\n",
+ c32k ? "on" : "off", err);
+ return err;
+}
+#endif
+
+/*
+ * Enable/disable back-up battery (or super cap) charging on TWL6035/37.
+ * Please use defined BB_xxx values.
+ */
+int twl603x_enable_bb_charge(u8 bb_fields)
+{
+ u8 val = bb_fields & 0x0f;
+ int err;
+
+ val |= (VRTC_EN_SLP | VRTC_EN_OFF | VRTC_PWEN);
+ err = palmas_i2c_write_u8(TWL603X_CHIP_P1, BB_VRTC_CTRL, val);
+ if (err)
+ printf("twl603x: could not set BB_VRTC_CTRL to 0x%02x: err = %d\n",
+ val, err);
+ return err;
}
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index fbc4e97..0f954a5 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -52,6 +52,8 @@ 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
+COBJS-$(CONFIG_FSL_LPUART) += serial_lpuart.o
ifndef CONFIG_SPL_BUILD
COBJS-$(CONFIG_USB_TTY) += usbtty.o
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 7f013ab..d77c25f 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -74,13 +74,8 @@ void NS16550_init(NS16550_t com_port, int baud_divisor)
defined(CONFIG_AM33XX) || defined(CONFIG_SOC_DA8XX) || \
defined(CONFIG_TI814X)
-#if defined(CONFIG_APTIX)
- /* /13 mode so Aptix 6MHz can hit 115200 */
- serial_out(3, &com_port->mdr1);
-#else
/* /16 is proper to hit 115200 with 48MHz */
serial_out(0, &com_port->mdr1);
-#endif
#endif /* CONFIG_OMAP */
}
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index 9f04643..daa8003 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -143,7 +143,6 @@ serial_initfunc(au1x00_serial_initialize);
serial_initfunc(asc_serial_initialize);
serial_initfunc(jz_serial_initialize);
serial_initfunc(mpc5xx_serial_initialize);
-serial_initfunc(mpc8220_serial_initialize);
serial_initfunc(mpc8260_scc_serial_initialize);
serial_initfunc(mpc8260_smc_serial_initialize);
serial_initfunc(mpc85xx_serial_initialize);
@@ -236,7 +235,6 @@ void serial_initialize(void)
asc_serial_initialize();
jz_serial_initialize();
mpc5xx_serial_initialize();
- mpc8220_serial_initialize();
mpc8260_scc_serial_initialize();
mpc8260_smc_serial_initialize();
mpc85xx_serial_initialize();
diff --git a/drivers/serial/serial_bfin.c b/drivers/serial/serial_bfin.c
new file mode 100644
index 0000000..0443b84
--- /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/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
new file mode 100644
index 0000000..51d5666
--- /dev/null
+++ b/drivers/serial/serial_lpuart.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+ *
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <asm/io.h>
+#include <serial.h>
+#include <linux/compiler.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/clock.h>
+
+#define US1_TDRE (1 << 7)
+#define US1_RDRF (1 << 5)
+#define UC2_TE (1 << 3)
+#define UC2_RE (1 << 2)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct lpuart_fsl *base = (struct lpuart_fsl *)LPUART_BASE;
+
+static void lpuart_serial_setbrg(void)
+{
+ u32 clk = mxc_get_clock(MXC_UART_CLK);
+ u16 sbr;
+
+ if (!gd->baudrate)
+ gd->baudrate = CONFIG_BAUDRATE;
+
+ sbr = (u16)(clk / (16 * gd->baudrate));
+ /* place adjustment later - n/32 BRFA */
+
+ __raw_writeb(sbr >> 8, &base->ubdh);
+ __raw_writeb(sbr & 0xff, &base->ubdl);
+}
+
+static int lpuart_serial_getc(void)
+{
+ u8 status;
+
+ while (!(__raw_readb(&base->us1) & US1_RDRF))
+ WATCHDOG_RESET();
+
+ status = __raw_readb(&base->us1);
+ status |= US1_RDRF;
+ __raw_writeb(status, &base->us1);
+
+ return __raw_readb(&base->ud);
+}
+
+static void lpuart_serial_putc(const char c)
+{
+ if (c == '\n')
+ serial_putc('\r');
+
+ while (!(__raw_readb(&base->us1) & US1_TDRE))
+ WATCHDOG_RESET();
+
+ __raw_writeb(c, &base->ud);
+}
+
+/*
+ * Test whether a character is in the RX buffer
+ */
+static int lpuart_serial_tstc(void)
+{
+ if (__raw_readb(&base->urcfifo) == 0)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Initialise the serial port with the given baudrate. The settings
+ * are always 8 data bits, no parity, 1 stop bit, no start bits.
+ */
+static int lpuart_serial_init(void)
+{
+ u8 ctrl;
+
+ ctrl = __raw_readb(&base->uc2);
+ ctrl &= ~UC2_RE;
+ ctrl &= ~UC2_TE;
+ __raw_writeb(ctrl, &base->uc2);
+
+ __raw_writeb(0, &base->umodem);
+ __raw_writeb(0, &base->uc1);
+
+ /* provide data bits, parity, stop bit, etc */
+
+ serial_setbrg();
+
+ __raw_writeb(UC2_RE | UC2_TE, &base->uc2);
+
+ return 0;
+}
+
+static struct serial_device lpuart_serial_drv = {
+ .name = "lpuart_serial",
+ .start = lpuart_serial_init,
+ .stop = NULL,
+ .setbrg = lpuart_serial_setbrg,
+ .putc = lpuart_serial_putc,
+ .puts = default_serial_puts,
+ .getc = lpuart_serial_getc,
+ .tstc = lpuart_serial_tstc,
+};
+
+void lpuart_serial_initialize(void)
+{
+ serial_register(&lpuart_serial_drv);
+}
+
+__weak struct serial_device *default_serial_console(void)
+{
+ return &lpuart_serial_drv;
+}
diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
index b92eef4..3c07da3 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -151,12 +151,7 @@ static int calc_divisor (NS16550_t port)
}
#endif
-#ifdef CONFIG_APTIX
-#define MODE_X_DIV 13
-#else
#define MODE_X_DIV 16
-#endif
-
/* Compute divisor value. Normally, we should simply return:
* CONFIG_SYS_NS16550_CLK) / MODE_X_DIV / gd->baudrate
* but we need to round that value by adding 0.5.
diff --git a/drivers/spi/bfin_spi.c b/drivers/spi/bfin_spi.c
index ab2e8b9..a9a4d92 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/usb/eth/smsc95xx.c b/drivers/usb/eth/smsc95xx.c
index fd8f8a7..685702e 100644
--- a/drivers/usb/eth/smsc95xx.c
+++ b/drivers/usb/eth/smsc95xx.c
@@ -798,6 +798,7 @@ struct smsc95xx_dongle {
static const struct smsc95xx_dongle smsc95xx_dongles[] = {
{ 0x0424, 0xec00 }, /* LAN9512/LAN9514 Ethernet */
{ 0x0424, 0x9500 }, /* LAN9500 Ethernet */
+ { 0x0424, 0x9730 }, /* LAN9730 Ethernet (HSIC) */
{ 0x0000, 0x0000 } /* END - Do not remove */
};
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c816878..e0f3e4b 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -122,6 +122,31 @@ static struct descriptor {
#define ehci_is_TDI() (0)
#endif
+int __ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+{
+ return PORTSC_PSPD(reg);
+}
+
+int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+ __attribute__((weak, alias("__ehci_get_port_speed")));
+
+void __ehci_set_usbmode(int index)
+{
+ uint32_t tmp;
+ uint32_t *reg_ptr;
+
+ reg_ptr = (uint32_t *)((u8 *)&ehcic[index].hcor->or_usbcmd + USBMODE);
+ tmp = ehci_readl(reg_ptr);
+ tmp |= USBMODE_CM_HC;
+#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
+ tmp |= USBMODE_BE;
+#endif
+ ehci_writel(reg_ptr, tmp);
+}
+
+void ehci_set_usbmode(int index)
+ __attribute__((weak, alias("__ehci_set_usbmode")));
+
void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
{
mdelay(50);
@@ -149,8 +174,6 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
static int ehci_reset(int index)
{
uint32_t cmd;
- uint32_t tmp;
- uint32_t *reg_ptr;
int ret = 0;
cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
@@ -163,15 +186,8 @@ static int ehci_reset(int index)
goto out;
}
- if (ehci_is_TDI()) {
- reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
- tmp = ehci_readl(reg_ptr);
- tmp |= USBMODE_CM_HC;
-#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
- tmp |= USBMODE_BE;
-#endif
- ehci_writel(reg_ptr, tmp);
- }
+ if (ehci_is_TDI())
+ ehci_set_usbmode(index);
#ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -587,16 +603,6 @@ fail:
return -1;
}
-static inline int min3(int a, int b, int c)
-{
-
- if (b < a)
- a = b;
- if (c < a)
- a = c;
- return a;
-}
-
int
ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
int length, struct devrequest *req)
@@ -607,15 +613,14 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
int len, srclen;
uint32_t reg;
uint32_t *status_reg;
+ int port = le16_to_cpu(req->index) & 0xff;
struct ehci_ctrl *ctrl = dev->controller;
- if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
- printf("The request port(%d) is not configured\n",
- le16_to_cpu(req->index) - 1);
+ if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+ printf("The request port(%d) is not configured\n", port - 1);
return -1;
}
- status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
- le16_to_cpu(req->index) - 1];
+ status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
srclen = 0;
debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
@@ -711,7 +716,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
if (ehci_is_TDI()) {
- switch (PORTSC_PSPD(reg)) {
+ switch (ehci_get_port_speed(ctrl->hcor, reg)) {
case PORTSC_PSPD_FS:
break;
case PORTSC_PSPD_LS:
@@ -732,7 +737,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
tmpbuf[2] |= USB_PORT_STAT_C_ENABLE;
if (reg & EHCI_PS_OCC)
tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
- if (ctrl->portreset & (1 << le16_to_cpu(req->index)))
+ if (ctrl->portreset & (1 << port))
tmpbuf[2] |= USB_PORT_STAT_C_RESET;
srcptr = tmpbuf;
@@ -758,7 +763,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
EHCI_PS_IS_LOWSPEED(reg)) {
/* Low speed device, give up ownership. */
debug("port %d low speed --> companion\n",
- req->index - 1);
+ port - 1);
reg |= EHCI_PS_PO;
ehci_writel(status_reg, reg);
break;
@@ -784,13 +789,17 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
ret = handshake(status_reg, EHCI_PS_PR, 0,
2 * 1000);
if (!ret)
- ctrl->portreset |=
- 1 << le16_to_cpu(req->index);
+ ctrl->portreset |= 1 << port;
else
printf("port(%d) reset error\n",
- le16_to_cpu(req->index) - 1);
+ port - 1);
}
break;
+ case USB_PORT_FEAT_TEST:
+ reg &= ~(0xf << 16);
+ reg |= ((le16_to_cpu(req->index) >> 8) & 0xf) << 16;
+ ehci_writel(status_reg, reg);
+ break;
default:
debug("unknown feature %x\n", le16_to_cpu(req->value));
goto unknown;
@@ -817,7 +826,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC;
break;
case USB_PORT_FEAT_C_RESET:
- ctrl->portreset &= ~(1 << le16_to_cpu(req->index));
+ ctrl->portreset &= ~(1 << port);
break;
default:
debug("unknown feature %x\n", le16_to_cpu(req->value));
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index efd711d..2060a3e 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -42,7 +42,7 @@ int usb_cpu_init(void)
while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB)
;
#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \
- defined(CONFIG_AT91SAM9X5)
+ defined(CONFIG_AT91SAM9X5) || defined(CONFIG_SAMA5D3)
/* Enable UPLL */
writel(readl(&pmc->uckr) | AT91_PMC_UPLLEN | AT91_PMC_BIASEN,
&pmc->uckr);
@@ -54,8 +54,13 @@ int usb_cpu_init(void)
#endif
/* Enable USB host clock. */
+#ifdef CONFIG_SAMA5D3
+ writel(1 << (ATMEL_ID_UHP - 32), &pmc->pcer1);
+#else
writel(1 << ATMEL_ID_UHP, &pmc->pcer);
-#ifdef CONFIG_AT91SAM9261
+#endif
+
+#if defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10)
writel(ATMEL_PMC_UHP | AT91_PMC_HCK0, &pmc->scer);
#else
writel(ATMEL_PMC_UHP, &pmc->scer);
@@ -69,8 +74,13 @@ int usb_cpu_stop(void)
at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
/* Disable USB host clock. */
+#ifdef CONFIG_SAMA5D3
+ writel(1 << (ATMEL_ID_UHP - 32), &pmc->pcdr1);
+#else
writel(1 << ATMEL_ID_UHP, &pmc->pcdr);
-#ifdef CONFIG_AT91SAM9261
+#endif
+
+#if defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10)
writel(ATMEL_PMC_UHP | AT91_PMC_HCK0, &pmc->scdr);
#else
writel(ATMEL_PMC_UHP, &pmc->scdr);
@@ -83,7 +93,7 @@ int usb_cpu_stop(void)
while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != 0)
;
#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \
- defined(CONFIG_AT91SAM9X5)
+ defined(CONFIG_AT91SAM9X5) || defined(CONFIG_SAMA5D3)
/* Disable UPLL */
writel(readl(&pmc->uckr) & (~AT91_PMC_UPLLEN), &pmc->uckr);
while ((readl(&pmc->sr) & AT91_PMC_LOCKU) == AT91_PMC_LOCKU)
diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c
index c7876ed..a395ebc 100644
--- a/drivers/usb/musb/omap3.c
+++ b/drivers/usb/musb/omap3.c
@@ -30,6 +30,7 @@
* MA 02111-1307 USA
*/
+#include <asm/omap_common.h>
#include <twl4030.h>
#include <twl6030.h>
#include "omap3.h"
@@ -135,7 +136,8 @@ int musb_platform_init(void)
#endif
#ifdef CONFIG_OMAP4430
- u32 *usbotghs_control = (u32 *)(CTRL_BASE + 0x33C);
+ u32 *usbotghs_control =
+ (u32 *)((*ctrl)->control_usbotghs_ctrl);
*usbotghs_control = 0x15;
#endif
platform_needs_initialization = 0;
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 461ff6e..b189419 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -39,6 +39,11 @@ static GraphicDevice panel;
* setenv videomode
* video=ctfb:x:800,y:480,depth:18,mode:0,pclk:30066,
* le:0,ri:256,up:0,lo:45,hs:1,vs:1,sync:100663296,vmode:0
+ *
+ * Freescale mx23evk/mx28evk with a Seiko 4.3'' WVGA panel:
+ * setenv videomode
+ * video=ctfb:x:800,y:480,depth:24,mode:0,pclk:29851,
+ * le:89,ri:164,up:23,lo:10,hs:10,vs:10,sync:0,vmode:0
*/
static void mxs_lcd_init(GraphicDevice *panel,
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 13e7c37..b9bbbc6 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -27,12 +27,13 @@ LIB := $(obj)libwatchdog.o
COBJS-$(CONFIG_AT91SAM9_WATCHDOG) += at91sam9_wdt.o
COBJS-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o
-ifneq (,$(filter $(SOC), mx31 mx35 mx5 mx6))
+ifneq (,$(filter $(SOC), mx31 mx35 mx5 mx6 vf610))
COBJS-y += imx_watchdog.o
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 0000000..7a6756b
--- /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);
+}