diff options
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 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..f22f4f4 --- /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 663141f..53a0673 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 8e10fbb..c5ec486 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 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/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 <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 0000000..439d5a6 --- /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 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 <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 ec71cfc..2a8dd7e 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 56cd2aa..c359f54 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 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) diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c index f96b21f..b9cf9de 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 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); diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index d558137..6474eb8 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; } |