diff options
| author | Wolfgang Denk <wd@denx.de> | 2011-02-02 21:57:19 +0100 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2011-02-02 21:57:19 +0100 | 
| commit | be9db564de898240034151c48cf9e0d03ece3f35 (patch) | |
| tree | f87b02a573c61fdab3f190de09e6b0c8061f446b /drivers | |
| parent | 89ffa8dbb5bd0552f5f3399f4430a4c97f4d50d4 (diff) | |
| parent | 9e40808c3fe0237a8d49f10394d3a8e4e29540a6 (diff) | |
| download | olio-uboot-2014.01-be9db564de898240034151c48cf9e0d03ece3f35.tar.xz olio-uboot-2014.01-be9db564de898240034151c48cf9e0d03ece3f35.zip | |
Merge branch 'master' of /home/wd/git/u-boot/custodians
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/block/Makefile | 1 | ||||
| -rw-r--r-- | drivers/block/mxc_ata.c | 146 | ||||
| -rw-r--r-- | drivers/gpio/mxc_gpio.c | 9 | ||||
| -rw-r--r-- | drivers/i2c/mxc_i2c.c | 172 | ||||
| -rw-r--r-- | drivers/misc/Makefile | 5 | ||||
| -rw-r--r-- | drivers/misc/fsl_pmic.c | 45 | ||||
| -rw-r--r-- | drivers/misc/mc9sdz60.c | 51 | ||||
| -rw-r--r-- | drivers/mmc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mmc/davinci_mmc.c | 404 | ||||
| -rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 6 | ||||
| -rw-r--r-- | drivers/net/davinci_emac.c | 15 | ||||
| -rw-r--r-- | drivers/net/fec_mxc.c | 2 | ||||
| -rw-r--r-- | drivers/net/fec_mxc.h | 4 | ||||
| -rw-r--r-- | drivers/serial/serial_mxc.c | 9 | ||||
| -rw-r--r-- | drivers/serial/serial_s5p.c | 2 | ||||
| -rw-r--r-- | drivers/spi/mxc_spi.c | 200 | 
16 files changed, 920 insertions, 152 deletions
| diff --git a/drivers/block/Makefile b/drivers/block/Makefile index e27175bb4..aa7dc877c 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -31,6 +31,7 @@ COBJS-$(CONFIG_FSL_SATA) += fsl_sata.o  COBJS-$(CONFIG_LIBATA) += libata.o  COBJS-$(CONFIG_CMD_MG_DISK) += mg_disk.o  COBJS-$(CONFIG_MVSATA_IDE) += mvsata_ide.o +COBJS-$(CONFIG_MX51_PATA) += mxc_ata.o  COBJS-$(CONFIG_PATA_BFIN) += pata_bfin.o  COBJS-$(CONFIG_SATA_DWC) += sata_dwc.o  COBJS-$(CONFIG_SATA_SIL3114) += sata_sil3114.o diff --git a/drivers/block/mxc_ata.c b/drivers/block/mxc_ata.c new file mode 100644 index 000000000..f22f4f40b --- /dev/null +++ b/drivers/block/mxc_ata.c @@ -0,0 +1,146 @@ +/* + * Freescale iMX51 ATA driver + * + * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com> + * + * Based on code by: + *	Mahesh Mahadevan <mahesh.mahadevan@freescale.com> + * + * Based on code from original FSL ATA driver, which is + * part of eCos, the Embedded Configurable Operating System. + * Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <config.h> +#include <asm/byteorder.h> +#include <asm/io.h> +#include <ide.h> + +#include <asm/arch/imx-regs.h> +#include <asm/arch/clock.h> + +/* MXC ATA register offsets */ +struct mxc_ata_config_regs { +	u8	time_off;	/* 0x00 */ +	u8	time_on; +	u8	time_1; +	u8	time_2w; +	u8	time_2r; +	u8	time_ax; +	u8	time_pio_rdx; +	u8	time_4; +	u8	time_9; +	u8	time_m; +	u8	time_jn; +	u8	time_d; +	u8	time_k; +	u8	time_ack; +	u8	time_env; +	u8	time_udma_rdx; +	u8	time_zah;	/* 0x10 */ +	u8	time_mlix; +	u8	time_dvh; +	u8	time_dzfs; +	u8	time_dvs; +	u8	time_cvh; +	u8	time_ss; +	u8	time_cyc; +	u32	fifo_data_32;	/* 0x18 */ +	u32	fifo_data_16; +	u32	fifo_fill; +	u32	ata_control; +	u32	interrupt_pending; +	u32	interrupt_enable; +	u32	interrupt_clear; +	u32	fifo_alarm; +}; + +struct mxc_data_hdd_regs { +	u32	drive_data;	/* 0xa0 */ +	u32	drive_features; +	u32	drive_sector_count; +	u32	drive_sector_num; +	u32	drive_cyl_low; +	u32	drive_cyl_high; +	u32	drive_dev_head; +	u32	command; +	u32	status; +	u32	alt_status; +}; + +/* PIO timing table */ +#define	NR_PIO_SPECS	5 +static uint16_t pio_t1[NR_PIO_SPECS]	= { 70,  50,  30,  30,  25 }; +static uint16_t pio_t2_8[NR_PIO_SPECS]	= { 290, 290, 290, 80,  70 }; +static uint16_t pio_t4[NR_PIO_SPECS]	= { 30,  20,  15,  10,  10 }; +static uint16_t pio_t9[NR_PIO_SPECS]	= { 20,  15,  10,  10,  10 }; +static uint16_t pio_tA[NR_PIO_SPECS]	= { 50,  50,  50,  50,  50 }; + +#define	REG2OFF(reg)	((((uint32_t)reg) & 0x3) * 8) +static void set_ata_bus_timing(unsigned char mode) +{ +	uint32_t val; +	uint32_t T = 1000000000 / mxc_get_clock(MXC_IPG_CLK); + +	struct mxc_ata_config_regs *ata_regs; +	ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR; + +	if (mode >= NR_PIO_SPECS) +		return; + +	/* Write TIME_OFF/ON/1/2W */ +	val =	(3 << REG2OFF(&ata_regs->time_off)) | +		(3 << REG2OFF(&ata_regs->time_on)) | +		(((pio_t1[mode] + T) / T) << REG2OFF(&ata_regs->time_1)) | +		(((pio_t2_8[mode] + T) / T) << REG2OFF(&ata_regs->time_2w)); +	writel(val, &ata_regs->time_off); + +	/* Write TIME_2R/AX/RDX/4 */ +	val =	(((pio_t2_8[mode] + T) / T) << REG2OFF(&ata_regs->time_2r)) | +		(((pio_tA[mode] + T) / T + 2) << REG2OFF(&ata_regs->time_ax)) | +		(1 << REG2OFF(&ata_regs->time_pio_rdx)) | +		(((pio_t4[mode] + T) / T) << REG2OFF(&ata_regs->time_4)); +	writel(val, &ata_regs->time_2r); + +	/* Write TIME_9 ; the rest of timing registers is irrelevant for PIO */ +	val =	(((pio_t9[mode] + T) / T) << REG2OFF(&ata_regs->time_9)); +	writel(val, &ata_regs->time_9); +} + +int ide_preinit(void) +{ +	struct mxc_ata_config_regs *ata_regs; +	ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR; + +	/* 46.3.3.4 @ FSL iMX51 manual */ +	/* FIFO normal op., drive reset */ +	writel(0x80, &ata_regs->ata_control); +	/* FIFO normal op., drive not reset */ +	writel(0xc0, &ata_regs->ata_control); + +	/* Configure the PIO timing */ +	set_ata_bus_timing(CONFIG_MXC_ATA_PIO_MODE); + +	/* 46.3.3.4 @ FSL iMX51 manual */ +	/* Drive not reset, IORDY handshake */ +	writel(0x41, &ata_regs->ata_control); + +	return 0; +} diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c index 663141f1b..53a067341 100644 --- a/drivers/gpio/mxc_gpio.c +++ b/drivers/gpio/mxc_gpio.c @@ -24,7 +24,7 @@  #ifdef CONFIG_MX31  #include <asm/arch/mx31-regs.h>  #endif -#ifdef CONFIG_MX51 +#if defined(CONFIG_MX51) || defined(CONFIG_MX53)  #include <asm/arch/imx-regs.h>  #endif  #include <asm/io.h> @@ -35,9 +35,14 @@ static unsigned long gpio_ports[] = {  	[0] = GPIO1_BASE_ADDR,  	[1] = GPIO2_BASE_ADDR,  	[2] = GPIO3_BASE_ADDR, -#ifdef CONFIG_MX51 +#if defined(CONFIG_MX51) || defined(CONFIG_MX53)  	[3] = GPIO4_BASE_ADDR,  #endif +#if defined(CONFIG_MX53) +	[4] = GPIO5_BASE_ADDR, +	[5] = GPIO6_BASE_ADDR, +	[6] = GPIO7_BASE_ADDR, +#endif  };  int mxc_gpio_direction(unsigned int gpio, enum mxc_gpio_direction direction) diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 8e10fbb21..c5ec486a7 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -23,11 +23,17 @@   */  #include <common.h> +#include <asm/io.h>  #if defined(CONFIG_HARD_I2C) +#if defined(CONFIG_MX31)  #include <asm/arch/mx31.h>  #include <asm/arch/mx31-regs.h> +#else +#include <asm/arch/imx-regs.h> +#include <asm/arch/clock.h> +#endif  #define IADR	0x00  #define IFDR	0x04 @@ -47,7 +53,7 @@  #define I2SR_IIF	(1 << 1)  #define I2SR_RX_NO_AK	(1 << 0) -#ifdef CONFIG_SYS_I2C_MX31_PORT1 +#if defined(CONFIG_SYS_I2C_MX31_PORT1)  #define I2C_BASE	0x43f80000  #define I2C_CLK_OFFSET	26  #elif defined (CONFIG_SYS_I2C_MX31_PORT2) @@ -56,130 +62,205 @@  #elif defined (CONFIG_SYS_I2C_MX31_PORT3)  #define I2C_BASE	0x43f84000  #define I2C_CLK_OFFSET	30 +#elif defined(CONFIG_SYS_I2C_MX53_PORT1) +#define I2C_BASE        I2C1_BASE_ADDR +#elif defined(CONFIG_SYS_I2C_MX53_PORT2) +#define I2C_BASE        I2C2_BASE_ADDR +#elif defined(CONFIG_SYS_I2C_MX35_PORT1) +#define I2C_BASE	I2C_BASE_ADDR  #else -#error "define CONFIG_SYS_I2C_MX31_PORTx to use the mx31 I2C driver" +#error "define CONFIG_SYS_I2C_MX<Processor>_PORTx to use the mx I2C driver"  #endif -#ifdef DEBUG -#define DPRINTF(args...)  printf(args) -#else -#define DPRINTF(args...) -#endif +#define I2C_MAX_TIMEOUT		10000 +#define I2C_MAX_RETRIES		3  static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144,  	             160, 192, 240, 288, 320, 384, 480, 576, 640, 768, 960,  	             1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840}; +static inline void i2c_reset(void) +{ +	writew(0, I2C_BASE + I2CR);	/* Reset module */ +	writew(0, I2C_BASE + I2SR); +	writew(I2CR_IEN, I2C_BASE + I2CR); +} +  void i2c_init(int speed, int unused)  { -	int freq = mx31_get_ipg_clk(); +	int freq;  	int i; +#if defined(CONFIG_MX31) +	struct clock_control_regs *sc_regs = +		(struct clock_control_regs *)CCM_BASE; + +	freq = mx31_get_ipg_clk();  	/* start the required I2C clock */ -	__REG(CCM_CGR0) = __REG(CCM_CGR0) | (3 << I2C_CLK_OFFSET); +	writel(readl(&sc_regs->cgr0) | (3 << I2C_CLK_OFFSET), +		&sc_regs->cgr0); +#else +	freq = mxc_get_clock(MXC_IPG_PERCLK); +#endif  	for (i = 0; i < 0x1f; i++)  		if (freq / div[i] <= speed)  			break; -	DPRINTF("%s: speed: %d\n",__FUNCTION__, speed); +	debug("%s: speed: %d\n", __func__, speed); -	__REG16(I2C_BASE + I2CR) = 0; /* Reset module */ -	__REG16(I2C_BASE + IFDR) = i; -	__REG16(I2C_BASE + I2CR) = I2CR_IEN; -	__REG16(I2C_BASE + I2SR) = 0; +	writew(i, I2C_BASE + IFDR); +	i2c_reset(); +} + +static int wait_idle(void) +{ +	int timeout = I2C_MAX_TIMEOUT; + +	while ((readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout) { +		writew(0, I2C_BASE + I2SR); +		udelay(1); +	} +	return timeout ? timeout : (!(readw(I2C_BASE + I2SR) & I2SR_IBB));  }  static int wait_busy(void)  { -	int timeout = 10000; +	int timeout = I2C_MAX_TIMEOUT; -	while (!(__REG16(I2C_BASE + I2SR) & I2SR_IIF) && --timeout) +	while (!(readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout)  		udelay(1); -	__REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ +	writew(0, I2C_BASE + I2SR); /* clear interrupt */  	return timeout;  } +static int wait_complete(void) +{ +	int timeout = I2C_MAX_TIMEOUT; + +	while ((!(readw(I2C_BASE + I2SR) & I2SR_ICF)) && (--timeout)) { +		writew(0, I2C_BASE + I2SR); +		udelay(1); +	} +	udelay(200); + +	writew(0, I2C_BASE + I2SR);	/* clear interrupt */ + +	return timeout; +} + +  static int tx_byte(u8 byte)  { -	__REG16(I2C_BASE + I2DR) = byte; +	writew(byte, I2C_BASE + I2DR); -	if (!wait_busy() || __REG16(I2C_BASE + I2SR) & I2SR_RX_NO_AK) +	if (!wait_complete() || readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)  		return -1;  	return 0;  } -static int rx_byte(void) +static int rx_byte(int last)  { -	if (!wait_busy()) +	if (!wait_complete())  		return -1; -	return __REG16(I2C_BASE + I2DR); +	if (last) +		writew(I2CR_IEN, I2C_BASE + I2CR); + +	return readw(I2C_BASE + I2DR);  }  int i2c_probe(uchar chip)  {  	int ret; -	__REG16(I2C_BASE + I2CR) = 0; /* Reset module */ -	__REG16(I2C_BASE + I2CR) = I2CR_IEN; +	writew(0, I2C_BASE + I2CR); /* Reset module */ +	writew(I2CR_IEN, I2C_BASE + I2CR); -	__REG16(I2C_BASE + I2CR) = I2CR_IEN |  I2CR_MSTA | I2CR_MTX; +	writew(I2CR_IEN |  I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR);  	ret = tx_byte(chip << 1); -	__REG16(I2C_BASE + I2CR) = I2CR_IEN | I2CR_MTX; +	writew(I2CR_IEN | I2CR_MTX, I2C_BASE + I2CR);  	return ret;  }  static int i2c_addr(uchar chip, uint addr, int alen)  { -	__REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ -	__REG16(I2C_BASE + I2CR) = I2CR_IEN |  I2CR_MSTA | I2CR_MTX; +	int i, retry = 0; +	for (retry = 0; retry < 3; retry++) { +		if (wait_idle()) +			break; +		i2c_reset(); +		for (i = 0; i < I2C_MAX_TIMEOUT; i++) +			udelay(1); +	} +	if (retry >= I2C_MAX_RETRIES) { +		debug("%s:bus is busy(%x)\n", +		       __func__, readw(I2C_BASE + I2SR)); +		return -1; +	} +	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR); -	if (tx_byte(chip << 1)) +	if (!wait_busy()) { +		debug("%s:trigger start fail(%x)\n", +		       __func__, readw(I2C_BASE + I2SR));  		return -1; +	} +	if (tx_byte(chip << 1) || (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) { +		debug("%s:chip address cycle fail(%x)\n", +		       __func__, readw(I2C_BASE + I2SR)); +		return -1; +	}  	while (alen--) -		if (tx_byte((addr >> (alen * 8)) & 0xff)) +		if (tx_byte((addr >> (alen * 8)) & 0xff) || +		    (readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK)) { +			debug("%s:device address cycle fail(%x)\n", +			       __func__, readw(I2C_BASE + I2SR));  			return -1; +		}  	return 0;  }  int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)  { -	int timeout = 10000; +	int timeout = I2C_MAX_TIMEOUT;  	int ret; -	DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",__FUNCTION__, chip, addr, alen, len); +	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n", +		__func__, chip, addr, alen, len);  	if (i2c_addr(chip, addr, alen)) {  		printf("i2c_addr failed\n");  		return -1;  	} -	__REG16(I2C_BASE + I2CR) = I2CR_IEN |  I2CR_MSTA | I2CR_MTX | I2CR_RSTA; +	writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX | I2CR_RSTA, I2C_BASE + I2CR);  	if (tx_byte(chip << 1 | 1))  		return -1; -	__REG16(I2C_BASE + I2CR) = I2CR_IEN |  I2CR_MSTA | ((len == 1) ? I2CR_TX_NO_AK : 0); +	writew(I2CR_IEN | I2CR_MSTA | +		((len == 1) ? I2CR_TX_NO_AK : 0), +		I2C_BASE + I2CR); -	ret = __REG16(I2C_BASE + I2DR); +	ret = readw(I2C_BASE + I2DR);  	while (len--) { -		if ((ret = rx_byte()) < 0) +		ret = rx_byte(len == 0); +		if (ret  < 0)  			return -1;  		*buf++ = ret;  		if (len <= 1) -			__REG16(I2C_BASE + I2CR) = I2CR_IEN |  I2CR_MSTA | I2CR_TX_NO_AK; +			writew(I2CR_IEN | I2CR_MSTA | +				I2CR_TX_NO_AK, +				I2C_BASE + I2CR);  	} -	wait_busy(); - -	__REG16(I2C_BASE + I2CR) = I2CR_IEN; +	writew(I2CR_IEN, I2C_BASE + I2CR); -	while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout) +	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)  		udelay(1);  	return 0; @@ -187,8 +268,9 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)  int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)  { -	int timeout = 10000; -	DPRINTF("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n",__FUNCTION__, chip, addr, alen, len); +	int timeout = I2C_MAX_TIMEOUT; +	debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n", +		__func__, chip, addr, alen, len);  	if (i2c_addr(chip, addr, alen))  		return -1; @@ -197,9 +279,9 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)  		if (tx_byte(*buf++))  			return -1; -	__REG16(I2C_BASE + I2CR) = I2CR_IEN; +	writew(I2CR_IEN, I2C_BASE + I2CR); -	while (__REG16(I2C_BASE + I2SR) & I2SR_IBB && --timeout) +	while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout)  		udelay(1);  	return 0; diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index a76bd4e58..b15248611 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -28,12 +28,13 @@ LIB	:= $(obj)libmisc.o  COBJS-$(CONFIG_ALI152X) += ali512x.o  COBJS-$(CONFIG_DS4510)  += ds4510.o  COBJS-$(CONFIG_FSL_LAW) += fsl_law.o +COBJS-$(CONFIG_FSL_PMIC) += fsl_pmic.o  COBJS-$(CONFIG_GPIO_LED) += gpio_led.o +COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o  COBJS-$(CONFIG_NS87308) += ns87308.o +COBJS-$(CONFIG_PDSP188x) += pdsp188x.o  COBJS-$(CONFIG_STATUS_LED) += status_led.o  COBJS-$(CONFIG_TWL4030_LED) += twl4030_led.o -COBJS-$(CONFIG_FSL_PMIC) += fsl_pmic.o -COBJS-$(CONFIG_PDSP188x) += pdsp188x.o  COBJS	:= $(COBJS-y)  SRCS	:= $(COBJS:.o=.c) diff --git a/drivers/misc/fsl_pmic.c b/drivers/misc/fsl_pmic.c index 5ee1de176..ef80ad949 100644 --- a/drivers/misc/fsl_pmic.c +++ b/drivers/misc/fsl_pmic.c @@ -22,11 +22,48 @@  #include <config.h>  #include <common.h> -#include <spi.h>  #include <asm/errno.h>  #include <linux/types.h>  #include <fsl_pmic.h> +static int check_param(u32 reg, u32 write) +{ +	if (reg > 63 || write > 1) { +		printf("<reg num> = %d is invalid. Should be less then 63\n", +			reg); +		return -1; +	} + +	return 0; +} + +#ifdef CONFIG_FSL_PMIC_I2C +#include <i2c.h> + +u32 pmic_reg(u32 reg, u32 val, u32 write) +{ +	unsigned char buf[4] = { 0 }; +	u32 ret_val = 0; + +	if (check_param(reg, write)) +		return -1; + +	if (write) { +		buf[0] = (val >> 16) & 0xff; +		buf[1] = (val >> 8) & 0xff; +		buf[2] = (val) & 0xff; +		if (i2c_write(CONFIG_SYS_FSL_PMIC_I2C_ADDR, reg, 1, buf, 3)) +			return -1; +	} else { +		if (i2c_read(CONFIG_SYS_FSL_PMIC_I2C_ADDR, reg, 1, buf, 3)) +			return -1; +		ret_val = buf[0] << 16 | buf[1] << 8 | buf[2]; +	} + +	return ret_val; +} +#else /* SPI interface */ +#include <spi.h>  static struct spi_slave *slave;  struct spi_slave *pmic_spi_probe(void) @@ -55,11 +92,8 @@ u32 pmic_reg(u32 reg, u32 val, u32 write)  			return -1;  	} -	if (reg > 63 || write > 1) { -		printf("<reg num> = %d is invalid. Should be less then 63\n", -			reg); +	if (check_param(reg, write))  		return -1; -	}  	if (spi_claim_bus(slave))  		return -1; @@ -87,6 +121,7 @@ u32 pmic_reg(u32 reg, u32 val, u32 write)  	spi_release_bus(slave);  	return cpu_to_be32(pmic_rx);  } +#endif  void pmic_reg_write(u32 reg, u32 value)  { diff --git a/drivers/misc/mc9sdz60.c b/drivers/misc/mc9sdz60.c new file mode 100644 index 000000000..439d5a639 --- /dev/null +++ b/drivers/misc/mc9sdz60.c @@ -0,0 +1,51 @@ +/* + * (C) Copyright 2010 Stefano Babic <sbabic@denx.de> + * + * 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 <asm/errno.h> +#include <linux/types.h> +#include <i2c.h> +#include <mc9sdz60.h> + +#ifndef CONFIG_SYS_FSL_MC9SDZ60_I2C_ADDR +#error "You have to configure I2C address for MC9SDZ60" +#endif + + +u8 mc9sdz60_reg_read(enum mc9sdz60_reg reg) +{ +	u8 val; + +	if (i2c_read(CONFIG_SYS_FSL_MC9SDZ60_I2C_ADDR, reg, 1, &val, 1)) { +		puts("Error reading MC9SDZ60 register\n"); +		return -1; +	} + +	return val; +} + +void mc9sdz60_reg_write(enum mc9sdz60_reg reg, u8 val) +{ +	i2c_write(CONFIG_SYS_FSL_MC9SDZ60_I2C_ADDR, reg, 1, &val, 1); +} diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 68afd30ef..3496f0aa0 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -27,6 +27,7 @@ LIB	:= $(obj)libmmc.o  COBJS-$(CONFIG_ATMEL_MCI) += atmel_mci.o  COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o +COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o  COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o  COBJS-$(CONFIG_GENERIC_MMC) += mmc.o  COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o diff --git a/drivers/mmc/davinci_mmc.c b/drivers/mmc/davinci_mmc.c new file mode 100644 index 000000000..4e572dc53 --- /dev/null +++ b/drivers/mmc/davinci_mmc.c @@ -0,0 +1,404 @@ +/* + * Davinci MMC Controller Driver + * + * Copyright (C) 2010 Texas Instruments Incorporated + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <config.h> +#include <common.h> +#include <command.h> +#include <mmc.h> +#include <part.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/arch/sdmmc_defs.h> + +#define DAVINCI_MAX_BLOCKS	(32) +#define WATCHDOG_COUNT		(100000) + +#define get_val(addr)		REG(addr) +#define set_val(addr, val)	REG(addr) = (val) +#define set_bit(addr, val)	set_val((addr), (get_val(addr) | (val))) +#define clear_bit(addr, val)	set_val((addr), (get_val(addr) & ~(val))) + +/* Set davinci clock prescalar value based on the required clock in HZ */ +static void dmmc_set_clock(struct mmc *mmc, uint clock) +{ +	struct davinci_mmc *host = mmc->priv; +	struct davinci_mmc_regs *regs = host->reg_base; +	uint clkrt, sysclk2, act_clock; + +	if (clock < mmc->f_min) +		clock = mmc->f_min; +	if (clock > mmc->f_max) +		clock = mmc->f_max; + +	set_val(®s->mmcclk, 0); +	sysclk2 = host->input_clk; +	clkrt = (sysclk2 / (2 * clock)) - 1; + +	/* Calculate the actual clock for the divider used */ +	act_clock = (sysclk2 / (2 * (clkrt + 1))); + +	/* Adjust divider if actual clock exceeds the required clock */ +	if (act_clock > clock) +		clkrt++; + +	/* check clock divider boundary and correct it */ +	if (clkrt > 0xFF) +		clkrt = 0xFF; + +	set_val(®s->mmcclk, (clkrt | MMCCLK_CLKEN)); +} + +/* Status bit wait loop for MMCST1 */ +static int +dmmc_wait_fifo_status(volatile struct davinci_mmc_regs *regs, uint status) +{ +	uint mmcstatus1, wdog = WATCHDOG_COUNT; +	mmcstatus1 = get_val(®s->mmcst1); +	while (--wdog && ((get_val(®s->mmcst1) & status) != status)) +		udelay(10); + +	if (!(get_val(®s->mmcctl) & MMCCTL_WIDTH_4_BIT)) +		udelay(100); + +	if (wdog == 0) +		return COMM_ERR; + +	return 0; +} + +/* Busy bit wait loop for MMCST1 */ +static int dmmc_busy_wait(volatile struct davinci_mmc_regs *regs) +{ +	uint mmcstatus1, wdog = WATCHDOG_COUNT; + +	mmcstatus1 = get_val(®s->mmcst1); +	while (--wdog && (get_val(®s->mmcst1) & MMCST1_BUSY)) +		udelay(10); + +	if (wdog == 0) +		return COMM_ERR; + +	return 0; +} + +/* Status bit wait loop for MMCST0 - Checks for error bits as well */ +static int dmmc_check_status(volatile struct davinci_mmc_regs *regs, +		uint *cur_st, uint st_ready, uint st_error) +{ +	uint wdog = WATCHDOG_COUNT; +	uint mmcstatus = *cur_st; + +	while (wdog--) { +		if (mmcstatus & st_ready) { +			*cur_st = mmcstatus; +			mmcstatus = get_val(®s->mmcst1); +			return 0; +		} else if (mmcstatus & st_error) { +			if (mmcstatus & MMCST0_TOUTRS) +				return TIMEOUT; +			printf("[ ST0 ERROR %x]\n", mmcstatus); +			/* +			 * Ignore CRC errors as some MMC cards fail to +			 * initialize on DM365-EVM on the SD1 slot +			 */ +			if (mmcstatus & MMCST0_CRCRS) +				return 0; +			return COMM_ERR; +		} +		udelay(10); + +		mmcstatus = get_val(®s->mmcst0); +	} + +	printf("Status %x Timeout ST0:%x ST1:%x\n", st_ready, mmcstatus, +			get_val(®s->mmcst1)); +	return COMM_ERR; +} + +/* + * Sends a command out on the bus.  Takes the mmc pointer, + * a command pointer, and an optional data pointer. + */ +static int +dmmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) +{ +	struct davinci_mmc *host = mmc->priv; +	volatile struct davinci_mmc_regs *regs = host->reg_base; +	uint mmcstatus, status_rdy, status_err; +	uint i, cmddata, bytes_left = 0; +	int fifo_words, fifo_bytes, err; +	char *data_buf = NULL; + +	/* Clear status registers */ +	mmcstatus = get_val(®s->mmcst0); +	fifo_words = (host->version == MMC_CTLR_VERSION_2) ? 16 : 8; +	fifo_bytes = fifo_words << 2; + +	/* Wait for any previous busy signal to be cleared */ +	dmmc_busy_wait(regs); + +	cmddata = cmd->cmdidx; +	cmddata |= MMCCMD_PPLEN; + +	/* Send init clock for CMD0 */ +	if (cmd->cmdidx == MMC_CMD_GO_IDLE_STATE) +		cmddata |= MMCCMD_INITCK; + +	switch (cmd->resp_type) { +	case MMC_RSP_R1b: +		cmddata |= MMCCMD_BSYEXP; +		/* Fall-through */ +	case MMC_RSP_R1:    /* R1, R1b, R5, R6, R7 */ +		cmddata |= MMCCMD_RSPFMT_R1567; +		break; +	case MMC_RSP_R2: +		cmddata |= MMCCMD_RSPFMT_R2; +		break; +	case MMC_RSP_R3: /* R3, R4 */ +		cmddata |= MMCCMD_RSPFMT_R3; +		break; +	} + +	set_val(®s->mmcim, 0); + +	if (data) { +		/* clear previous data transfer if any and set new one */ +		bytes_left = (data->blocksize * data->blocks); + +		/* Reset FIFO - Always use 32 byte fifo threshold */ +		set_val(®s->mmcfifoctl, +				(MMCFIFOCTL_FIFOLEV | MMCFIFOCTL_FIFORST)); + +		if (host->version == MMC_CTLR_VERSION_2) +			cmddata |= MMCCMD_DMATRIG; + +		cmddata |= MMCCMD_WDATX; +		if (data->flags == MMC_DATA_READ) { +			set_val(®s->mmcfifoctl, MMCFIFOCTL_FIFOLEV); +		} else if (data->flags == MMC_DATA_WRITE) { +			set_val(®s->mmcfifoctl, +					(MMCFIFOCTL_FIFOLEV | +					 MMCFIFOCTL_FIFODIR)); +			cmddata |= MMCCMD_DTRW; +		} + +		set_val(®s->mmctod, 0xFFFF); +		set_val(®s->mmcnblk, (data->blocks & MMCNBLK_NBLK_MASK)); +		set_val(®s->mmcblen, (data->blocksize & MMCBLEN_BLEN_MASK)); + +		if (data->flags == MMC_DATA_WRITE) { +			uint val; +			data_buf = (char *)data->src; +			/* For write, fill FIFO with data before issue of CMD */ +			for (i = 0; (i < fifo_words) && bytes_left; i++) { +				memcpy((char *)&val, data_buf, 4); +				set_val(®s->mmcdxr, val); +				data_buf += 4; +				bytes_left -= 4; +			} +		} +	} else { +		set_val(®s->mmcblen, 0); +		set_val(®s->mmcnblk, 0); +	} + +	set_val(®s->mmctor, 0x1FFF); + +	/* Send the command */ +	set_val(®s->mmcarghl, cmd->cmdarg); +	set_val(®s->mmccmd, cmddata); + +	status_rdy = MMCST0_RSPDNE; +	status_err = (MMCST0_TOUTRS | MMCST0_TOUTRD | +			MMCST0_CRCWR | MMCST0_CRCRD); +	if (cmd->resp_type & MMC_RSP_CRC) +		status_err |= MMCST0_CRCRS; + +	mmcstatus = get_val(®s->mmcst0); +	err = dmmc_check_status(regs, &mmcstatus, status_rdy, status_err); +	if (err) +		return err; + +	/* For R1b wait for busy done */ +	if (cmd->resp_type == MMC_RSP_R1b) +		dmmc_busy_wait(regs); + +	/* Collect response from controller for specific commands */ +	if (mmcstatus & MMCST0_RSPDNE) { +		/* Copy the response to the response buffer */ +		if (cmd->resp_type & MMC_RSP_136) { +			cmd->response[0] = get_val(®s->mmcrsp67); +			cmd->response[1] = get_val(®s->mmcrsp45); +			cmd->response[2] = get_val(®s->mmcrsp23); +			cmd->response[3] = get_val(®s->mmcrsp01); +		} else if (cmd->resp_type & MMC_RSP_PRESENT) { +			cmd->response[0] = get_val(®s->mmcrsp67); +		} +	} + +	if (data == NULL) +		return 0; + +	if (data->flags == MMC_DATA_READ) { +		/* check for DATDNE along with DRRDY as the controller might +		 * set the DATDNE without DRRDY for smaller transfers with +		 * less than FIFO threshold bytes +		 */ +		status_rdy = MMCST0_DRRDY | MMCST0_DATDNE; +		status_err = MMCST0_TOUTRD | MMCST0_CRCRD; +		data_buf = data->dest; +	} else { +		status_rdy = MMCST0_DXRDY | MMCST0_DATDNE; +		status_err = MMCST0_CRCWR; +	} + +	/* Wait until all of the blocks are transferred */ +	while (bytes_left) { +		err = dmmc_check_status(regs, &mmcstatus, status_rdy, +				status_err); +		if (err) +			return err; + +		if (data->flags == MMC_DATA_READ) { +			/* +			 * MMC controller sets the Data receive ready bit +			 * (DRRDY) in MMCST0 even before the entire FIFO is +			 * full. This results in erratic behavior if we start +			 * reading the FIFO soon after DRRDY.  Wait for the +			 * FIFO full bit in MMCST1 for proper FIFO clearing. +			 */ +			if (bytes_left > fifo_bytes) +				dmmc_wait_fifo_status(regs, 0x4a); +			else if (bytes_left == fifo_bytes) +				dmmc_wait_fifo_status(regs, 0x40); + +			for (i = 0; bytes_left && (i < fifo_words); i++) { +				cmddata = get_val(®s->mmcdrr); +				memcpy(data_buf, (char *)&cmddata, 4); +				data_buf += 4; +				bytes_left -= 4; +			} +		} else { +			/* +			 * MMC controller sets the Data transmit ready bit +			 * (DXRDY) in MMCST0 even before the entire FIFO is +			 * empty. This results in erratic behavior if we start +			 * writing the FIFO soon after DXRDY.  Wait for the +			 * FIFO empty bit in MMCST1 for proper FIFO clearing. +			 */ +			dmmc_wait_fifo_status(regs, MMCST1_FIFOEMP); +			for (i = 0; bytes_left && (i < fifo_words); i++) { +				memcpy((char *)&cmddata, data_buf, 4); +				set_val(®s->mmcdxr, cmddata); +				data_buf += 4; +				bytes_left -= 4; +			} +			dmmc_busy_wait(regs); +		} +	} + +	err = dmmc_check_status(regs, &mmcstatus, MMCST0_DATDNE, status_err); +	if (err) +		return err; + +	return 0; +} + +/* Initialize Davinci MMC controller */ +static int dmmc_init(struct mmc *mmc) +{ +	struct davinci_mmc *host = mmc->priv; +	struct davinci_mmc_regs *regs = host->reg_base; + +	/* Clear status registers explicitly - soft reset doesn't clear it +	 * If Uboot is invoked from UBL with SDMMC Support, the status +	 * registers can have uncleared bits +	 */ +	get_val(®s->mmcst0); +	get_val(®s->mmcst1); + +	/* Hold software reset */ +	set_bit(®s->mmcctl, MMCCTL_DATRST); +	set_bit(®s->mmcctl, MMCCTL_CMDRST); +	udelay(10); + +	set_val(®s->mmcclk, 0x0); +	set_val(®s->mmctor, 0x1FFF); +	set_val(®s->mmctod, 0xFFFF); + +	/* Clear software reset */ +	clear_bit(®s->mmcctl, MMCCTL_DATRST); +	clear_bit(®s->mmcctl, MMCCTL_CMDRST); + +	udelay(10); + +	/* Reset FIFO - Always use the maximum fifo threshold */ +	set_val(®s->mmcfifoctl, (MMCFIFOCTL_FIFOLEV | MMCFIFOCTL_FIFORST)); +	set_val(®s->mmcfifoctl, MMCFIFOCTL_FIFOLEV); + +	return 0; +} + +/* Set buswidth or clock as indicated by the GENERIC_MMC framework */ +static void dmmc_set_ios(struct mmc *mmc) +{ +	struct davinci_mmc *host = mmc->priv; +	struct davinci_mmc_regs *regs = host->reg_base; + +	/* Set the bus width */ +	if (mmc->bus_width == 4) +		set_bit(®s->mmcctl, MMCCTL_WIDTH_4_BIT); +	else +		clear_bit(®s->mmcctl, MMCCTL_WIDTH_4_BIT); + +	/* Set clock speed */ +	if (mmc->clock) +		dmmc_set_clock(mmc, mmc->clock); +} + +/* Called from board_mmc_init during startup. Can be called multiple times + * depending on the number of slots available on board and controller + */ +int davinci_mmc_init(bd_t *bis, struct davinci_mmc *host) +{ +	struct mmc *mmc; + +	mmc = malloc(sizeof(struct mmc)); +	memset(mmc, 0, sizeof(struct mmc)); + +	sprintf(mmc->name, "davinci"); +	mmc->priv = host; +	mmc->send_cmd = dmmc_send_cmd; +	mmc->set_ios = dmmc_set_ios; +	mmc->init = dmmc_init; + +	mmc->f_min = 200000; +	mmc->f_max = 25000000; +	mmc->voltages = host->voltages; +	mmc->host_caps = host->host_caps; + +#ifdef CONFIG_MMC_MBLOCK +	mmc->b_max = DAVINCI_MAX_BLOCKS; +#endif +	mmc_register(mmc); + +	return 0; +} + diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index ec71cfcaf..2a8dd7e23 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -22,7 +22,7 @@  #include <nand.h>  #include <linux/err.h>  #include <asm/io.h> -#if defined(CONFIG_MX25) || defined(CONFIG_MX27) +#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35)  #include <asm/arch/imx-regs.h>  #endif @@ -50,7 +50,7 @@   */  #if defined(CONFIG_MX31) || defined(CONFIG_MX27)  #define MXC_NFC_V1 -#elif defined(CONFIG_MX25) +#elif defined(CONFIG_MX25) || defined(CONFIG_MX35)  #define MXC_NFC_V1_1  #else  #warning "MXC NFC version not defined" @@ -265,7 +265,7 @@ static int is_16bit_nand(void)  	else  		return 0;  } -#elif defined(CONFIG_MX25) +#elif defined(CONFIG_MX25) || defined(CONFIG_MX35)  static int is_16bit_nand(void)  {  	struct ccm_regs *ccm = diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 56cd2aaf4..c359f54f9 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -322,9 +322,10 @@ static void  __attribute__((unused)) davinci_eth_gigabit_enable(void)  			 * Check if link detected is giga-bit  			 * If Gigabit mode detected, enable gigbit in MAC  			 */ -			writel(EMAC_MACCONTROL_GIGFORCE | -			       EMAC_MACCONTROL_GIGABIT_ENABLE, -			       &adap_emac->MACCONTROL); +			writel(readl(&adap_emac->MACCONTROL) | +				EMAC_MACCONTROL_GIGFORCE | +				EMAC_MACCONTROL_GIGABIT_ENABLE, +				&adap_emac->MACCONTROL);  		}  	}  } @@ -666,6 +667,7 @@ int davinci_emac_initialize(void)  		return -1;  	memset(dev, 0, sizeof *dev); +	sprintf(dev->name, "DaVinci-EMAC");  	dev->iobase = 0;  	dev->init = davinci_eth_open; @@ -723,6 +725,13 @@ int davinci_emac_initialize(void)  			phy.get_link_speed = dp83848_get_link_speed;  			phy.auto_negotiate = dp83848_auto_negotiate;  			break; +		case PHY_ET1011C: +			sprintf(phy.name, "ET1011C @ 0x%02x", active_phy_addr); +			phy.init = gen_init_phy; +			phy.is_phy_connected = gen_is_phy_connected; +			phy.get_link_speed = et1011c_get_link_speed; +			phy.auto_negotiate = gen_auto_negotiate; +			break;  		default:  			sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr);  			phy.init = gen_init_phy; diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index c4389629a..4e4cd2749 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -354,7 +354,7 @@ static int fec_open(struct eth_device *edev)  	 */  	writel(readl(&fec->eth->ecntrl) | FEC_ECNTRL_ETHER_EN,  		&fec->eth->ecntrl); -#ifdef CONFIG_MX25 +#if defined(CONFIG_MX25) || defined(CONFIG_MX53)  	udelay(100);  	/*  	 * setup the MII gasket for RMII mode diff --git a/drivers/net/fec_mxc.h b/drivers/net/fec_mxc.h index 5d0d69d5e..1ba51617d 100644 --- a/drivers/net/fec_mxc.h +++ b/drivers/net/fec_mxc.h @@ -147,7 +147,7 @@ struct ethernet_regs {  	uint32_t res14[7];		/* MBAR_ETH + 0x2E4-2FC */ -#ifdef CONFIG_MX25 +#if defined(CONFIG_MX25) || defined(CONFIG_MX53)  	uint16_t miigsk_cfgr;		/* MBAR_ETH + 0x300 */  	uint16_t res15[3];		/* MBAR_ETH + 0x302-306 */  	uint16_t miigsk_enr;		/* MBAR_ETH + 0x308 */ @@ -204,7 +204,7 @@ struct ethernet_regs {  #define FEC_ECNTRL_RESET		0x00000001	/* reset the FEC */  #define FEC_ECNTRL_ETHER_EN		0x00000002	/* enable the FEC */ -#ifdef CONFIG_MX25 +#if defined(CONFIG_MX25) || defined(CONFIG_MX53)  /* defines for MIIGSK */  /* RMII frequency control: 0=50MHz, 1=5MHz */  #define MIIGSK_CFGR_FRCONT		(1 << 6) diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index f96b21f7b..b9cf9de74 100644 --- a/drivers/serial/serial_mxc.c +++ b/drivers/serial/serial_mxc.c @@ -50,11 +50,14 @@  #define UART_PHYS 0x1001b000  #elif defined(CONFIG_SYS_MX27_UART6)  #define UART_PHYS 0x1001c000 -#elif defined(CONFIG_SYS_MX51_UART1) +#elif defined(CONFIG_SYS_MX35_UART1) || defined(CONFIG_SYS_MX51_UART1) || \ +	defined(CONFIG_SYS_MX53_UART1)  #define UART_PHYS UART1_BASE_ADDR -#elif defined(CONFIG_SYS_MX51_UART2) +#elif defined(CONFIG_SYS_MX35_UART2) || defined(CONFIG_SYS_MX51_UART2) || \ +	defined(CONFIG_SYS_MX53_UART2)  #define UART_PHYS UART2_BASE_ADDR -#elif defined(CONFIG_SYS_MX51_UART3) +#elif defined(CONFIG_SYS_MX35_UART3) || defined(CONFIG_SYS_MX51_UART3) || \ +	defined(CONFIG_SYS_MX53_UART3)  #define UART_PHYS UART3_BASE_ADDR  #else  #error "define CONFIG_SYS_MXxx_UARTx to use the MXC UART driver" diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index 9c1cbf4a4..f1ffa29fd 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -72,7 +72,7 @@ void serial_setbrg_dev(const int dev_index)  	writel(val / 16 - 1, &uart->ubrdiv); -	if (use_divslot) +	if (s5p_uart_divslot())  		writew(udivslot[val % 16], &uart->rest.slot);  	else  		writeb(val % 16, &uart->rest.value); diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index d558137c9..6474eb802 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -36,16 +36,6 @@  #include <asm/arch/mx31.h> -#define MXC_CSPIRXDATA		0x00 -#define MXC_CSPITXDATA		0x04 -#define MXC_CSPICTRL		0x08 -#define MXC_CSPIINT		0x0C -#define MXC_CSPIDMA		0x10 -#define MXC_CSPISTAT		0x14 -#define MXC_CSPIPERIOD		0x18 -#define MXC_CSPITEST		0x1C -#define MXC_CSPIRESET		0x00 -  #define MXC_CSPICTRL_EN		(1 << 0)  #define MXC_CSPICTRL_MODE	(1 << 1)  #define MXC_CSPICTRL_XCH	(1 << 2) @@ -70,19 +60,12 @@ static unsigned long spi_bases[] = {  	0x53f84000,  }; +#define mxc_get_clock(x)	mx31_get_ipg_clk() +  #elif defined(CONFIG_MX51)  #include <asm/arch/imx-regs.h>  #include <asm/arch/clock.h> -#define MXC_CSPIRXDATA		0x00 -#define MXC_CSPITXDATA		0x04 -#define MXC_CSPICTRL		0x08 -#define MXC_CSPICON		0x0C -#define MXC_CSPIINT		0x10 -#define MXC_CSPIDMA		0x14 -#define MXC_CSPISTAT		0x18 -#define MXC_CSPIPERIOD		0x1C -#define MXC_CSPIRESET		0x00  #define MXC_CSPICTRL_EN		(1 << 0)  #define MXC_CSPICTRL_MODE	(1 << 1)  #define MXC_CSPICTRL_XCH	(1 << 2) @@ -111,12 +94,44 @@ static unsigned long spi_bases[] = {  	CSPI2_BASE_ADDR,  	CSPI3_BASE_ADDR,  }; + +#elif defined(CONFIG_MX35) + +#include <asm/arch/imx-regs.h> +#include <asm/arch/clock.h> + +#define MXC_CSPICTRL_EN		(1 << 0) +#define MXC_CSPICTRL_MODE	(1 << 1) +#define MXC_CSPICTRL_XCH	(1 << 2) +#define MXC_CSPICTRL_SMC	(1 << 3) +#define MXC_CSPICTRL_POL	(1 << 4) +#define MXC_CSPICTRL_PHA	(1 << 5) +#define MXC_CSPICTRL_SSCTL	(1 << 6) +#define MXC_CSPICTRL_SSPOL	(1 << 7) +#define MXC_CSPICTRL_CHIPSELECT(x)	(((x) & 0x3) << 12) +#define MXC_CSPICTRL_BITCOUNT(x)	(((x) & 0xfff) << 20) +#define MXC_CSPICTRL_DATARATE(x)	(((x) & 0x7) << 16) +#define MXC_CSPICTRL_TC		(1 << 7) +#define MXC_CSPICTRL_RXOVF	(1 << 6) +#define MXC_CSPICTRL_MAXBITS	0xfff + +#define MXC_CSPIPERIOD_32KHZ	(1 << 15) +#define MAX_SPI_BYTES	4 + +static unsigned long spi_bases[] = { +	0x43fa4000, +	0x50010000, +}; +  #else  #error "Unsupported architecture"  #endif  #define OUT	MXC_GPIO_DIRECTION_OUT +#define reg_read readl +#define reg_write(a, v) writel(v, a) +  struct mxc_spi_slave {  	struct spi_slave slave;  	unsigned long	base; @@ -133,16 +148,6 @@ static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave)  	return container_of(slave, struct mxc_spi_slave, slave);  } -static inline u32 reg_read(unsigned long addr) -{ -	return *(volatile unsigned long*)addr; -} - -static inline void reg_write(unsigned long addr, u32 val) -{ -	*(volatile unsigned long*)addr = val; -} -  void spi_cs_activate(struct spi_slave *slave)  {  	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); @@ -158,24 +163,73 @@ void spi_cs_deactivate(struct spi_slave *slave)  			      !(mxcs->ss_pol));  } -#ifdef CONFIG_MX51 -static s32 spi_cfg(struct mxc_spi_slave *mxcs, unsigned int cs, +u32 get_cspi_div(u32 div) +{ +	int i; + +	for (i = 0; i < 8; i++) { +		if (div <= (4 << i)) +			return i; +	} +	return i; +} + +#if defined(CONFIG_MX31) || defined(CONFIG_MX35) +static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, +		unsigned int max_hz, unsigned int mode) +{ +	unsigned int ctrl_reg; +	u32 clk_src; +	u32 div; + +	clk_src = mxc_get_clock(MXC_CSPI_CLK); + +	div = clk_src / max_hz; +	div = get_cspi_div(div); + +	debug("clk %d Hz, div %d, real clk %d Hz\n", +		max_hz, div, clk_src / (4 << div)); + +	ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) | +		MXC_CSPICTRL_BITCOUNT(MXC_CSPICTRL_MAXBITS) | +		MXC_CSPICTRL_DATARATE(div) | +		MXC_CSPICTRL_EN | +#ifdef CONFIG_MX35 +		MXC_CSPICTRL_SSCTL | +#endif +		MXC_CSPICTRL_MODE; + +	if (mode & SPI_CPHA) +		ctrl_reg |= MXC_CSPICTRL_PHA; +	if (mode & SPI_CPOL) +		ctrl_reg |= MXC_CSPICTRL_POL; +	if (mode & SPI_CS_HIGH) +		ctrl_reg |= MXC_CSPICTRL_SSPOL; +	mxcs->ctrl_reg = ctrl_reg; + +	return 0; +} +#endif + +#if defined(CONFIG_MX51) +static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs,  		unsigned int max_hz, unsigned int mode)  {  	u32 clk_src = mxc_get_clock(MXC_CSPI_CLK);  	s32 pre_div = 0, post_div = 0, i, reg_ctrl, reg_config;  	u32 ss_pol = 0, sclkpol = 0, sclkpha = 0; +	struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;  	if (max_hz == 0) {  		printf("Error: desired clock is 0\n");  		return -1;  	} -	reg_ctrl = reg_read(mxcs->base + MXC_CSPICTRL); +	reg_ctrl = reg_read(®s->ctrl);  	/* Reset spi */ -	reg_write(mxcs->base + MXC_CSPICTRL, 0); -	reg_write(mxcs->base + MXC_CSPICTRL, (reg_ctrl | 0x1)); +	reg_write(®s->ctrl, 0); +	reg_write(®s->ctrl, (reg_ctrl | 0x1));  	/*  	 * The following computation is taken directly from Freescale's code. @@ -223,11 +277,11 @@ static s32 spi_cfg(struct mxc_spi_slave *mxcs, unsigned int cs,  	if (mode & SPI_CPHA)  		sclkpha = 1; -	reg_config = reg_read(mxcs->base + MXC_CSPICON); +	reg_config = reg_read(®s->cfg);  	/*  	 * Configuration register setup -	 * The MX51 has support different setup for each SS +	 * The MX51 supports different setup for each SS  	 */  	reg_config = (reg_config & ~(1 << (cs + MXC_CSPICON_SSPOL))) |  		(ss_pol << (cs + MXC_CSPICON_SSPOL)); @@ -237,18 +291,17 @@ static s32 spi_cfg(struct mxc_spi_slave *mxcs, unsigned int cs,  		(sclkpha << (cs + MXC_CSPICON_PHA));  	debug("reg_ctrl = 0x%x\n", reg_ctrl); -	reg_write(mxcs->base + MXC_CSPICTRL, reg_ctrl); +	reg_write(®s->ctrl, reg_ctrl);  	debug("reg_config = 0x%x\n", reg_config); -	reg_write(mxcs->base + MXC_CSPICON, reg_config); +	reg_write(®s->cfg, reg_config);  	/* save config register and control register */  	mxcs->ctrl_reg = reg_ctrl;  	mxcs->cfg_reg = reg_config;  	/* clear interrupt reg */ -	reg_write(mxcs->base + MXC_CSPIINT, 0); -	reg_write(mxcs->base + MXC_CSPISTAT, -		MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF); +	reg_write(®s->intr, 0); +	reg_write(®s->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);  	return 0;  } @@ -260,6 +313,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,  	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);  	int nbytes = (bitlen + 7) / 8;  	u32 data, cnt, i; +	struct cspi_regs *regs = (struct cspi_regs *)mxcs->base;  	debug("%s: bitlen %d dout 0x%x din 0x%x\n",  		__func__, bitlen, (u32)dout, (u32)din); @@ -268,14 +322,13 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,  		~MXC_CSPICTRL_BITCOUNT(MXC_CSPICTRL_MAXBITS)) |  		MXC_CSPICTRL_BITCOUNT(bitlen - 1); -	reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg | MXC_CSPICTRL_EN); +	reg_write(®s->ctrl, mxcs->ctrl_reg | MXC_CSPICTRL_EN);  #ifdef CONFIG_MX51 -	reg_write(mxcs->base + MXC_CSPICON, mxcs->cfg_reg); +	reg_write(®s->cfg, mxcs->cfg_reg);  #endif  	/* Clear interrupt register */ -	reg_write(mxcs->base + MXC_CSPISTAT, -		MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF); +	reg_write(®s->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);  	/*  	 * The SPI controller works only with words, @@ -292,7 +345,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,  		}  		debug("Sending SPI 0x%x\n", data); -		reg_write(mxcs->base + MXC_CSPITXDATA, data); +		reg_write(®s->txdata, data);  		nbytes -= cnt;  	} @@ -304,9 +357,8 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,  			/* Buffer is not 32-bit aligned */  			if ((unsigned long)dout & 0x03) {  				data = 0; -				for (i = 0; i < 4; i++, data <<= 8) { +				for (i = 0; i < 4; i++)  					data = (data << 8) | (*dout++ & 0xFF); -				}  			} else {  				data = *(u32 *)dout;  				data = cpu_to_be32(data); @@ -314,41 +366,40 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,  			dout += 4;  		}  		debug("Sending SPI 0x%x\n", data); -		reg_write(mxcs->base + MXC_CSPITXDATA, data); +		reg_write(®s->txdata, data);  		nbytes -= 4;  	}  	/* FIFO is written, now starts the transfer setting the XCH bit */ -	reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg | +	reg_write(®s->ctrl, mxcs->ctrl_reg |  		MXC_CSPICTRL_EN | MXC_CSPICTRL_XCH);  	/* Wait until the TC (Transfer completed) bit is set */ -	while ((reg_read(mxcs->base + MXC_CSPISTAT) & MXC_CSPICTRL_TC) == 0) +	while ((reg_read(®s->stat) & MXC_CSPICTRL_TC) == 0)  		;  	/* Transfer completed, clear any pending request */ -	reg_write(mxcs->base + MXC_CSPISTAT, -		MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF); +	reg_write(®s->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF);  	nbytes = (bitlen + 7) / 8;  	cnt = nbytes % 32;  	if (bitlen % 32) { -		data = reg_read(mxcs->base + MXC_CSPIRXDATA); +		data = reg_read(®s->rxdata);  		cnt = (bitlen % 32) / 8; +		data = cpu_to_be32(data) >> ((sizeof(data) - cnt) * 8);  		debug("SPI Rx unaligned: 0x%x\n", data);  		if (din) { -			for (i = 0; i < cnt; i++, data >>= 8) { -				*din++ = data & 0xFF; -			} +			memcpy(din, &data, cnt); +			din += cnt;  		}  		nbytes -= cnt;  	}  	while (nbytes > 0) {  		u32 tmp; -		tmp = reg_read(mxcs->base + MXC_CSPIRXDATA); +		tmp = reg_read(®s->rxdata);  		data = cpu_to_be32(tmp);  		debug("SPI Rx: 0x%x 0x%x\n", tmp, data);  		cnt = min(nbytes, sizeof(data)); @@ -363,7 +414,6 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen,  } -  int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,  		void *din, unsigned long flags)  { @@ -381,7 +431,6 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,  		spi_cs_activate(slave);  	while (n_bytes > 0) { -  		if (n_bytes < MAX_SPI_BYTES)  			blk_size = n_bytes;  		else @@ -441,7 +490,6 @@ static int decode_cs(struct mxc_spi_slave *mxcs, unsigned int cs)  struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,  			unsigned int max_hz, unsigned int mode)  { -	unsigned int ctrl_reg;  	struct mxc_spi_slave *mxcs;  	int ret; @@ -467,30 +515,12 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,  	mxcs->base = spi_bases[bus];  	mxcs->ss_pol = (mode & SPI_CS_HIGH) ? 1 : 0; -#ifdef CONFIG_MX51 -	/* Can be used for i.MX31 too ? */ -	ctrl_reg = 0; -	ret = spi_cfg(mxcs, cs, max_hz, mode); +	ret = spi_cfg_mxc(mxcs, cs, max_hz, mode);  	if (ret) {  		printf("mxc_spi: cannot setup SPI controller\n");  		free(mxcs);  		return NULL;  	} -#else -	ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) | -		MXC_CSPICTRL_BITCOUNT(31) | -		MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */ -		MXC_CSPICTRL_EN | -		MXC_CSPICTRL_MODE; - -	if (mode & SPI_CPHA) -		ctrl_reg |= MXC_CSPICTRL_PHA; -	if (mode & SPI_CPOL) -		ctrl_reg |= MXC_CSPICTRL_POL; -	if (mode & SPI_CS_HIGH) -		ctrl_reg |= MXC_CSPICTRL_SSPOL; -	mxcs->ctrl_reg = ctrl_reg; -#endif  	return &mxcs->slave;  } @@ -504,13 +534,13 @@ void spi_free_slave(struct spi_slave *slave)  int spi_claim_bus(struct spi_slave *slave)  {  	struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); +	struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; -	reg_write(mxcs->base + MXC_CSPIRESET, 1); +	reg_write(®s->rxdata, 1);  	udelay(1); -	reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg); -	reg_write(mxcs->base + MXC_CSPIPERIOD, -		  MXC_CSPIPERIOD_32KHZ); -	reg_write(mxcs->base + MXC_CSPIINT, 0); +	reg_write(®s->ctrl, mxcs->ctrl_reg); +	reg_write(®s->period, MXC_CSPIPERIOD_32KHZ); +	reg_write(®s->intr, 0);  	return 0;  } |