From 96912453fe9707d84874da56cef94d715adc6e29 Mon Sep 17 00:00:00 2001 From: Liu Hui-R64343 Date: Mon, 3 Jan 2011 22:27:36 +0000 Subject: fec_mxc: add support for MX53 processor This patch add FEC support for Freescale MX53 processor Signed-off-by: Jason Liu --- drivers/net/fec_mxc.c | 2 +- drivers/net/fec_mxc.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index c438962..4e4cd27 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 5d0d69d..1ba5161 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) -- cgit v1.1 From 0c466ad017cebd4919b9905eb82a99140163be76 Mon Sep 17 00:00:00 2001 From: Liu Hui-R64343 Date: Mon, 3 Jan 2011 22:27:37 +0000 Subject: serial_mxc: add support for MX53 processor This patch add UART support for Freescale MX53 processor Signed-off-by: Jason Liu --- drivers/serial/serial_mxc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index f96b21f..805f4c5 100644 --- a/drivers/serial/serial_mxc.c +++ b/drivers/serial/serial_mxc.c @@ -56,6 +56,12 @@ #define UART_PHYS UART2_BASE_ADDR #elif defined(CONFIG_SYS_MX51_UART3) #define UART_PHYS UART3_BASE_ADDR +#elif defined(CONFIG_SYS_MX53_UART1) +#define UART_PHYS UART1_BASE_ADDR +#elif defined(CONFIG_SYS_MX53_UART2) +#define UART_PHYS UART2_BASE_ADDR +#elif defined(CONFIG_SYS_MX53_UART3) +#define UART_PHYS UART3_BASE_ADDR #else #error "define CONFIG_SYS_MXxx_UARTx to use the MXC UART driver" #endif -- cgit v1.1 From 01643ec180d975192e2a1fcf964dd3239bebc75a Mon Sep 17 00:00:00 2001 From: Liu Hui-R64343 Date: Mon, 3 Jan 2011 22:27:38 +0000 Subject: mxc_gpio: add support for MX53 processor This patch add mxc_gpio support for Freescale MX53 processor Signed-off-by: Jason Liu --- drivers/gpio/mxc_gpio.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/mxc_gpio.c b/drivers/gpio/mxc_gpio.c index 663141f..53a0673 100644 --- a/drivers/gpio/mxc_gpio.c +++ b/drivers/gpio/mxc_gpio.c @@ -24,7 +24,7 @@ #ifdef CONFIG_MX31 #include #endif -#ifdef CONFIG_MX51 +#if defined(CONFIG_MX51) || defined(CONFIG_MX53) #include #endif #include @@ -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) -- cgit v1.1 From 127cec1889c7a9bb3c3eab521779b08657043a9a Mon Sep 17 00:00:00 2001 From: Liu Hui-R64343 Date: Mon, 3 Jan 2011 22:27:39 +0000 Subject: mxc_i2c: add support for MX53 processor This patch add I2C support for Freescale MX53 processor Signed-off-by: Jason Liu --- drivers/i2c/mxc_i2c.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 8e10fbb..1ebec14 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -26,8 +26,14 @@ #if defined(CONFIG_HARD_I2C) +#if defined(CONFIG_MX31) #include #include +#endif + +#if defined(CONFIG_MX53) +#include +#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,8 +62,12 @@ #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 #else -#error "define CONFIG_SYS_I2C_MX31_PORTx to use the mx31 I2C driver" +#error "define CONFIG_SYS_I2C_MXxx_PORTx to use the I2C driver" #endif #ifdef DEBUG @@ -72,11 +82,16 @@ static u16 div[] = { 30, 32, 36, 42, 48, 52, 60, 72, 80, 88, 104, 128, 144, void i2c_init(int speed, int unused) { - int freq = mx31_get_ipg_clk(); + int freq; int i; +#if defined(CONFIG_MX31) + freq = mx31_get_ipg_clk(); /* start the required I2C clock */ __REG(CCM_CGR0) = __REG(CCM_CGR0) | (3 << I2C_CLK_OFFSET); +#else + freq = mxc_get_clock(MXC_IPG_PERCLK); +#endif for (i = 0; i < 0x1f; i++) if (freq / div[i] <= speed) -- cgit v1.1 From 3382fd48f277a3dc77ad8d3d99d255e88797b045 Mon Sep 17 00:00:00 2001 From: Liu Hui-R64343 Date: Mon, 3 Jan 2011 22:27:40 +0000 Subject: fsl_pmic: add I2C interface support This patch add I2C interface for fsl_pmic driver support Signed-off-by: Jason Liu --- drivers/misc/fsl_pmic.c | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/fsl_pmic.c b/drivers/misc/fsl_pmic.c index 5ee1de1..ef80ad9 100644 --- a/drivers/misc/fsl_pmic.c +++ b/drivers/misc/fsl_pmic.c @@ -22,11 +22,48 @@ #include #include -#include #include #include #include +static int check_param(u32 reg, u32 write) +{ + if (reg > 63 || write > 1) { + printf(" = %d is invalid. Should be less then 63\n", + reg); + return -1; + } + + return 0; +} + +#ifdef CONFIG_FSL_PMIC_I2C +#include + +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 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(" = %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) { -- cgit v1.1 From 76f260d105f9982bd74c5b5a573e34421dce3512 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 13 Jan 2011 07:27:55 +0000 Subject: BLOCK: Add freescale IMX51 PATA driver Signed-off-by: Marek Vasut Acked-by: Stefano Babic Acked-by: Wolfgang Denk --- drivers/block/Makefile | 1 + drivers/block/mxc_ata.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 drivers/block/mxc_ata.c (limited to 'drivers') diff --git a/drivers/block/Makefile b/drivers/block/Makefile index e27175b..aa7dc87 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 0000000..842a633 --- /dev/null +++ b/drivers/block/mxc_ata.c @@ -0,0 +1,149 @@ +/* + * Freescale iMX51 ATA driver + * + * Copyright (C) 2010 Marek Vasut + * + * Based on code by: + * Mahesh Mahadevan + * + * 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 +#include +#include +#include +#include +#include + +#include +#include + +/* 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_t0[NR_PIO_SPECS] = { 600, 383, 240, 180, 120 }; +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_t2_16[NR_PIO_SPECS] = { 165, 125, 100, 80, 70 }; +static uint16_t pio_t2i[NR_PIO_SPECS] = { 40, 0, 0, 0, 0 }; +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; +} -- cgit v1.1 From 58c758fe5a632e955c94f203f245bd79a64f9bbc Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Fri, 14 Jan 2011 03:35:21 +0000 Subject: mxc_nand: add support for i.MX35 processor Signed-off-by: Stefano Babic Acked-by: Scott Wood --- drivers/mtd/nand/mxc_nand.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index ec71cfc..2a8dd7e 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -22,7 +22,7 @@ #include #include #include -#if defined(CONFIG_MX25) || defined(CONFIG_MX27) +#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35) #include #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 = -- cgit v1.1 From 1b22b0d35bb18b86ac6a5b2a8ae1ddba7822bc47 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Wed, 19 Jan 2011 22:46:25 +0000 Subject: serial_mxc: add support for Freescale's i.MX35 processor The patch adds UART support for the i.MX35 processor. Signed-off-by: Stefano Babic --- drivers/serial/serial_mxc.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index 805f4c5..b9cf9de 100644 --- a/drivers/serial/serial_mxc.c +++ b/drivers/serial/serial_mxc.c @@ -50,17 +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) -#define UART_PHYS UART3_BASE_ADDR -#elif defined(CONFIG_SYS_MX53_UART1) -#define UART_PHYS UART1_BASE_ADDR -#elif defined(CONFIG_SYS_MX53_UART2) -#define UART_PHYS UART2_BASE_ADDR -#elif defined(CONFIG_SYS_MX53_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" -- cgit v1.1 From 04220612f69a7148f7f6d045638c8046bd265b29 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Wed, 19 Jan 2011 22:46:26 +0000 Subject: mxc_i2c: Add support for the i.MX35 processor Signed-off-by: Stefano Babic CC: Heiko Schocher Acked-by: Heiko Schocher --- drivers/i2c/mxc_i2c.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 1ebec14..7f669ff 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -29,9 +29,8 @@ #if defined(CONFIG_MX31) #include #include -#endif - -#if defined(CONFIG_MX53) +#else +#include #include #endif @@ -66,8 +65,10 @@ #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_MXxx_PORTx to use the I2C driver" +#error "define CONFIG_SYS_I2C_MX_PORTx to use the mx I2C driver" #endif #ifdef DEBUG -- cgit v1.1 From 1d549ade61078b50e68ff867fe59401bb5c2db9b Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Thu, 20 Jan 2011 07:50:44 +0000 Subject: I2C: mxc_i2c: get rid of __REG access This driver accesses to processor's register via __REG macros, that are removed (or are planned to be removed) and replaced by C structures. This patches replaces all occurrencies of __REG macros. Signed-off-by: Stefano Babic CC: Heiko Schocher Acked-by: Heiko Schocher --- drivers/i2c/mxc_i2c.c | 72 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index 7f669ff..fd6db18 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -23,6 +23,7 @@ */ #include +#include #if defined(CONFIG_HARD_I2C) @@ -81,15 +82,26 @@ 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; 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 @@ -98,30 +110,28 @@ void i2c_init(int speed, int unused) 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_busy(void) { int timeout = 10000; - while (!(__REG16(I2C_BASE + I2SR) & I2SR_IIF) && --timeout) + while (!(readw(I2C_BASE + I2SR) & I2SR_IIF) && --timeout) udelay(1); - __REG16(I2C_BASE + I2SR) = 0; /* clear interrupt */ + 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_busy() || readw(I2C_BASE + I2SR) & I2SR_RX_NO_AK) return -1; return 0; } @@ -131,27 +141,27 @@ static int rx_byte(void) if (!wait_busy()) return -1; - return __REG16(I2C_BASE + I2DR); + 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; + writew(0, I2C_BASE + I2SR); + writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR); if (tx_byte(chip << 1)) return -1; @@ -167,35 +177,40 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) int timeout = 10000; 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) 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; @@ -203,8 +218,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; @@ -213,9 +229,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; -- cgit v1.1 From 81687212ee0b4fcb11f7d6700275b062c8f8d2b4 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Thu, 20 Jan 2011 07:51:31 +0000 Subject: I2C: mxc_i2c: address failure with mx35 processor There is sporadic failures when more as one I2C slave is on the bus and the processor tries to communicate with more as one slave. The problem was seen on a mx35pdk (two I2C slaves, PMIC controller and CAN/RTC chip). The current driver uses the IIF bit in the status register to check if the bus is busy or not. According to the manual, this is not correct, because the IIB bit should be checked. Not only, to check if a transfer is finished must be checked the ICF bit, and this is not tested at all. This patch comes from analyse with a corresponding driver provided by Freescale as part of the LTIB tool. Comparing the two drivers, it appears that the current u-boot driver checks the wrong bits, and depending on race condition, the transfer can be successful or not. The patch gets rid also of own debug function (DPRINTF), replaced with the general debug(). Tested on Freescale mx35pdk. Signed-off-by: Stefano Babic CC: Heiko Schocher Acked-by: Heiko Schocher --- drivers/i2c/mxc_i2c.c | 86 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/mxc_i2c.c b/drivers/i2c/mxc_i2c.c index fd6db18..c5ec486 100644 --- a/drivers/i2c/mxc_i2c.c +++ b/drivers/i2c/mxc_i2c.c @@ -72,11 +72,8 @@ #error "define CONFIG_SYS_I2C_MX_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, @@ -116,31 +113,61 @@ void i2c_init(int speed, int unused) 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 (!(readw(I2C_BASE + I2SR) & I2SR_IIF) && --timeout) + while (!(readw(I2C_BASE + I2SR) & I2SR_IBB) && --timeout) udelay(1); 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) { writew(byte, I2C_BASE + I2DR); - if (!wait_busy() || readw(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; + if (last) + writew(I2CR_IEN, I2C_BASE + I2CR); + return readw(I2C_BASE + I2DR); } @@ -160,21 +187,45 @@ int i2c_probe(uchar chip) static int i2c_addr(uchar chip, uint addr, int alen) { - writew(0, I2C_BASE + I2SR); - writew(I2CR_IEN | I2CR_MSTA | I2CR_MTX, I2C_BASE + I2CR); + 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; debug("%s chip: 0x%02x addr: 0x%04x alen: %d len: %d\n", @@ -197,7 +248,8 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) 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) @@ -206,8 +258,6 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len) I2C_BASE + I2CR); } - wait_busy(); - writew(I2CR_IEN, I2C_BASE + I2CR); while (readw(I2C_BASE + I2SR) & I2SR_IBB && --timeout) -- cgit v1.1 From 01bb24b6427eb77d8626e0366dc2aebaaab8b40b Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Wed, 19 Jan 2011 22:46:29 +0000 Subject: Add basic support for Freescale's mc9sdz60 The patch adds helper funtions for basic access to the registers of the MC9sdz60 chip (multifunctional device with RTC and CAN) via I2C interface. Signed-off-by: Stefano Babic --- drivers/misc/Makefile | 5 +++-- drivers/misc/mc9sdz60.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 drivers/misc/mc9sdz60.c (limited to 'drivers') diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index a76bd4e..b152486 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/mc9sdz60.c b/drivers/misc/mc9sdz60.c new file mode 100644 index 0000000..439d5a6 --- /dev/null +++ b/drivers/misc/mc9sdz60.c @@ -0,0 +1,51 @@ +/* + * (C) Copyright 2010 Stefano Babic + * + * 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 +#include +#include +#include +#include +#include + +#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); +} -- cgit v1.1 From c9d59c7fbe07aa9c519cf113107851cf4b3e1f54 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Wed, 19 Jan 2011 22:46:30 +0000 Subject: SPI: mxc_spi: add support for i.MX35 processor Signed-off-by: Stefano Babic --- drivers/spi/mxc_spi.c | 96 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index d558137..5670714 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -70,6 +70,8 @@ static unsigned long spi_bases[] = { 0x53f84000, }; +#define mxc_get_clock(x) mx31_get_ipg_clk() + #elif defined(CONFIG_MX51) #include #include @@ -111,6 +113,45 @@ static unsigned long spi_bases[] = { CSPI2_BASE_ADDR, CSPI3_BASE_ADDR, }; + +#elif defined(CONFIG_MX35) + +#include +#include + +#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) +#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 @@ -158,8 +199,35 @@ 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, +#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; + + ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) | + MXC_CSPICTRL_BITCOUNT(MXC_CSPICTRL_MAXBITS) | + MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */ + 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); @@ -227,7 +295,7 @@ static s32 spi_cfg(struct mxc_spi_slave *mxcs, unsigned int cs, /* * 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)); @@ -363,7 +431,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) { @@ -441,7 +508,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 +533,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; } -- cgit v1.1 From dff0109496846fd9787b6cdc0941217ecdf0ae28 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Thu, 20 Jan 2011 07:53:06 +0000 Subject: SPI: mxc_spi: fix swapping bug and add missing swapping in unaligned rx case We need to shift only one time in each cycle in the swapping loop for unaligned tx case. Currently two byte shift operations are performed in each loop cycle causing zero gaps in the transmited data, so not all data scheduled for transmition is actually transmited. The proper swapping in unaligned rx case is missing, so add it as we need to put the received data into the rx buffer in the correct byte order. Signed-off-by: Anatolij Gustschin Tested-by: Stefano Babic --- drivers/spi/mxc_spi.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 5670714..dadf228 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -372,9 +372,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); @@ -405,11 +404,11 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen, if (bitlen % 32) { data = reg_read(mxcs->base + MXC_CSPIRXDATA); 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; } -- cgit v1.1 From afaa9f65c24d815ed4f6133c800884921e051913 Mon Sep 17 00:00:00 2001 From: Anatolij Gustschin Date: Wed, 19 Jan 2011 22:46:32 +0000 Subject: SPI: mxc_spi: add SPI clock calculation and setup to the driver The MXC SPI driver didn't calculate the SPI clock up to now and just used highest possible divider 512 for DATA RATE in the control register. This results in very low transfer rates. The patch adds code to calculate and setup the SPI clock frequency for transfers. Signed-off-by: Anatolij Gustschin Signed-off-by: Stefano Babic --- drivers/spi/mxc_spi.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index dadf228..2a4ddad 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -199,15 +199,36 @@ void spi_cs_deactivate(struct spi_slave *slave) !(mxcs->ss_pol)); } +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(7) | /* FIXME: calculate data rate */ + MXC_CSPICTRL_DATARATE(div) | MXC_CSPICTRL_EN | #ifdef CONFIG_MX35 MXC_CSPICTRL_SSCTL | -- cgit v1.1 From ac87c17d344ede52d8d421addf92cbb2e271f73e Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Wed, 19 Jan 2011 22:46:33 +0000 Subject: SPI: mxc_spi: replace fixed offsets with structures This patch cleans driver code replacing all accesses to registers with fixed offsets with a corresponding structure. Signed-off-by: Stefano Babic --- drivers/spi/mxc_spi.c | 94 +++++++++++++++------------------------------------ 1 file changed, 28 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 2a4ddad..6474eb8 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -36,16 +36,6 @@ #include -#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) @@ -76,15 +66,6 @@ static unsigned long spi_bases[] = { #include #include -#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) @@ -119,16 +100,6 @@ static unsigned long spi_bases[] = { #include #include -#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) @@ -158,6 +129,9 @@ static unsigned long spi_bases[] = { #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; @@ -174,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); @@ -254,17 +218,18 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, 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. @@ -312,7 +277,7 @@ static s32 spi_cfg_mxc(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 @@ -326,18 +291,17 @@ static s32 spi_cfg_mxc(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; } @@ -349,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); @@ -357,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, @@ -381,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; } @@ -402,28 +366,27 @@ 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); @@ -436,7 +399,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen, 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)); @@ -468,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 @@ -572,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; } -- cgit v1.1 From fe38434dfef51b55bcae5017495249689e87b110 Mon Sep 17 00:00:00 2001 From: Stefano Babic Date: Tue, 1 Feb 2011 08:13:45 +0100 Subject: MXC: removed warnings from IMX51 ATA driver Drop warnings due to unused variables. Signed-off-by: Stefano Babic CC: Marek Vasut Acked-by: Marek Vasut --- drivers/block/mxc_ata.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/block/mxc_ata.c b/drivers/block/mxc_ata.c index 842a633..f22f4f4 100644 --- a/drivers/block/mxc_ata.c +++ b/drivers/block/mxc_ata.c @@ -87,11 +87,8 @@ struct mxc_data_hdd_regs { /* PIO timing table */ #define NR_PIO_SPECS 5 -static uint16_t pio_t0[NR_PIO_SPECS] = { 600, 383, 240, 180, 120 }; 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_t2_16[NR_PIO_SPECS] = { 165, 125, 100, 80, 70 }; -static uint16_t pio_t2i[NR_PIO_SPECS] = { 40, 0, 0, 0, 0 }; 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 }; -- cgit v1.1 From 57418d2139f032f9dae8cea38917aa90fdd673d8 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Mon, 20 Dec 2010 20:01:21 -0500 Subject: Davinci MMCSD Support Added support for MMC/SD cards for Davinci. This feature is enabled by CONFIG_DAVINCI_MMC and is dependant on CONFIG_MMC and CONFIG_GENERIC_MMC options. This is tested on DM355 and DM365 EVMs with both the available mmc controllers. Signed-off-by: Alagu Sankar Signed-off-by: Sandeep Paulraj --- drivers/mmc/Makefile | 1 + drivers/mmc/davinci_mmc.c | 404 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 405 insertions(+) create mode 100644 drivers/mmc/davinci_mmc.c (limited to 'drivers') diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 68afd30..3496f0a 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 0000000..4e572dc --- /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 +#include +#include +#include +#include +#include +#include +#include + +#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; +} + -- cgit v1.1 From 4b9b9e7c665bfcff43bc720b579b6b03a5078736 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Tue, 28 Dec 2010 14:37:33 -0500 Subject: DaVinci EMAC: Fix davinci_eth_gigabit_enable Enabling the gigabit was overwriting the previous configuration by setting up only GIGAFORCE and GIG bits of MAC control register. Modified to retain previous configuration while gigabit enabling. Signed-off-by: Prakash PM Signed-off-by: Sandeep Paulraj --- drivers/net/davinci_emac.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 56cd2aa..2642a5a 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); } } } -- cgit v1.1 From 2a7d603f37de94cb8529c67a35e71906f3c66dce Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Tue, 28 Dec 2010 14:42:27 -0500 Subject: DaVinci EMAC: Add name to Ethernet device Adds "DaVinci-EMAC" as the name of the device so that it gets printed as "Using DaVinci-EMAC device" during network access (dhcp, tftp) instead of empty name in "Using" statement.This name also gets reflected in 'ethact' env variable. Signed-off-by: Hemant Pedanekar Signed-off-by: Sandeep Paulraj --- drivers/net/davinci_emac.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 2642a5a..2067a54 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -667,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; -- cgit v1.1 From 840f8923a076b02b983cf58c9466b5bdf5957133 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Tue, 28 Dec 2010 15:43:16 -0500 Subject: DaVinci DM6467: Added ET1011C (LSI) PHY support Added arch/arm/cpu/arm926ejs/davinci/et1011c.c for handling ET1011C gigabit phy. which overrides get_link_speed function from default implementation. This enables output of 125 MHz reference clock on SYS_CLK pin. Signed-off-by: Prakash PM Signed-off-by: Sandeep Paulraj --- drivers/net/davinci_emac.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 2067a54..c359f54 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -725,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; -- cgit v1.1 From e0617c621def4bea5c6013dbc698ecf4f75d97c1 Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Mon, 24 Jan 2011 14:43:25 +0900 Subject: S5P: serial: Use the inline function instead of static value Signed-off-by: Minkyu Kang --- drivers/serial/serial_s5p.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index 9c1cbf4..f1ffa29 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); -- cgit v1.1