diff options
| author | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2013-05-30 14:45:06 +0200 | 
|---|---|---|
| committer | Albert ARIBAUD <albert.u.boot@aribaud.net> | 2013-05-30 14:45:06 +0200 | 
| commit | a19b0dd62d7b8efc658fa1aa685ff5665878f3ee (patch) | |
| tree | 1fadf0fb3da83203ba28f209ec99e1b33e03f4d5 /drivers | |
| parent | 60985bba58e7695dac1fddae8cdbb62d8cfd1254 (diff) | |
| parent | a71d45d706a5b51c348160163b6c159632273fed (diff) | |
| download | olio-uboot-2014.01-a19b0dd62d7b8efc658fa1aa685ff5665878f3ee.tar.xz olio-uboot-2014.01-a19b0dd62d7b8efc658fa1aa685ff5665878f3ee.zip | |
Merge branch 'u-boot/master' into 'u-boot-arm/master'
Conflicts:
	common/cmd_fpga.c
	drivers/usb/host/ohci-at91.c
Diffstat (limited to 'drivers')
34 files changed, 1976 insertions, 1030 deletions
| diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9df1e2632..f77c1ec1e 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 000000000..7a034eba1 --- /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 000000000..37fb0c50b --- /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(®s->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(®s->gpiodir); + +		gpio_priv = gpio - priv->gpio_min; +		if (direction == GPIO_DIRECTION_OUT) +			val &= ~(1 << gpio_priv); +		else +			val |= 1 << gpio_priv; + +		writel(val, ®s->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(®s->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, ®s->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/mmc/Makefile b/drivers/mmc/Makefile index 7cd428173..24648a293 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 e2379e326..5aa218426 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(®s->mmcdrr); diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index e945c0a47..861f4b9d6 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 42f0e0ce5..000000000 --- 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(®->int_mask); -	newmask |= imask; - -	writel(newmask, ®->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 000000000..562b14aff --- /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, +		®s->clr); +	writel(arg, ®s->argu); +	writel(cmd, ®s->cmd); + +	if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) { +		for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { +			if (readl(®s->status) & FTSDC010_STATUS_CMD_SEND) { +				writel(FTSDC010_STATUS_CMD_SEND, ®s->clr); +				ret = 0; +				break; +			} +		} +	} else { +		st = 0; +		for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { +			st = readl(®s->status); +			writel(st & FTSDC010_STATUS_RSP_MASK, ®s->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(®s->rsp3); +				mmc_cmd->response[1] = readl(®s->rsp2); +				mmc_cmd->response[2] = readl(®s->rsp1); +				mmc_cmd->response[3] = readl(®s->rsp0); +			} else { +				mmc_cmd->response[0] = readl(®s->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), ®s->ccr); + +	if (IS_SD(mmc)) { +		setbits_le32(®s->ccr, FTSDC010_CCR_CLK_SD); + +		if (chip->rate > 25000000) +			setbits_le32(®s->ccr, FTSDC010_CCR_CLK_HISPD); +		else +			clrbits_le32(®s->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(®s->status); +		if (!(st & mask)) +			continue; +		writel(st & mask, ®s->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, ®s->dcr); + +		/* 2. clear status register */ +		writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN +			| FTSDC010_STATUS_FIFO_ORUN, ®s->clr); + +		/* 3. data timeout (1 sec) */ +		writel(chip->rate, ®s->dtr); + +		/* 4. data length (bytes) */ +		writel(len, ®s->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, ®s->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, ®s->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(®s->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(®s->bwr, FTSDC010_BWR_MODE_MASK); +	switch (mmc->bus_width) { +	case 4: +		setbits_le32(®s->bwr, FTSDC010_BWR_MODE_4BIT); +		break; +	case 8: +		setbits_le32(®s->bwr, FTSDC010_BWR_MODE_8BIT); +		break; +	default: +		setbits_le32(®s->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(®s->status) & FTSDC010_STATUS_CARD_DETECT) +		return NO_CARD_ERR; + +	if (readl(®s->status) & FTSDC010_STATUS_WRITE_PROT) { +		printf("ftsdc010: write protected\n"); +		chip->wprot = 1; +	} + +	chip->fifo = (readl(®s->feature) & 0xff) << 2; + +	/* 1. chip reset */ +	writel(FTSDC010_CMD_SDC_RST, ®s->cmd); +	for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) { +		if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST) +			continue; +		break; +	} +	if (readl(®s->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, ®s->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(®s->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 2590f1bcc..0a2f5358e 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,5 +1444,6 @@ 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 2fe34b699..63e1f9062 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/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index dc49d37f5..e50ff925a 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 000000000..23f1f4b70 --- /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 7efdcb88b..000000000 --- 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 22d84407d..25f875202 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 bc558c4c9..dad30b54c 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 c63398ebf..0ffd59d49 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/fm/Makefile b/drivers/net/fm/Makefile index f191c79a2..9aaa82853 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 8cde7afc1..3b5defefa 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 54b142f47..9b139eeb0 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 = ®->memac[num].fm_memac;  	phyregs = ®->memac[num].fm_memac_mdio;  #else diff --git a/drivers/net/fm/fm.h b/drivers/net/fm/fm.h index 228df330f..ba581e9ef 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 ae389b884..5908c3254 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 48c530c91..275395f18 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 78447b711..84ce7362f 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 6c5cb9977..c283d823b 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 a290073bb..f63a0695e 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/serial/Makefile b/drivers/serial/Makefile index fbc4e97e9..442b7ea0d 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -52,6 +52,7 @@ COBJS-$(CONFIG_XILINX_UARTLITE) += serial_xuartlite.o  COBJS-$(CONFIG_SANDBOX_SERIAL) += sandbox.o  COBJS-$(CONFIG_SCIF_CONSOLE) += serial_sh.o  COBJS-$(CONFIG_ZYNQ_SERIAL) += serial_zynq.o +COBJS-$(CONFIG_BFIN_SERIAL) += serial_bfin.o  ifndef CONFIG_SPL_BUILD  COBJS-$(CONFIG_USB_TTY) += usbtty.o diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index 9f0464355..daa80038a 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 000000000..0443b8427 --- /dev/null +++ b/drivers/serial/serial_bfin.c @@ -0,0 +1,411 @@ +/* + * U-boot - serial.c Blackfin Serial Driver + * + * Copyright (c) 2005-2008 Analog Devices Inc. + * + * Copyright (c) 2003	Bas Vermeulen <bas@buyways.nl>, + *			BuyWays B.V. (www.buyways.nl) + * + * Based heavily on: + * blkfinserial.c: Serial driver for BlackFin DSP internal USRTs. + * Copyright(c) 2003	Metrowerks	<mwaddel@metrowerks.com> + * Copyright(c)	2001	Tony Z. Kou	<tonyko@arcturusnetworks.com> + * Copyright(c)	2001-2002 Arcturus Networks Inc. <www.arcturusnetworks.com> + * + * Based on code from 68328 version serial driver imlpementation which was: + * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu> + * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com> + * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org> + * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com> + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Licensed under the GPL-2 or later. + */ + +/* Anomaly notes: + *  05000086 - we don't support autobaud + *  05000099 - we only use DR bit, so losing others is not a problem + *  05000100 - we don't use the UART_IIR register + *  05000215 - we poll the uart (no dma/interrupts) + *  05000225 - no workaround possible, but this shouldnt cause errors ... + *  05000230 - we tweak the baud rate calculation slightly + *  05000231 - we always use 1 stop bit + *  05000309 - we always enable the uart before we modify it in anyway + *  05000350 - we always enable the uart regardless of boot mode + *  05000363 - we don't support break signals, so don't generate one + */ + +#include <common.h> +#include <post.h> +#include <watchdog.h> +#include <serial.h> +#include <linux/compiler.h> +#include <asm/blackfin.h> +#include <asm/serial.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_UART_CONSOLE + +#ifdef CONFIG_DEBUG_SERIAL +static uart_lsr_t cached_lsr[256]; +static uart_lsr_t cached_rbr[256]; +static size_t cache_count; + +/* The LSR is read-to-clear on some parts, so we have to make sure status + * bits aren't inadvertently lost when doing various tests.  This also + * works around anomaly 05000099 at the same time by keeping a cumulative + * tally of all the status bits. + */ +static uart_lsr_t uart_lsr_save; +static uart_lsr_t uart_lsr_read(uint32_t uart_base) +{ +	uart_lsr_t lsr = _lsr_read(pUART); +	uart_lsr_save |= (lsr & (OE|PE|FE|BI)); +	return lsr | uart_lsr_save; +} +/* Just do the clear for everyone since it can't hurt. */ +static void uart_lsr_clear(uint32_t uart_base) +{ +	uart_lsr_save = 0; +	_lsr_write(pUART, -1); +} +#else +/* When debugging is disabled, we only care about the DR bit, so if other + * bits get set/cleared, we don't really care since we don't read them + * anyways (and thus anomaly 05000099 is irrelevant). + */ +static inline uart_lsr_t uart_lsr_read(uint32_t uart_base) +{ +	return _lsr_read(pUART); +} +static void uart_lsr_clear(uint32_t uart_base) +{ +	_lsr_write(pUART, -1); +} +#endif + +static void uart_putc(uint32_t uart_base, const char c) +{ +	/* send a \r for compatibility */ +	if (c == '\n') +		serial_putc('\r'); + +	WATCHDOG_RESET(); + +	/* wait for the hardware fifo to clear up */ +	while (!(uart_lsr_read(uart_base) & THRE)) +		continue; + +	/* queue the character for transmission */ +	bfin_write(&pUART->thr, c); +	SSYNC(); + +	WATCHDOG_RESET(); +} + +static int uart_tstc(uint32_t uart_base) +{ +	WATCHDOG_RESET(); +	return (uart_lsr_read(uart_base) & DR) ? 1 : 0; +} + +static int uart_getc(uint32_t uart_base) +{ +	uint16_t uart_rbr_val; + +	/* wait for data ! */ +	while (!uart_tstc(uart_base)) +		continue; + +	/* grab the new byte */ +	uart_rbr_val = bfin_read(&pUART->rbr); + +#ifdef CONFIG_DEBUG_SERIAL +	/* grab & clear the LSR */ +	uart_lsr_t uart_lsr_val = uart_lsr_read(uart_base); + +	cached_lsr[cache_count] = uart_lsr_val; +	cached_rbr[cache_count] = uart_rbr_val; +	cache_count = (cache_count + 1) % ARRAY_SIZE(cached_lsr); + +	if (uart_lsr_val & (OE|PE|FE|BI)) { +		printf("\n[SERIAL ERROR]\n"); +		do { +			--cache_count; +			printf("\t%3zu: RBR=0x%02x LSR=0x%02x\n", cache_count, +				cached_rbr[cache_count], cached_lsr[cache_count]); +		} while (cache_count > 0); +		return -1; +	} +#endif +	uart_lsr_clear(uart_base); + +	return uart_rbr_val; +} + +#if CONFIG_POST & CONFIG_SYS_POST_UART +# define LOOP(x) x +#else +# define LOOP(x) +#endif + +#if BFIN_UART_HW_VER < 4 + +LOOP( +static void uart_loop(uint32_t uart_base, int state) +{ +	u16 mcr; + +	/* Drain the TX fifo first so bytes don't come back */ +	while (!(uart_lsr_read(uart_base) & TEMT)) +		continue; + +	mcr = bfin_read(&pUART->mcr); +	if (state) +		mcr |= LOOP_ENA | MRTS; +	else +		mcr &= ~(LOOP_ENA | MRTS); +	bfin_write(&pUART->mcr, mcr); +} +) + +#else + +LOOP( +static void uart_loop(uint32_t uart_base, int state) +{ +	u32 control; + +	/* Drain the TX fifo first so bytes don't come back */ +	while (!(uart_lsr_read(uart_base) & TEMT)) +		continue; + +	control = bfin_read(&pUART->control); +	if (state) +		control |= LOOP_ENA | MRTS; +	else +		control &= ~(LOOP_ENA | MRTS); +	bfin_write(&pUART->control, control); +} +) + +#endif + +static inline void __serial_set_baud(uint32_t uart_base, uint32_t baud) +{ +#ifdef CONFIG_DEBUG_EARLY_SERIAL +	serial_early_set_baud(uart_base, baud); +#else +	uint16_t divisor = (get_uart_clk() + (baud * 8)) / (baud * 16) +			- ANOMALY_05000230; + +	/* Program the divisor to get the baud rate we want */ +	serial_set_divisor(uart_base, divisor); +#endif +} + +static void uart_puts(uint32_t uart_base, const char *s) +{ +	while (*s) +		uart_putc(uart_base, *s++); +} + +#define DECL_BFIN_UART(n) \ +static int uart##n##_init(void) \ +{ \ +	const unsigned short pins[] = { _P_UART(n, RX), _P_UART(n, TX), 0, }; \ +	peripheral_request_list(pins, "bfin-uart"); \ +	uart_init(MMR_UART(n)); \ +	__serial_set_baud(MMR_UART(n), gd->baudrate); \ +	uart_lsr_clear(MMR_UART(n)); \ +	return 0; \ +} \ +\ +static int uart##n##_uninit(void) \ +{ \ +	return serial_early_uninit(MMR_UART(n)); \ +} \ +\ +static void uart##n##_setbrg(void) \ +{ \ +	__serial_set_baud(MMR_UART(n), gd->baudrate); \ +} \ +\ +static int uart##n##_getc(void) \ +{ \ +	return uart_getc(MMR_UART(n)); \ +} \ +\ +static int uart##n##_tstc(void) \ +{ \ +	return uart_tstc(MMR_UART(n)); \ +} \ +\ +static void uart##n##_putc(const char c) \ +{ \ +	uart_putc(MMR_UART(n), c); \ +} \ +\ +static void uart##n##_puts(const char *s) \ +{ \ +	uart_puts(MMR_UART(n), s); \ +} \ +\ +LOOP( \ +static void uart##n##_loop(int state) \ +{ \ +	uart_loop(MMR_UART(n), state); \ +} \ +) \ +\ +struct serial_device bfin_serial##n##_device = { \ +	.name   = "bfin_uart"#n, \ +	.start  = uart##n##_init, \ +	.stop   = uart##n##_uninit, \ +	.setbrg = uart##n##_setbrg, \ +	.getc   = uart##n##_getc, \ +	.tstc   = uart##n##_tstc, \ +	.putc   = uart##n##_putc, \ +	.puts   = uart##n##_puts, \ +	LOOP(.loop = uart##n##_loop) \ +}; + +#ifdef UART0_RBR +DECL_BFIN_UART(0) +#endif +#ifdef UART1_RBR +DECL_BFIN_UART(1) +#endif +#ifdef UART2_RBR +DECL_BFIN_UART(2) +#endif +#ifdef UART3_RBR +DECL_BFIN_UART(3) +#endif + +__weak struct serial_device *default_serial_console(void) +{ +#if CONFIG_UART_CONSOLE == 0 +	return &bfin_serial0_device; +#elif CONFIG_UART_CONSOLE == 1 +	return &bfin_serial1_device; +#elif CONFIG_UART_CONSOLE == 2 +	return &bfin_serial2_device; +#elif CONFIG_UART_CONSOLE == 3 +	return &bfin_serial3_device; +#endif +} + +void bfin_serial_initialize(void) +{ +#ifdef UART0_RBR +	serial_register(&bfin_serial0_device); +#endif +#ifdef UART1_RBR +	serial_register(&bfin_serial1_device); +#endif +#ifdef UART2_RBR +	serial_register(&bfin_serial2_device); +#endif +#ifdef UART3_RBR +	serial_register(&bfin_serial3_device); +#endif +} + +#ifdef CONFIG_DEBUG_EARLY_SERIAL +inline void uart_early_putc(uint32_t uart_base, const char c) +{ +	/* send a \r for compatibility */ +	if (c == '\n') +		uart_early_putc(uart_base, '\r'); + +	/* wait for the hardware fifo to clear up */ +	while (!(_lsr_read(pUART) & THRE)) +		continue; + +	/* queue the character for transmission */ +	bfin_write(&pUART->thr, c); +	SSYNC(); +} + +void uart_early_puts(const char *s) +{ +	while (*s) +		uart_early_putc(UART_BASE, *s++); +} + +/* Symbol for our assembly to call. */ +void _serial_early_set_baud(uint32_t baud) +{ +	serial_early_set_baud(UART_BASE, baud); +} + +/* Symbol for our assembly to call. */ +void _serial_early_init(void) +{ +	serial_early_init(UART_BASE); +} +#endif + +#elif defined(CONFIG_UART_MEM) + +char serial_logbuf[CONFIG_UART_MEM]; +char *serial_logbuf_head = serial_logbuf; + +int serial_mem_init(void) +{ +	serial_logbuf_head = serial_logbuf; +	return 0; +} + +void serial_mem_setbrg(void) +{ +} + +int serial_mem_tstc(void) +{ +	return 0; +} + +int serial_mem_getc(void) +{ +	return 0; +} + +void serial_mem_putc(const char c) +{ +	*serial_logbuf_head = c; +	if (++serial_logbuf_head == serial_logbuf + CONFIG_UART_MEM) +		serial_logbuf_head = serial_logbuf; +} + +void serial_mem_puts(const char *s) +{ +	while (*s) +		serial_putc(*s++); +} + +struct serial_device bfin_serial_mem_device = { +	.name   = "bfin_uart_mem", +	.start  = serial_mem_init, +	.setbrg = serial_mem_setbrg, +	.getc   = serial_mem_getc, +	.tstc   = serial_mem_tstc, +	.putc   = serial_mem_putc, +	.puts   = serial_mem_puts, +}; + + +__weak struct serial_device *default_serial_console(void) +{ +	return &bfin_serial_mem_device; +} + +void bfin_serial_initialize(void) +{ +	serial_register(&bfin_serial_mem_device); +} +#endif /* CONFIG_UART_MEM */ diff --git a/drivers/spi/bfin_spi.c b/drivers/spi/bfin_spi.c index ab2e8b998..a9a4d92c3 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 fd8f8a760..685702e8e 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 c81687820..e0f3e4b6c 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 086cd0fe5..2060a3eb4 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -60,7 +60,7 @@ int usb_cpu_init(void)  	writel(1 << ATMEL_ID_UHP, &pmc->pcer);  #endif -#ifdef CONFIG_AT91SAM9261 +#if defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10)  	writel(ATMEL_PMC_UHP | AT91_PMC_HCK0, &pmc->scer);  #else  	writel(ATMEL_PMC_UHP, &pmc->scer); @@ -80,7 +80,7 @@ int usb_cpu_stop(void)  	writel(1 << ATMEL_ID_UHP, &pmc->pcdr);  #endif -#ifdef CONFIG_AT91SAM9261 +#if defined(CONFIG_AT91SAM9261) || defined(CONFIG_AT91SAM9G10)  	writel(ATMEL_PMC_UHP | AT91_PMC_HCK0, &pmc->scdr);  #else  	writel(ATMEL_PMC_UHP, &pmc->scdr); diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 13e7c3768..d57578df6 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -33,6 +33,7 @@ endif  COBJS-$(CONFIG_TNETV107X_WATCHDOG) += tnetv107x_wdt.o  COBJS-$(CONFIG_S5P)               += s5p_wdt.o  COBJS-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o +COBJS-$(CONFIG_BFIN_WATCHDOG)  += bfin_wdt.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c new file mode 100644 index 000000000..7a6756b2e --- /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); +} |