summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/systemace.c38
-rw-r--r--drivers/dfu/dfu_mmc.c34
-rw-r--r--drivers/gpio/tegra_gpio.c8
-rw-r--r--drivers/i2c/omap24xx_i2c.c8
-rw-r--r--drivers/i2c/tegra_i2c.c12
-rw-r--r--drivers/input/Makefile2
-rw-r--r--drivers/misc/fsl_law.c54
-rw-r--r--drivers/mmc/arm_pl180_mmci.c2
-rw-r--r--drivers/mmc/mmc.c20
-rw-r--r--drivers/mmc/mxsmmc.c4
-rw-r--r--drivers/mmc/pxa_mmc_gen.c8
-rw-r--r--drivers/mmc/s5p_sdhci.c18
-rw-r--r--drivers/mmc/sdhci.c30
-rw-r--r--drivers/mmc/sh_mmcif.c2
-rw-r--r--drivers/mmc/tegra_mmc.c34
-rw-r--r--drivers/mmc/tegra_mmc.h131
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/mxc_nand.c337
-rw-r--r--drivers/mtd/nand/mxs_nand.c2
-rw-r--r--drivers/mtd/nand/nand_base.c13
-rw-r--r--drivers/mtd/nand/nand_util.c26
-rw-r--r--drivers/mtd/nand/tegra_nand.c1026
-rw-r--r--drivers/mtd/nand/tegra_nand.h257
-rw-r--r--drivers/net/fm/Makefile2
-rw-r--r--drivers/net/fm/init.c30
-rw-r--r--drivers/net/fm/p3060.c97
-rw-r--r--drivers/net/greth.c10
-rw-r--r--drivers/pci/fsl_pci_init.c116
-rw-r--r--drivers/pci/pci.c6
-rw-r--r--drivers/pci/pci_auto.c2
-rw-r--r--drivers/qe/uec.c15
-rw-r--r--drivers/serial/serial_xuartlite.c34
-rw-r--r--drivers/spi/Makefile1
-rw-r--r--drivers/spi/cf_qspi.c373
-rw-r--r--drivers/spi/kirkwood_spi.c5
-rw-r--r--drivers/spi/mpc8xxx_spi.c4
-rw-r--r--drivers/spi/mxs_spi.c58
-rw-r--r--drivers/spi/tegra_spi.c6
-rw-r--r--drivers/spi/xilinx_spi.c1
-rw-r--r--drivers/usb/host/ehci-hcd.c7
-rw-r--r--drivers/video/omap3_dss.c3
41 files changed, 2188 insertions, 649 deletions
diff --git a/drivers/block/systemace.c b/drivers/block/systemace.c
index 58402b9..247cf06 100644
--- a/drivers/block/systemace.c
+++ b/drivers/block/systemace.c
@@ -51,24 +51,36 @@
* to be the base address for the chip, usually in the local
* peripheral bus.
*/
-#if (CONFIG_SYS_SYSTEMACE_WIDTH == 8)
+
+static u32 base = CONFIG_SYS_SYSTEMACE_BASE;
+static u32 width = CONFIG_SYS_SYSTEMACE_WIDTH;
+
+static void ace_writew(u16 val, unsigned off)
+{
+ if (width == 8) {
#if !defined(__BIG_ENDIAN)
-#define ace_readw(off) ((readb(CONFIG_SYS_SYSTEMACE_BASE+off)<<8) | \
- (readb(CONFIG_SYS_SYSTEMACE_BASE+off+1)))
-#define ace_writew(val, off) {writeb(val>>8, CONFIG_SYS_SYSTEMACE_BASE+off); \
- writeb(val, CONFIG_SYS_SYSTEMACE_BASE+off+1);}
+ writeb(val >> 8, base + off);
+ writeb(val, base + off + 1);
#else
-#define ace_readw(off) ((readb(CONFIG_SYS_SYSTEMACE_BASE+off)) | \
- (readb(CONFIG_SYS_SYSTEMACE_BASE+off+1)<<8))
-#define ace_writew(val, off) {writeb(val, CONFIG_SYS_SYSTEMACE_BASE+off); \
- writeb(val>>8, CONFIG_SYS_SYSTEMACE_BASE+off+1);}
+ writeb(val, base + off);
+ writeb(val >> 8, base + off + 1);
#endif
+ }
+ out16(base + off, val);
+}
+
+static u16 ace_readw(unsigned off)
+{
+ if (width == 8) {
+#if !defined(__BIG_ENDIAN)
+ return (readb(base + off) << 8) | readb(base + off + 1);
#else
-#define ace_readw(off) (in16(CONFIG_SYS_SYSTEMACE_BASE+off))
-#define ace_writew(val, off) (out16(CONFIG_SYS_SYSTEMACE_BASE+off,val))
+ return readb(base + off) | (readb(base + off + 1) << 8);
#endif
+ }
-/* */
+ return in16(base + off);
+}
static unsigned long systemace_read(int dev, unsigned long start,
unsigned long blkcnt, void *buffer);
@@ -121,7 +133,7 @@ block_dev_desc_t *systemace_get_dev(int dev)
/*
* Ensure the correct bus mode (8/16 bits) gets enabled
*/
- ace_writew(CONFIG_SYS_SYSTEMACE_WIDTH == 8 ? 0 : 0x0001, 0);
+ ace_writew(width == 8 ? 0 : 0x0001, 0);
init_part(&systemace_dev);
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index 060145b..5d504df 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -63,10 +63,23 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu,
char *str_env;
int ret;
- sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s %lx",
- op == DFU_OP_READ ? "load" : "write",
- dfu->data.mmc.dev, dfu->data.mmc.part,
- (unsigned int) buf, dfu->name, *len);
+ switch (dfu->layout) {
+ case DFU_FS_FAT:
+ sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s %lx",
+ op == DFU_OP_READ ? "load" : "write",
+ dfu->data.mmc.dev, dfu->data.mmc.part,
+ (unsigned int) buf, dfu->name, *len);
+ break;
+ case DFU_FS_EXT4:
+ sprintf(cmd_buf, "ext4%s mmc %d:%d /%s 0x%x %ld",
+ op == DFU_OP_READ ? "load" : "write",
+ dfu->data.mmc.dev, dfu->data.mmc.part,
+ dfu->name, (unsigned int) buf, *len);
+ break;
+ default:
+ printf("%s: Layout (%s) not (yet) supported!\n", __func__,
+ dfu_get_layout(dfu->layout));
+ }
debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf);
@@ -76,7 +89,7 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu,
return ret;
}
- if (dfu->layout != DFU_RAW_ADDR) {
+ if (dfu->layout != DFU_RAW_ADDR && op == DFU_OP_READ) {
str_env = getenv("filesize");
if (str_env == NULL) {
puts("dfu: Wrong file size!\n");
@@ -107,6 +120,7 @@ int dfu_write_medium_mmc(struct dfu_entity *dfu, void *buf, long *len)
ret = mmc_block_write(dfu, buf, len);
break;
case DFU_FS_FAT:
+ case DFU_FS_EXT4:
ret = mmc_file_write(dfu, buf, len);
break;
default:
@@ -126,6 +140,7 @@ int dfu_read_medium_mmc(struct dfu_entity *dfu, void *buf, long *len)
ret = mmc_block_read(dfu, buf, len);
break;
case DFU_FS_FAT:
+ case DFU_FS_EXT4:
ret = mmc_file_read(dfu, buf, len);
break;
default:
@@ -149,12 +164,17 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s)
dfu->data.mmc.lba_blk_size = get_mmc_blk_size(dfu->dev_num);
} else if (!strcmp(st, "fat")) {
dfu->layout = DFU_FS_FAT;
- dfu->data.mmc.dev = simple_strtoul(s, &s, 10);
- dfu->data.mmc.part = simple_strtoul(++s, &s, 10);
+ } else if (!strcmp(st, "ext4")) {
+ dfu->layout = DFU_FS_EXT4;
} else {
printf("%s: Memory layout (%s) not supported!\n", __func__, st);
}
+ if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) {
+ dfu->data.mmc.dev = simple_strtoul(s, &s, 10);
+ dfu->data.mmc.part = simple_strtoul(++s, &s, 10);
+ }
+
dfu->read_medium = dfu_read_medium_mmc;
dfu->write_medium = dfu_write_medium_mmc;
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c
index 8cfcf82..747f4cf 100644
--- a/drivers/gpio/tegra_gpio.c
+++ b/drivers/gpio/tegra_gpio.c
@@ -34,10 +34,10 @@
#include <asm/gpio.h>
enum {
- TEGRA20_CMD_INFO,
- TEGRA20_CMD_PORT,
- TEGRA20_CMD_OUTPUT,
- TEGRA20_CMD_INPUT,
+ TEGRA_CMD_INFO,
+ TEGRA_CMD_PORT,
+ TEGRA_CMD_OUTPUT,
+ TEGRA_CMD_INPUT,
};
static struct gpio_names {
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 978507b..094305f 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -442,6 +442,14 @@ int i2c_set_bus_num(unsigned int bus)
return -1;
}
+#if I2C_BUS_MAX == 4
+ if (bus == 3)
+ i2c_base = (struct i2c *)I2C_BASE4;
+ else
+ if (bus == 2)
+ i2c_base = (struct i2c *)I2C_BASE3;
+ else
+#endif
#if I2C_BUS_MAX == 3
if (bus == 2)
i2c_base = (struct i2c *)I2C_BASE3;
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index b4eb491..e3be14e 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -262,7 +262,7 @@ exit:
return error;
}
-static int tegra20_i2c_write_data(u32 addr, u8 *data, u32 len)
+static int tegra_i2c_write_data(u32 addr, u8 *data, u32 len)
{
int error;
struct i2c_trans_info trans_info;
@@ -275,12 +275,12 @@ static int tegra20_i2c_write_data(u32 addr, u8 *data, u32 len)
error = send_recv_packets(&i2c_controllers[i2c_bus_num], &trans_info);
if (error)
- debug("tegra20_i2c_write_data: Error (%d) !!!\n", error);
+ debug("tegra_i2c_write_data: Error (%d) !!!\n", error);
return error;
}
-static int tegra20_i2c_read_data(u32 addr, u8 *data, u32 len)
+static int tegra_i2c_read_data(u32 addr, u8 *data, u32 len)
{
int error;
struct i2c_trans_info trans_info;
@@ -293,7 +293,7 @@ static int tegra20_i2c_read_data(u32 addr, u8 *data, u32 len)
error = send_recv_packets(&i2c_controllers[i2c_bus_num], &trans_info);
if (error)
- debug("tegra20_i2c_read_data: Error (%d) !!!\n", error);
+ debug("tegra_i2c_read_data: Error (%d) !!!\n", error);
return error;
}
@@ -438,7 +438,7 @@ int i2c_write_data(uchar chip, uchar *buffer, int len)
debug("\n");
/* Shift 7-bit address over for lower-level i2c functions */
- rc = tegra20_i2c_write_data(chip << 1, buffer, len);
+ rc = tegra_i2c_write_data(chip << 1, buffer, len);
if (rc)
debug("i2c_write_data(): rc=%d\n", rc);
@@ -452,7 +452,7 @@ int i2c_read_data(uchar chip, uchar *buffer, int len)
debug("inside i2c_read_data():\n");
/* Shift 7-bit address over for lower-level i2c functions */
- rc = tegra20_i2c_read_data(chip << 1, buffer, len);
+ rc = tegra_i2c_read_data(chip << 1, buffer, len);
if (rc) {
debug("i2c_read_data(): rc=%d\n", rc);
return rc;
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 68c6a16..0805e86 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libinput.o
COBJS-$(CONFIG_I8042_KBD) += i8042.o
-COBJS-$(CONFIG_TEGRA20_KEYBOARD) += tegra-kbc.o
+COBJS-$(CONFIG_TEGRA_KEYBOARD) += tegra-kbc.o
ifdef CONFIG_PS2KBD
COBJS-y += keyboard.o pc_keyb.o
COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o
diff --git a/drivers/misc/fsl_law.c b/drivers/misc/fsl_law.c
index a7d04b7..223cd5d 100644
--- a/drivers/misc/fsl_law.c
+++ b/drivers/misc/fsl_law.c
@@ -275,5 +275,59 @@ void init_laws(void)
law_table[i].size, law_table[i].trgt_id);
}
+#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE
+ /* check RCW to get which port is used for boot */
+ ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
+ u32 bootloc = in_be32(&gur->rcwsr[6]);
+ /*
+ * in SRIO or PCIE boot we need to set specail LAWs for
+ * SRIO or PCIE interfaces.
+ */
+ switch ((bootloc & FSL_CORENET_RCWSR6_BOOT_LOC) >> 23) {
+ case 0x0: /* boot from PCIE1 */
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_1);
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_1);
+ break;
+ case 0x1: /* boot from PCIE2 */
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_2);
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_2);
+ break;
+ case 0x2: /* boot from PCIE3 */
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_3);
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_PCIE_3);
+ break;
+ case 0x8: /* boot from SRIO1 */
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_RIO_1);
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_RIO_1);
+ break;
+ case 0x9: /* boot from SRIO2 */
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_RIO_2);
+ set_next_law(CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+ LAW_SIZE_1M,
+ LAW_TRGT_IF_RIO_2);
+ break;
+ default:
+ break;
+ }
+#endif
+
return ;
}
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c
index db2c7ab..af1380a 100644
--- a/drivers/mmc/arm_pl180_mmci.c
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -52,7 +52,7 @@ static int wait_for_command_end(struct mmc *dev, struct mmc_cmd *cmd)
debug("CMD%d time out\n", cmd->cmdidx);
return TIMEOUT;
} else if ((hoststatus & SDI_STA_CCRCFAIL) &&
- (cmd->flags & MMC_RSP_CRC)) {
+ (cmd->resp_type & MMC_RSP_CRC)) {
printf("CMD%d CRC error\n", cmd->cmdidx);
return -EILSEQ;
}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index fa673cf..a60cfe1 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -236,7 +236,7 @@ int mmc_send_status(struct mmc *mmc, int timeout)
status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
printf("CURR STATE:%d\n", status);
#endif
- if (!timeout) {
+ if (timeout <= 0) {
printf("Timeout waiting card ready\n");
return TIMEOUT;
}
@@ -658,7 +658,7 @@ int mmc_send_op_cond(struct mmc *mmc)
}
-int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
+int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
{
struct mmc_cmd cmd;
struct mmc_data data;
@@ -669,7 +669,7 @@ int mmc_send_ext_csd(struct mmc *mmc, char *ext_csd)
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
- data.dest = ext_csd;
+ data.dest = (char *)ext_csd;
data.blocks = 1;
data.blocksize = 512;
data.flags = MMC_DATA_READ;
@@ -704,7 +704,7 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
int mmc_change_freq(struct mmc *mmc)
{
- ALLOC_CACHE_ALIGN_BUFFER(char, ext_csd, 512);
+ ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, 512);
char cardtype;
int err;
@@ -963,8 +963,8 @@ int mmc_startup(struct mmc *mmc)
uint mult, freq;
u64 cmult, csize, capacity;
struct mmc_cmd cmd;
- ALLOC_CACHE_ALIGN_BUFFER(char, ext_csd, 512);
- ALLOC_CACHE_ALIGN_BUFFER(char, test_csd, 512);
+ ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, 512);
+ ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, 512);
int timeout = 1000;
#ifdef CONFIG_MMC_SPI_CRC_ON
@@ -1137,7 +1137,8 @@ int mmc_startup(struct mmc *mmc)
}
/* store the partition info of emmc */
- if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT)
+ if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
+ ext_csd[EXT_CSD_BOOT_MULT])
mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
}
@@ -1232,7 +1233,9 @@ int mmc_startup(struct mmc *mmc)
(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff);
sprintf(mmc->block_dev.revision, "%d.%d", mmc->cid[2] >> 28,
(mmc->cid[2] >> 24) & 0xf);
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
init_part(&mmc->block_dev);
+#endif
return 0;
}
@@ -1283,10 +1286,9 @@ int mmc_register(struct mmc *mmc)
block_dev_desc_t *mmc_get_dev(int dev)
{
struct mmc *mmc = find_mmc_device(dev);
- if (!mmc)
+ if (!mmc || mmc_init(mmc))
return NULL;
- mmc_init(mmc);
return &mmc->block_dev;
}
#endif
diff --git a/drivers/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c
index 9a98c6b..c80b41b 100644
--- a/drivers/mmc/mxsmmc.c
+++ b/drivers/mmc/mxsmmc.c
@@ -119,6 +119,10 @@ static int mxsmmc_send_cmd_dma(struct mxsmmc_priv *priv, struct mmc_data *data)
(uint32_t)(priv->desc->cmd.address + cache_data_count));
}
+ /* Invalidate the area, so no writeback into the RAM races with DMA */
+ invalidate_dcache_range((uint32_t)priv->desc->cmd.address,
+ (uint32_t)(priv->desc->cmd.address + cache_data_count));
+
priv->desc->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM |
(data_count << MXS_DMA_DESC_BYTES_OFFSET);
diff --git a/drivers/mmc/pxa_mmc_gen.c b/drivers/mmc/pxa_mmc_gen.c
index 2c5bf17..b3ec441 100644
--- a/drivers/mmc/pxa_mmc_gen.c
+++ b/drivers/mmc/pxa_mmc_gen.c
@@ -118,7 +118,7 @@ static int pxa_mmc_start_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
int ret;
/* The card can send a "busy" response */
- if (cmd->flags & MMC_RSP_BUSY)
+ if (cmd->resp_type & MMC_RSP_BUSY)
cmdat |= MMC_CMDAT_BUSY;
/* Inform the controller about response type */
@@ -181,9 +181,11 @@ static int pxa_mmc_cmd_done(struct mmc *mmc, struct mmc_cmd *cmd)
/* The command response didn't arrive */
if (stat & MMC_STAT_TIME_OUT_RESPONSE)
return -ETIMEDOUT;
- else if (stat & MMC_STAT_RES_CRC_ERROR && cmd->flags & MMC_RSP_CRC) {
+ else if (stat & MMC_STAT_RES_CRC_ERROR
+ && cmd->resp_type & MMC_RSP_CRC) {
#ifdef PXAMMC_CRC_SKIP
- if (cmd->flags & MMC_RSP_136 && cmd->response[0] & (1 << 31))
+ if (cmd->resp_type & MMC_RSP_136
+ && cmd->response[0] & (1 << 31))
printf("Ignoring CRC, this may be dangerous!\n");
else
#endif
diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index 1d4481b..b978236 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -21,6 +21,7 @@
#include <malloc.h>
#include <sdhci.h>
#include <asm/arch/mmc.h>
+#include <asm/arch/clk.h>
static char *S5P_NAME = "SAMSUNG SDHCI";
static void s5p_sdhci_set_control_reg(struct sdhci_host *host)
@@ -54,7 +55,7 @@ static void s5p_sdhci_set_control_reg(struct sdhci_host *host)
* 00 = Delay3 (inverter delay)
* 10 = Delay4 (inverter delay + 2ns)
*/
- val = SDHCI_CTRL3_FCSEL3 | SDHCI_CTRL3_FCSEL1;
+ val = SDHCI_CTRL3_FCSEL0 | SDHCI_CTRL3_FCSEL1;
sdhci_writel(host, val, SDHCI_CONTROL3);
/*
@@ -69,7 +70,7 @@ static void s5p_sdhci_set_control_reg(struct sdhci_host *host)
sdhci_writel(host, ctrl, SDHCI_CONTROL2);
}
-int s5p_sdhci_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks)
+int s5p_sdhci_init(u32 regbase, int index, int bus_width)
{
struct sdhci_host *host = NULL;
host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host));
@@ -80,19 +81,18 @@ int s5p_sdhci_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks)
host->name = S5P_NAME;
host->ioaddr = (void *)regbase;
- host->quirks = quirks;
- host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE;
+ host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE |
+ SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR;
host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
- if (quirks & SDHCI_QUIRK_REG32_RW)
- host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
- else
- host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
+ host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
host->set_control_reg = &s5p_sdhci_set_control_reg;
+ host->set_clock = set_mmc_clk;
+ host->index = index;
host->host_caps = MMC_MODE_HC;
- add_sdhci(host, max_clk, min_clk);
+ add_sdhci(host, 52000000, 400000);
return 0;
}
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 1709643..2e3c408 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -260,7 +260,7 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
if (clock == 0)
return 0;
- if (host->version >= SDHCI_SPEC_300) {
+ if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) {
/* Version 3.00 divisors must be a multiple of 2. */
if (mmc->f_max <= clock)
div = 1;
@@ -279,6 +279,9 @@ static int sdhci_set_clock(struct mmc *mmc, unsigned int clock)
}
div >>= 1;
+ if (host->set_clock)
+ host->set_clock(host->index, div);
+
clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
<< SDHCI_DIVIDER_HI_SHIFT;
@@ -347,10 +350,10 @@ void sdhci_set_ios(struct mmc *mmc)
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if (mmc->bus_width == 8) {
ctrl &= ~SDHCI_CTRL_4BITBUS;
- if (host->version >= SDHCI_SPEC_300)
+ if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
ctrl |= SDHCI_CTRL_8BITBUS;
} else {
- if (host->version >= SDHCI_SPEC_300)
+ if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
ctrl &= ~SDHCI_CTRL_8BITBUS;
if (mmc->bus_width == 4)
ctrl |= SDHCI_CTRL_4BITBUS;
@@ -381,12 +384,25 @@ int sdhci_init(struct mmc *mmc)
}
}
+ sdhci_set_power(host, fls(mmc->voltages) - 1);
+
+ if (host->quirks & SDHCI_QUIRK_NO_CD) {
+ unsigned int status;
+
+ sdhci_writel(host, SDHCI_CTRL_CD_TEST_INS | SDHCI_CTRL_CD_TEST,
+ SDHCI_HOST_CONTROL);
+
+ status = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ while ((!(status & SDHCI_CARD_PRESENT)) ||
+ (!(status & SDHCI_CARD_STATE_STABLE)) ||
+ (!(status & SDHCI_CARD_DETECT_PIN_LEVEL)))
+ status = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ }
+
/* Eable all state */
sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_INT_ENABLE);
sdhci_writel(host, SDHCI_INT_ALL_MASK, SDHCI_SIGNAL_ENABLE);
- sdhci_set_power(host, fls(mmc->voltages) - 1);
-
return 0;
}
@@ -421,7 +437,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
if (max_clk)
mmc->f_max = max_clk;
else {
- if (host->version >= SDHCI_SPEC_300)
+ if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
mmc->f_max = (caps & SDHCI_CLOCK_V3_BASE_MASK)
>> SDHCI_CLOCK_BASE_SHIFT;
else
@@ -436,7 +452,7 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk)
if (min_clk)
mmc->f_min = min_clk;
else {
- if (host->version >= SDHCI_SPEC_300)
+ if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300)
mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_300;
else
mmc->f_min = mmc->f_max / SDHCI_MAX_DIV_SPEC_200;
diff --git a/drivers/mmc/sh_mmcif.c b/drivers/mmc/sh_mmcif.c
index 2835e24..4588568 100644
--- a/drivers/mmc/sh_mmcif.c
+++ b/drivers/mmc/sh_mmcif.c
@@ -593,7 +593,7 @@ int mmcif_mmc_init(void)
mmc->f_max = CLKDEV_EMMC_DATA;
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT |
- MMC_MODE_8BIT;
+ MMC_MODE_8BIT | MMC_MODE_HC;
memcpy(mmc->name, DRIVER_NAME, sizeof(DRIVER_NAME));
mmc->send_cmd = sh_mmcif_request;
mmc->set_ios = sh_mmcif_set_ios;
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index ddfa727..ca8fad8 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -25,7 +25,7 @@
#include <asm/io.h>
#include <asm/arch/clk_rst.h>
#include <asm/arch/clock.h>
-#include "tegra_mmc.h"
+#include <asm/arch/tegra_mmc.h>
/* support 4 mmc hosts */
struct mmc mmc_dev[4];
@@ -39,31 +39,31 @@ struct mmc_host mmc_host[4];
* @param host Structure to fill in (base, reg, mmc_id)
* @param dev_index Device index (0-3)
*/
-static void tegra20_get_setup(struct mmc_host *host, int dev_index)
+static void tegra_get_setup(struct mmc_host *host, int dev_index)
{
- debug("tegra20_get_base_mmc: dev_index = %d\n", dev_index);
+ debug("tegra_get_setup: dev_index = %d\n", dev_index);
switch (dev_index) {
case 1:
- host->base = TEGRA20_SDMMC3_BASE;
+ host->base = TEGRA_SDMMC3_BASE;
host->mmc_id = PERIPH_ID_SDMMC3;
break;
case 2:
- host->base = TEGRA20_SDMMC2_BASE;
+ host->base = TEGRA_SDMMC2_BASE;
host->mmc_id = PERIPH_ID_SDMMC2;
break;
case 3:
- host->base = TEGRA20_SDMMC1_BASE;
+ host->base = TEGRA_SDMMC1_BASE;
host->mmc_id = PERIPH_ID_SDMMC1;
break;
case 0:
default:
- host->base = TEGRA20_SDMMC4_BASE;
+ host->base = TEGRA_SDMMC4_BASE;
host->mmc_id = PERIPH_ID_SDMMC4;
break;
}
- host->reg = (struct tegra20_mmc *)host->base;
+ host->reg = (struct tegra_mmc *)host->base;
}
static void mmc_prepare_data(struct mmc_host *host, struct mmc_data *data)
@@ -345,7 +345,7 @@ static void mmc_change_clock(struct mmc_host *host, uint clock)
debug(" mmc_change_clock called\n");
/*
- * Change Tegra20 SDMMCx clock divisor here. Source is 216MHz,
+ * Change Tegra SDMMCx clock divisor here. Source is 216MHz,
* PLLP_OUT0
*/
if (clock == 0)
@@ -494,11 +494,11 @@ static int mmc_core_init(struct mmc *mmc)
return 0;
}
-int tegra20_mmc_getcd(struct mmc *mmc)
+int tegra_mmc_getcd(struct mmc *mmc)
{
struct mmc_host *host = (struct mmc_host *)mmc->priv;
- debug("tegra20_mmc_getcd called\n");
+ debug("tegra_mmc_getcd called\n");
if (host->cd_gpio >= 0)
return !gpio_get_value(host->cd_gpio);
@@ -506,13 +506,13 @@ int tegra20_mmc_getcd(struct mmc *mmc)
return 1;
}
-int tegra20_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
+int tegra_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
{
struct mmc_host *host;
char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */
struct mmc *mmc;
- debug(" tegra20_mmc_init: index %d, bus width %d "
+ debug(" tegra_mmc_init: index %d, bus width %d "
"pwr_gpio %d cd_gpio %d\n",
dev_index, bus_width, pwr_gpio, cd_gpio);
@@ -521,7 +521,7 @@ int tegra20_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
host->clock = 0;
host->pwr_gpio = pwr_gpio;
host->cd_gpio = cd_gpio;
- tegra20_get_setup(host, dev_index);
+ tegra_get_setup(host, dev_index);
clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000);
@@ -539,12 +539,12 @@ int tegra20_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
mmc = &mmc_dev[dev_index];
- sprintf(mmc->name, "Tegra20 SD/MMC");
+ sprintf(mmc->name, "Tegra SD/MMC");
mmc->priv = host;
mmc->send_cmd = mmc_send_cmd;
mmc->set_ios = mmc_set_ios;
mmc->init = mmc_core_init;
- mmc->getcd = tegra20_mmc_getcd;
+ mmc->getcd = tegra_mmc_getcd;
mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
if (bus_width == 8)
@@ -559,7 +559,7 @@ int tegra20_mmc_init(int dev_index, int bus_width, int pwr_gpio, int cd_gpio)
* max freq is highest HS eMMC clock as per the SD/MMC spec
* (actually 52MHz)
* Both of these are the closest equivalents w/216MHz source
- * clock and Tegra20 SDMMC divisors.
+ * clock and Tegra SDMMC divisors.
*/
mmc->f_min = 375000;
mmc->f_max = 48000000;
diff --git a/drivers/mmc/tegra_mmc.h b/drivers/mmc/tegra_mmc.h
deleted file mode 100644
index b1f2564..0000000
--- a/drivers/mmc/tegra_mmc.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * (C) Copyright 2009 SAMSUNG Electronics
- * Minkyu Kang <mk7.kang@samsung.com>
- * Portions Copyright (C) 2011-2012 NVIDIA Corporation
- *
- * 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
- *
- */
-
-#ifndef __TEGRA_MMC_H_
-#define __TEGRA_MMC_H_
-
-#define TEGRA20_SDMMC1_BASE 0xC8000000
-#define TEGRA20_SDMMC2_BASE 0xC8000200
-#define TEGRA20_SDMMC3_BASE 0xC8000400
-#define TEGRA20_SDMMC4_BASE 0xC8000600
-
-#ifndef __ASSEMBLY__
-struct tegra20_mmc {
- unsigned int sysad; /* _SYSTEM_ADDRESS_0 */
- unsigned short blksize; /* _BLOCK_SIZE_BLOCK_COUNT_0 15:00 */
- unsigned short blkcnt; /* _BLOCK_SIZE_BLOCK_COUNT_0 31:16 */
- unsigned int argument; /* _ARGUMENT_0 */
- unsigned short trnmod; /* _CMD_XFER_MODE_0 15:00 xfer mode */
- unsigned short cmdreg; /* _CMD_XFER_MODE_0 31:16 cmd reg */
- unsigned int rspreg0; /* _RESPONSE_R0_R1_0 CMD RESP 31:00 */
- unsigned int rspreg1; /* _RESPONSE_R2_R3_0 CMD RESP 63:32 */
- unsigned int rspreg2; /* _RESPONSE_R4_R5_0 CMD RESP 95:64 */
- unsigned int rspreg3; /* _RESPONSE_R6_R7_0 CMD RESP 127:96 */
- unsigned int bdata; /* _BUFFER_DATA_PORT_0 */
- unsigned int prnsts; /* _PRESENT_STATE_0 */
- unsigned char hostctl; /* _POWER_CONTROL_HOST_0 7:00 */
- unsigned char pwrcon; /* _POWER_CONTROL_HOST_0 15:8 */
- unsigned char blkgap; /* _POWER_CONTROL_HOST_9 23:16 */
- unsigned char wakcon; /* _POWER_CONTROL_HOST_0 31:24 */
- unsigned short clkcon; /* _CLOCK_CONTROL_0 15:00 */
- unsigned char timeoutcon; /* _TIMEOUT_CTRL 23:16 */
- unsigned char swrst; /* _SW_RESET_ 31:24 */
- unsigned int norintsts; /* _INTERRUPT_STATUS_0 */
- unsigned int norintstsen; /* _INTERRUPT_STATUS_ENABLE_0 */
- unsigned int norintsigen; /* _INTERRUPT_SIGNAL_ENABLE_0 */
- unsigned short acmd12errsts; /* _AUTO_CMD12_ERR_STATUS_0 15:00 */
- unsigned char res1[2]; /* _RESERVED 31:16 */
- unsigned int capareg; /* _CAPABILITIES_0 */
- unsigned char res2[4]; /* RESERVED, offset 44h-47h */
- unsigned int maxcurr; /* _MAXIMUM_CURRENT_0 */
- unsigned char res3[4]; /* RESERVED, offset 4Ch-4Fh */
- unsigned short setacmd12err; /* offset 50h */
- unsigned short setinterr; /* offset 52h */
- unsigned char admaerr; /* offset 54h */
- unsigned char res4[3]; /* RESERVED, offset 55h-57h */
- unsigned long admaaddr; /* offset 58h-5Fh */
- unsigned char res5[0x9c]; /* RESERVED, offset 60h-FBh */
- unsigned short slotintstatus; /* offset FCh */
- unsigned short hcver; /* HOST Version */
- unsigned char res6[0x100]; /* RESERVED, offset 100h-1FFh */
-};
-
-#define TEGRA_MMC_HOSTCTL_DMASEL_MASK (3 << 3)
-#define TEGRA_MMC_HOSTCTL_DMASEL_SDMA (0 << 3)
-#define TEGRA_MMC_HOSTCTL_DMASEL_ADMA2_32BIT (2 << 3)
-#define TEGRA_MMC_HOSTCTL_DMASEL_ADMA2_64BIT (3 << 3)
-
-#define TEGRA_MMC_TRNMOD_DMA_ENABLE (1 << 0)
-#define TEGRA_MMC_TRNMOD_BLOCK_COUNT_ENABLE (1 << 1)
-#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_WRITE (0 << 4)
-#define TEGRA_MMC_TRNMOD_DATA_XFER_DIR_SEL_READ (1 << 4)
-#define TEGRA_MMC_TRNMOD_MULTI_BLOCK_SELECT (1 << 5)
-
-#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_MASK (3 << 0)
-#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_NO_RESPONSE (0 << 0)
-#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_136 (1 << 0)
-#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48 (2 << 0)
-#define TEGRA_MMC_CMDREG_RESP_TYPE_SELECT_LENGTH_48_BUSY (3 << 0)
-
-#define TEGRA_MMC_TRNMOD_CMD_CRC_CHECK (1 << 3)
-#define TEGRA_MMC_TRNMOD_CMD_INDEX_CHECK (1 << 4)
-#define TEGRA_MMC_TRNMOD_DATA_PRESENT_SELECT_DATA_TRANSFER (1 << 5)
-
-#define TEGRA_MMC_PRNSTS_CMD_INHIBIT_CMD (1 << 0)
-#define TEGRA_MMC_PRNSTS_CMD_INHIBIT_DAT (1 << 1)
-
-#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_ENABLE (1 << 0)
-#define TEGRA_MMC_CLKCON_INTERNAL_CLOCK_STABLE (1 << 1)
-#define TEGRA_MMC_CLKCON_SD_CLOCK_ENABLE (1 << 2)
-
-#define TEGRA_MMC_CLKCON_SDCLK_FREQ_SEL_SHIFT 8
-#define TEGRA_MMC_CLKCON_SDCLK_FREQ_SEL_MASK (0xff << 8)
-
-#define TEGRA_MMC_SWRST_SW_RESET_FOR_ALL (1 << 0)
-#define TEGRA_MMC_SWRST_SW_RESET_FOR_CMD_LINE (1 << 1)
-#define TEGRA_MMC_SWRST_SW_RESET_FOR_DAT_LINE (1 << 2)
-
-#define TEGRA_MMC_NORINTSTS_CMD_COMPLETE (1 << 0)
-#define TEGRA_MMC_NORINTSTS_XFER_COMPLETE (1 << 1)
-#define TEGRA_MMC_NORINTSTS_DMA_INTERRUPT (1 << 3)
-#define TEGRA_MMC_NORINTSTS_ERR_INTERRUPT (1 << 15)
-#define TEGRA_MMC_NORINTSTS_CMD_TIMEOUT (1 << 16)
-
-#define TEGRA_MMC_NORINTSTSEN_CMD_COMPLETE (1 << 0)
-#define TEGRA_MMC_NORINTSTSEN_XFER_COMPLETE (1 << 1)
-#define TEGRA_MMC_NORINTSTSEN_DMA_INTERRUPT (1 << 3)
-#define TEGRA_MMC_NORINTSTSEN_BUFFER_WRITE_READY (1 << 4)
-#define TEGRA_MMC_NORINTSTSEN_BUFFER_READ_READY (1 << 5)
-
-#define TEGRA_MMC_NORINTSIGEN_XFER_COMPLETE (1 << 1)
-
-struct mmc_host {
- struct tegra20_mmc *reg;
- unsigned int version; /* SDHCI spec. version */
- unsigned int clock; /* Current clock (MHz) */
- unsigned int base; /* Base address, SDMMC1/2/3/4 */
- enum periph_id mmc_id; /* Peripheral ID: PERIPH_ID_... */
- int pwr_gpio; /* Power GPIO */
- int cd_gpio; /* Change Detect GPIO */
-};
-
-#endif /* __ASSEMBLY__ */
-#endif /* __TEGRA_MMC_H_ */
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 29dc20e..beb99ca 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -62,6 +62,7 @@ COBJS-$(CONFIG_NAND_NOMADIK) += nomadik.o
COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o
COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o
COBJS-$(CONFIG_NAND_SPEAR) += spr_nand.o
+COBJS-$(CONFIG_TEGRA_NAND) += tegra_nand.o
COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o
endif
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 936186f..d0ded48 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -25,168 +25,23 @@
#if defined(CONFIG_MX25) || defined(CONFIG_MX27) || defined(CONFIG_MX35)
#include <asm/arch/imx-regs.h>
#endif
+#include <fsl_nfc.h>
#define DRIVER_NAME "mxc_nand"
-/*
- * TODO: Use same register defs here as nand_spl mxc nand driver.
- */
-/*
- * Register map and bit definitions for the Freescale NAND Flash Controller
- * present in various i.MX devices.
- *
- * MX31 and MX27 have version 1 which has
- * 4 512 byte main buffers and
- * 4 16 byte spare buffers
- * to support up to 2K byte pagesize nand.
- * Reading or writing a 2K page requires 4 FDI/FDO cycles.
- *
- * MX25 has version 1.1 which has
- * 8 512 byte main buffers and
- * 8 64 byte spare buffers
- * to support up to 4K byte pagesize nand.
- * Reading or writing a 2K or 4K page requires only 1 FDI/FDO cycle.
- * Also some of registers are moved and/or changed meaning as seen below.
- */
-#if defined(CONFIG_MX31) || defined(CONFIG_MX27)
-#define MXC_NFC_V1
-#elif defined(CONFIG_MX25) || defined(CONFIG_MX35)
-#define MXC_NFC_V1_1
-#else
-#warning "MXC NFC version not defined"
-#endif
-
-#if defined(MXC_NFC_V1)
-#define NAND_MXC_NR_BUFS 4
-#define NAND_MXC_SPARE_BUF_SIZE 16
-#define NAND_MXC_REG_OFFSET 0xe00
-#define is_mxc_nfc_11() 0
-#elif defined(MXC_NFC_V1_1)
-#define NAND_MXC_NR_BUFS 8
-#define NAND_MXC_SPARE_BUF_SIZE 64
-#define NAND_MXC_REG_OFFSET 0x1e00
-#define is_mxc_nfc_11() 1
-#else
-#error "define CONFIG_NAND_MXC_VXXX to use mtd mxc nand driver"
-#endif
-struct nfc_regs {
- uint8_t main_area[NAND_MXC_NR_BUFS][0x200];
- uint8_t spare_area[NAND_MXC_NR_BUFS][NAND_MXC_SPARE_BUF_SIZE];
- /*
- * reserved size is offset of nfc registers
- * minus total main and spare sizes
- */
- uint8_t reserved1[NAND_MXC_REG_OFFSET
- - NAND_MXC_NR_BUFS * (512 + NAND_MXC_SPARE_BUF_SIZE)];
-#if defined(MXC_NFC_V1)
- uint16_t nfc_buf_size;
- uint16_t reserved2;
- uint16_t nfc_buf_addr;
- uint16_t nfc_flash_addr;
- uint16_t nfc_flash_cmd;
- uint16_t nfc_config;
- uint16_t nfc_ecc_status_result;
- uint16_t nfc_rsltmain_area;
- uint16_t nfc_rsltspare_area;
- uint16_t nfc_wrprot;
- uint16_t nfc_unlockstart_blkaddr;
- uint16_t nfc_unlockend_blkaddr;
- uint16_t nfc_nf_wrprst;
- uint16_t nfc_config1;
- uint16_t nfc_config2;
-#elif defined(MXC_NFC_V1_1)
- uint16_t reserved2[2];
- uint16_t nfc_buf_addr;
- uint16_t nfc_flash_addr;
- uint16_t nfc_flash_cmd;
- uint16_t nfc_config;
- uint16_t nfc_ecc_status_result;
- uint16_t nfc_ecc_status_result2;
- uint16_t nfc_spare_area_size;
- uint16_t nfc_wrprot;
- uint16_t reserved3[2];
- uint16_t nfc_nf_wrprst;
- uint16_t nfc_config1;
- uint16_t nfc_config2;
- uint16_t reserved4;
- uint16_t nfc_unlockstart_blkaddr;
- uint16_t nfc_unlockend_blkaddr;
- uint16_t nfc_unlockstart_blkaddr1;
- uint16_t nfc_unlockend_blkaddr1;
- uint16_t nfc_unlockstart_blkaddr2;
- uint16_t nfc_unlockend_blkaddr2;
- uint16_t nfc_unlockstart_blkaddr3;
- uint16_t nfc_unlockend_blkaddr3;
-#endif
-};
-
-/*
- * Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register
- * for Command operation
- */
-#define NFC_CMD 0x1
-
-/*
- * Set INT to 0, FADD to 1, rest to 0 in NFC_CONFIG2 Register
- * for Address operation
- */
-#define NFC_ADDR 0x2
-
-/*
- * Set INT to 0, FDI to 1, rest to 0 in NFC_CONFIG2 Register
- * for Input operation
- */
-#define NFC_INPUT 0x4
-
-/*
- * Set INT to 0, FDO to 001, rest to 0 in NFC_CONFIG2 Register
- * for Data Output operation
- */
-#define NFC_OUTPUT 0x8
-
-/*
- * Set INT to 0, FD0 to 010, rest to 0 in NFC_CONFIG2 Register
- * for Read ID operation
- */
-#define NFC_ID 0x10
-
-/*
- * Set INT to 0, FDO to 100, rest to 0 in NFC_CONFIG2 Register
- * for Read Status operation
- */
-#define NFC_STATUS 0x20
-
-/*
- * Set INT to 1, rest to 0 in NFC_CONFIG2 Register for Read
- * Status operation
- */
-#define NFC_INT 0x8000
-
-#ifdef MXC_NFC_V1_1
-#define NFC_4_8N_ECC (1 << 0)
-#else
-#define NFC_4_8N_ECC 0
-#endif
-#define NFC_SP_EN (1 << 2)
-#define NFC_ECC_EN (1 << 3)
-#define NFC_BIG (1 << 5)
-#define NFC_RST (1 << 6)
-#define NFC_CE (1 << 7)
-#define NFC_ONE_CYCLE (1 << 8)
-
typedef enum {false, true} bool;
struct mxc_nand_host {
- struct mtd_info mtd;
- struct nand_chip *nand;
-
- struct nfc_regs __iomem *regs;
- int spare_only;
- int status_request;
- int pagesize_2k;
- int clk_act;
- uint16_t col_addr;
- unsigned int page_addr;
+ struct mtd_info mtd;
+ struct nand_chip *nand;
+
+ struct fsl_nfc_regs __iomem *regs;
+ int spare_only;
+ int status_request;
+ int pagesize_2k;
+ int clk_act;
+ uint16_t col_addr;
+ unsigned int page_addr;
};
static struct mxc_nand_host mxc_host;
@@ -222,7 +77,7 @@ static struct nand_ecclayout nand_hw_eccoob2k = {
.oobfree = { {2, 4}, {11, 11}, {27, 11}, {43, 11}, {59, 5} },
};
#endif
-#elif defined(MXC_NFC_V1_1)
+#elif defined(MXC_NFC_V2_1)
#ifndef CONFIG_SYS_NAND_LARGEPAGE
static struct nand_ecclayout nand_hw_eccoob = {
.eccbytes = 9,
@@ -268,8 +123,7 @@ static int is_16bit_nand(void)
#elif defined(CONFIG_MX25) || defined(CONFIG_MX35)
static int is_16bit_nand(void)
{
- struct ccm_regs *ccm =
- (struct ccm_regs *)IMX_CCM_BASE;
+ struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
if (readl(&ccm->rcsr) & CCM_RCSR_NF_16BIT_SEL)
return 1;
@@ -304,10 +158,10 @@ static void wait_op_done(struct mxc_nand_host *host, int max_retries,
uint32_t tmp;
while (max_retries-- > 0) {
- if (readw(&host->regs->nfc_config2) & NFC_INT) {
- tmp = readw(&host->regs->nfc_config2);
+ if (readw(&host->regs->config2) & NFC_INT) {
+ tmp = readw(&host->regs->config2);
tmp &= ~NFC_INT;
- writew(tmp, &host->regs->nfc_config2);
+ writew(tmp, &host->regs->config2);
break;
}
udelay(1);
@@ -326,8 +180,8 @@ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd)
{
MTDDEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x)\n", cmd);
- writew(cmd, &host->regs->nfc_flash_cmd);
- writew(NFC_CMD, &host->regs->nfc_config2);
+ writew(cmd, &host->regs->flash_cmd);
+ writew(NFC_CMD, &host->regs->config2);
/* Wait for operation to complete */
wait_op_done(host, TROP_US_DELAY, cmd);
@@ -342,8 +196,8 @@ static void send_addr(struct mxc_nand_host *host, uint16_t addr)
{
MTDDEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x)\n", addr);
- writew(addr, &host->regs->nfc_flash_addr);
- writew(NFC_ADDR, &host->regs->nfc_config2);
+ writew(addr, &host->regs->flash_addr);
+ writew(NFC_ADDR, &host->regs->config2);
/* Wait for operation to complete */
wait_op_done(host, TROP_US_DELAY, addr);
@@ -359,7 +213,7 @@ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
if (spare_only)
MTDDEBUG(MTD_DEBUG_LEVEL1, "send_prog_page (%d)\n", spare_only);
- if (is_mxc_nfc_11()) {
+ if (is_mxc_nfc_21()) {
int i;
/*
* The controller copies the 64 bytes of spare data from
@@ -375,19 +229,19 @@ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
}
}
- writew(buf_id, &host->regs->nfc_buf_addr);
+ writew(buf_id, &host->regs->buf_addr);
/* Configure spare or page+spare access */
if (!host->pagesize_2k) {
- uint16_t config1 = readw(&host->regs->nfc_config1);
+ uint16_t config1 = readw(&host->regs->config1);
if (spare_only)
config1 |= NFC_SP_EN;
else
- config1 &= ~(NFC_SP_EN);
- writew(config1, &host->regs->nfc_config1);
+ config1 &= ~NFC_SP_EN;
+ writew(config1, &host->regs->config1);
}
- writew(NFC_INPUT, &host->regs->nfc_config2);
+ writew(NFC_INPUT, &host->regs->config2);
/* Wait for operation to complete */
wait_op_done(host, TROP_US_DELAY, spare_only);
@@ -402,24 +256,24 @@ static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id,
{
MTDDEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only);
- writew(buf_id, &host->regs->nfc_buf_addr);
+ writew(buf_id, &host->regs->buf_addr);
/* Configure spare or page+spare access */
if (!host->pagesize_2k) {
- uint32_t config1 = readw(&host->regs->nfc_config1);
+ uint32_t config1 = readw(&host->regs->config1);
if (spare_only)
config1 |= NFC_SP_EN;
else
config1 &= ~NFC_SP_EN;
- writew(config1, &host->regs->nfc_config1);
+ writew(config1, &host->regs->config1);
}
- writew(NFC_OUTPUT, &host->regs->nfc_config2);
+ writew(NFC_OUTPUT, &host->regs->config2);
/* Wait for operation to complete */
wait_op_done(host, TROP_US_DELAY, spare_only);
- if (is_mxc_nfc_11()) {
+ if (is_mxc_nfc_21()) {
int i;
/*
@@ -442,14 +296,14 @@ static void send_read_id(struct mxc_nand_host *host)
uint16_t tmp;
/* NANDFC buffer 0 is used for device ID output */
- writew(0x0, &host->regs->nfc_buf_addr);
+ writew(0x0, &host->regs->buf_addr);
/* Read ID into main buffer */
- tmp = readw(&host->regs->nfc_config1);
+ tmp = readw(&host->regs->config1);
tmp &= ~NFC_SP_EN;
- writew(tmp, &host->regs->nfc_config1);
+ writew(tmp, &host->regs->config1);
- writew(NFC_ID, &host->regs->nfc_config2);
+ writew(NFC_ID, &host->regs->config2);
/* Wait for operation to complete */
wait_op_done(host, TROP_US_DELAY, 0);
@@ -469,14 +323,14 @@ static uint16_t get_dev_status(struct mxc_nand_host *host)
/* store the main area1 first word, later do recovery */
store = readl(main_buf);
/* NANDFC buffer 1 is used for device status */
- writew(1, &host->regs->nfc_buf_addr);
+ writew(1, &host->regs->buf_addr);
/* Read status into main buffer */
- tmp = readw(&host->regs->nfc_config1);
+ tmp = readw(&host->regs->config1);
tmp &= ~NFC_SP_EN;
- writew(tmp, &host->regs->nfc_config1);
+ writew(tmp, &host->regs->config1);
- writew(NFC_STATUS, &host->regs->nfc_config2);
+ writew(NFC_STATUS, &host->regs->config2);
/* Wait for operation to complete */
wait_op_done(host, TROP_US_DELAY, 0);
@@ -501,29 +355,29 @@ static int mxc_nand_dev_ready(struct mtd_info *mtd)
return 1;
}
-#ifdef CONFIG_MXC_NAND_HWECC
-static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
-{
- /*
- * If HW ECC is enabled, we turn it on during init. There is
- * no need to enable again here.
- */
-}
-
-#ifdef MXC_NFC_V1_1
static void _mxc_nand_enable_hwecc(struct mtd_info *mtd, int on)
{
struct nand_chip *nand_chip = mtd->priv;
struct mxc_nand_host *host = nand_chip->priv;
- uint16_t tmp = readw(&host->regs->nfc_config1);
+ uint16_t tmp = readw(&host->regs->config1);
if (on)
tmp |= NFC_ECC_EN;
else
tmp &= ~NFC_ECC_EN;
- writew(tmp, &host->regs->nfc_config1);
+ writew(tmp, &host->regs->config1);
+}
+
+#ifdef CONFIG_MXC_NAND_HWECC
+static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ /*
+ * If HW ECC is enabled, we turn it on during init. There is
+ * no need to enable again here.
+ */
}
+#ifdef MXC_NFC_V2_1
static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd,
struct nand_chip *chip,
int page, int sndcmd)
@@ -616,7 +470,7 @@ static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd,
size = mtd->oobsize - (oob - chip->oob_poi);
if (size)
chip->read_buf(mtd, oob, size);
- _mxc_nand_enable_hwecc(mtd, 0);
+ _mxc_nand_enable_hwecc(mtd, 1);
return 0;
}
@@ -799,7 +653,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
{
struct nand_chip *nand_chip = mtd->priv;
struct mxc_nand_host *host = nand_chip->priv;
- uint16_t ecc_status = readw(&host->regs->nfc_ecc_status_result);
+ uint32_t ecc_status = readl(&host->regs->ecc_status_result);
int subpages = mtd->writesize / nand_chip->subpagesize;
int pg2blk_shift = nand_chip->phys_erase_shift -
nand_chip->page_shift;
@@ -832,7 +686,6 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
#define mxc_nand_write_page_syndrome NULL
#define mxc_nand_write_page_raw_syndrome NULL
#define mxc_nand_write_oob_syndrome NULL
-#define mxc_nfc_11_nand_correct_data NULL
static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
@@ -845,7 +698,7 @@ static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat,
* additional correction. 2-Bit errors cannot be corrected by
* HW ECC, so we need to return failure
*/
- uint16_t ecc_status = readw(&host->regs->nfc_ecc_status_result);
+ uint16_t ecc_status = readw(&host->regs->ecc_status_result);
if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
MTDDEBUG(MTD_DEBUG_LEVEL0,
@@ -1208,7 +1061,7 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command,
case NAND_CMD_PAGEPROG:
send_prog_page(host, 0, host->spare_only);
- if (host->pagesize_2k && !is_mxc_nfc_11()) {
+ if (host->pagesize_2k && is_mxc_nfc_1()) {
/* data in 4 areas */
send_prog_page(host, 1, host->spare_only);
send_prog_page(host, 2, host->spare_only);
@@ -1258,7 +1111,7 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command,
send_cmd(host, NAND_CMD_READSTART);
/* read for each AREA */
send_read_page(host, 0, host->spare_only);
- if (!is_mxc_nfc_11()) {
+ if (is_mxc_nfc_1()) {
send_read_page(host, 1, host->spare_only);
send_read_page(host, 2, host->spare_only);
send_read_page(host, 3, host->spare_only);
@@ -1284,24 +1137,6 @@ void mxc_nand_command(struct mtd_info *mtd, unsigned command,
}
}
-#ifdef MXC_NFC_V1_1
-static void mxc_setup_config1(void)
-{
- uint16_t tmp;
-
- tmp = readw(&host->regs->nfc_config1);
- tmp |= NFC_ONE_CYCLE;
- tmp |= NFC_4_8N_ECC;
- writew(tmp, &host->regs->nfc_config1);
- if (host->pagesize_2k)
- writew(64/2, &host->regs->nfc_spare_area_size);
- else
- writew(16/2, &host->regs->nfc_spare_area_size);
-}
-#else
-#define mxc_setup_config1()
-#endif
-
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
@@ -1332,8 +1167,9 @@ static struct nand_bbt_descr bbt_mirror_descr = {
int board_nand_init(struct nand_chip *this)
{
struct mtd_info *mtd;
+#ifdef MXC_NFC_V2_1
uint16_t tmp;
- int err = 0;
+#endif
#ifdef CONFIG_SYS_NAND_USE_FLASH_BBT
this->options |= NAND_USE_FLASH_BBT;
@@ -1359,14 +1195,14 @@ int board_nand_init(struct nand_chip *this)
this->read_buf = mxc_nand_read_buf;
this->verify_buf = mxc_nand_verify_buf;
- host->regs = (struct nfc_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE;
+ host->regs = (struct fsl_nfc_regs __iomem *)CONFIG_MXC_NAND_REGS_BASE;
host->clk_act = 1;
#ifdef CONFIG_MXC_NAND_HWECC
this->ecc.calculate = mxc_nand_calculate_ecc;
this->ecc.hwctl = mxc_nand_enable_hwecc;
this->ecc.correct = mxc_nand_correct_data;
- if (is_mxc_nfc_11()) {
+ if (is_mxc_nfc_21()) {
this->ecc.mode = NAND_ECC_HW_SYNDROME;
this->ecc.read_page = mxc_nand_read_page_syndrome;
this->ecc.read_page_raw = mxc_nand_read_page_raw_syndrome;
@@ -1383,27 +1219,46 @@ int board_nand_init(struct nand_chip *this)
host->pagesize_2k = 0;
this->ecc.size = 512;
- tmp = readw(&host->regs->nfc_config1);
- tmp |= NFC_ECC_EN;
- writew(tmp, &host->regs->nfc_config1);
+ _mxc_nand_enable_hwecc(mtd, 1);
#else
this->ecc.layout = &nand_soft_eccoob;
this->ecc.mode = NAND_ECC_SOFT;
- tmp = readw(&host->regs->nfc_config1);
- tmp &= ~NFC_ECC_EN;
- writew(tmp, &host->regs->nfc_config1);
+ _mxc_nand_enable_hwecc(mtd, 0);
#endif
/* Reset NAND */
this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ /* NAND bus width determines access functions used by upper layer */
+ if (is_16bit_nand())
+ this->options |= NAND_BUSWIDTH_16;
+
+#ifdef CONFIG_SYS_NAND_LARGEPAGE
+ host->pagesize_2k = 1;
+ this->ecc.layout = &nand_hw_eccoob2k;
+#else
+ host->pagesize_2k = 0;
+ this->ecc.layout = &nand_hw_eccoob;
+#endif
+
+#ifdef MXC_NFC_V2_1
+ tmp = readw(&host->regs->config1);
+ tmp |= NFC_ONE_CYCLE;
+ tmp |= NFC_4_8N_ECC;
+ writew(tmp, &host->regs->config1);
+ if (host->pagesize_2k)
+ writew(64/2, &host->regs->spare_area_size);
+ else
+ writew(16/2, &host->regs->spare_area_size);
+#endif
+
/*
* preset operation
* Unlock the internal RAM Buffer
*/
- writew(0x2, &host->regs->nfc_config);
+ writew(0x2, &host->regs->config);
/* Blocks to be unlocked */
- writew(0x0, &host->regs->nfc_unlockstart_blkaddr);
+ writew(0x0, &host->regs->unlockstart_blkaddr);
/* Originally (Freescale LTIB 2.6.21) 0x4000 was written to the
* unlockend_blkaddr, but the magic 0x4000 does not always work
* when writing more than some 32 megabytes (on 2k page nands)
@@ -1415,22 +1270,10 @@ int board_nand_init(struct nand_chip *this)
* This might be NAND chip specific and the i.MX31 datasheet is
* extremely vague about the semantics of this register.
*/
- writew(0xFFFF, &host->regs->nfc_unlockend_blkaddr);
+ writew(0xFFFF, &host->regs->unlockend_blkaddr);
/* Unlock Block Command for given address range */
- writew(0x4, &host->regs->nfc_wrprot);
+ writew(0x4, &host->regs->wrprot);
- /* NAND bus width determines access functions used by upper layer */
- if (is_16bit_nand())
- this->options |= NAND_BUSWIDTH_16;
-
-#ifdef CONFIG_SYS_NAND_LARGEPAGE
- host->pagesize_2k = 1;
- this->ecc.layout = &nand_hw_eccoob2k;
-#else
- host->pagesize_2k = 0;
- this->ecc.layout = &nand_hw_eccoob;
-#endif
- mxc_setup_config1();
- return err;
+ return 0;
}
diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c
index bf9414f..4701be8 100644
--- a/drivers/mtd/nand/mxs_nand.c
+++ b/drivers/mtd/nand/mxs_nand.c
@@ -25,10 +25,10 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include <common.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/types.h>
-#include <common.h>
#include <malloc.h>
#include <asm/errno.h>
#include <asm/io.h>
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index bfd668f..71f5027 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2573,14 +2573,13 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
mtd->writesize = le32_to_cpu(p->byte_per_page);
mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize;
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
- chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize;
+ chip->chipsize = le32_to_cpu(p->blocks_per_lun);
+ chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
*busw = 0;
if (le16_to_cpu(p->features) & 1)
*busw = NAND_BUSWIDTH_16;
- chip->options &= ~NAND_CHIPOPTIONS_MSK;
- chip->options |= (NAND_NO_READRDY |
- NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK;
+ chip->options |= NAND_NO_READRDY | NAND_NO_AUTOINCR;
return 1;
}
@@ -2752,8 +2751,7 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
}
}
/* Get chip options, preserve non chip based options */
- chip->options &= ~NAND_CHIPOPTIONS_MSK;
- chip->options |= type->options & NAND_CHIPOPTIONS_MSK;
+ chip->options |= type->options;
/* Check if chip is a not a samsung device. Do not clear the
* options for chips which are not having an extended id.
@@ -2936,7 +2934,8 @@ int nand_scan_tail(struct mtd_info *mtd)
struct nand_chip *chip = mtd->priv;
if (!(chip->options & NAND_OWN_BUFFERS))
- chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
+ chip->buffers = memalign(ARCH_DMA_MINALIGN,
+ sizeof(*chip->buffers));
if (!chip->buffers)
return -ENOMEM;
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 7ed8b18..c4752a7 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -207,12 +207,6 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
* Support for locking / unlocking operations of some NAND devices
*****************************************************************************/
-#define NAND_CMD_LOCK 0x2a
-#define NAND_CMD_LOCK_TIGHT 0x2c
-#define NAND_CMD_UNLOCK1 0x23
-#define NAND_CMD_UNLOCK2 0x24
-#define NAND_CMD_LOCK_STATUS 0x7a
-
/**
* nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT
* state
@@ -271,7 +265,6 @@ int nand_lock(struct mtd_info *mtd, int tight)
* >0 lock status:
* bitfield with the following combinations:
* NAND_LOCK_STATUS_TIGHT: page in tight state
- * NAND_LOCK_STATUS_LOCK: page locked
* NAND_LOCK_STATUS_UNLOCK: page unlocked
*
*/
@@ -300,7 +293,6 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
chip->cmdfunc(mtd, NAND_CMD_LOCK_STATUS, -1, page & chip->pagemask);
ret = chip->read_byte(mtd) & (NAND_LOCK_STATUS_TIGHT
- | NAND_LOCK_STATUS_LOCK
| NAND_LOCK_STATUS_UNLOCK);
out:
@@ -317,18 +309,21 @@ int nand_get_lock_status(struct mtd_info *mtd, loff_t offset)
* @param start start byte address
* @param length number of bytes to unlock (must be a multiple of
* page size nand->writesize)
+ * @param allexcept if set, unlock everything not selected
*
* @return 0 on success, -1 in case of error
*/
-int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
+int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length,
+ int allexcept)
{
int ret = 0;
int chipnr;
int status;
int page;
struct nand_chip *chip = mtd->priv;
- printf ("nand_unlock: start: %08x, length: %d!\n",
- (int)start, (int)length);
+
+ debug("nand_unlock%s: start: %08llx, length: %d!\n",
+ allexcept ? " (allexcept)" : "", start, length);
/* select the NAND device */
chipnr = (int)(start >> chip->chip_shift);
@@ -368,6 +363,15 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
/* submit ADDRESS of LAST page to unlock */
page += (int)(length >> chip->page_shift);
+
+ /*
+ * Page addresses for unlocking are supposed to be block-aligned.
+ * At least some NAND chips use the low bit to indicate that the
+ * page range should be inverted.
+ */
+ if (allexcept)
+ page |= 1;
+
chip->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & chip->pagemask);
/* call wait ready function */
diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c
new file mode 100644
index 0000000..8c1de34
--- /dev/null
+++ b/drivers/mtd/nand/tegra_nand.c
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * (C) Copyright 2011 NVIDIA Corporation <www.nvidia.com>
+ * (C) Copyright 2006 Detlev Zundel, dzu@denx.de
+ * (C) Copyright 2006 DENX Software Engineering
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <nand.h>
+#include <asm/arch/clk_rst.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/funcmux.h>
+#include <asm/arch/gpio.h>
+#include <asm/errno.h>
+#include <asm-generic/gpio.h>
+#include <fdtdec.h>
+#include "tegra_nand.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define NAND_CMD_TIMEOUT_MS 10
+
+#define SKIPPED_SPARE_BYTES 4
+
+/* ECC bytes to be generated for tag data */
+#define TAG_ECC_BYTES 4
+
+/* 64 byte oob block info for large page (== 2KB) device
+ *
+ * OOB flash layout for Tegra with Reed-Solomon 4 symbol correct ECC:
+ * Skipped bytes(4)
+ * Main area Ecc(36)
+ * Tag data(20)
+ * Tag data Ecc(4)
+ *
+ * Yaffs2 will use 16 tag bytes.
+ */
+static struct nand_ecclayout eccoob = {
+ .eccbytes = 36,
+ .eccpos = {
+ 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ },
+ .oobavail = 20,
+ .oobfree = {
+ {
+ .offset = 40,
+ .length = 20,
+ },
+ }
+};
+
+enum {
+ ECC_OK,
+ ECC_TAG_ERROR = 1 << 0,
+ ECC_DATA_ERROR = 1 << 1
+};
+
+/* Timing parameters */
+enum {
+ FDT_NAND_MAX_TRP_TREA,
+ FDT_NAND_TWB,
+ FDT_NAND_MAX_TCR_TAR_TRR,
+ FDT_NAND_TWHR,
+ FDT_NAND_MAX_TCS_TCH_TALS_TALH,
+ FDT_NAND_TWH,
+ FDT_NAND_TWP,
+ FDT_NAND_TRH,
+ FDT_NAND_TADL,
+
+ FDT_NAND_TIMING_COUNT
+};
+
+/* Information about an attached NAND chip */
+struct fdt_nand {
+ struct nand_ctlr *reg;
+ int enabled; /* 1 to enable, 0 to disable */
+ struct fdt_gpio_state wp_gpio; /* write-protect GPIO */
+ s32 width; /* bit width, normally 8 */
+ u32 timing[FDT_NAND_TIMING_COUNT];
+};
+
+struct nand_drv {
+ struct nand_ctlr *reg;
+
+ /*
+ * When running in PIO mode to get READ ID bytes from register
+ * RESP_0, we need this variable as an index to know which byte in
+ * register RESP_0 should be read.
+ * Because common code in nand_base.c invokes read_byte function two
+ * times for NAND_CMD_READID.
+ * And our controller returns 4 bytes at once in register RESP_0.
+ */
+ int pio_byte_index;
+ struct fdt_nand config;
+};
+
+static struct nand_drv nand_ctrl;
+static struct mtd_info *our_mtd;
+static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];
+
+#ifdef CONFIG_SYS_DCACHE_OFF
+static inline void dma_prepare(void *start, unsigned long length,
+ int is_writing)
+{
+}
+#else
+/**
+ * Prepare for a DMA transaction
+ *
+ * For a write we flush out our data. For a read we invalidate, since we
+ * need to do this before we read from the buffer after the DMA has
+ * completed, so may as well do it now.
+ *
+ * @param start Start address for DMA buffer (should be cache-aligned)
+ * @param length Length of DMA buffer in bytes
+ * @param is_writing 0 if reading, non-zero if writing
+ */
+static void dma_prepare(void *start, unsigned long length, int is_writing)
+{
+ unsigned long addr = (unsigned long)start;
+
+ length = ALIGN(length, ARCH_DMA_MINALIGN);
+ if (is_writing)
+ flush_dcache_range(addr, addr + length);
+ else
+ invalidate_dcache_range(addr, addr + length);
+}
+#endif
+
+/**
+ * Wait for command completion
+ *
+ * @param reg nand_ctlr structure
+ * @return
+ * 1 - Command completed
+ * 0 - Timeout
+ */
+static int nand_waitfor_cmd_completion(struct nand_ctlr *reg)
+{
+ u32 reg_val;
+ int running;
+ int i;
+
+ for (i = 0; i < NAND_CMD_TIMEOUT_MS * 1000; i++) {
+ if ((readl(&reg->command) & CMD_GO) ||
+ !(readl(&reg->status) & STATUS_RBSY0) ||
+ !(readl(&reg->isr) & ISR_IS_CMD_DONE)) {
+ udelay(1);
+ continue;
+ }
+ reg_val = readl(&reg->dma_mst_ctrl);
+ /*
+ * If DMA_MST_CTRL_EN_A_ENABLE or DMA_MST_CTRL_EN_B_ENABLE
+ * is set, that means DMA engine is running.
+ *
+ * Then we have to wait until DMA_MST_CTRL_IS_DMA_DONE
+ * is cleared, indicating DMA transfer completion.
+ */
+ running = reg_val & (DMA_MST_CTRL_EN_A_ENABLE |
+ DMA_MST_CTRL_EN_B_ENABLE);
+ if (!running || (reg_val & DMA_MST_CTRL_IS_DMA_DONE))
+ return 1;
+ udelay(1);
+ }
+ return 0;
+}
+
+/**
+ * Read one byte from the chip
+ *
+ * @param mtd MTD device structure
+ * @return data byte
+ *
+ * Read function for 8bit bus-width
+ */
+static uint8_t read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ u32 dword_read;
+ struct nand_drv *info;
+
+ info = (struct nand_drv *)chip->priv;
+
+ /* In PIO mode, only 4 bytes can be transferred with single CMD_GO. */
+ if (info->pio_byte_index > 3) {
+ info->pio_byte_index = 0;
+ writel(CMD_GO | CMD_PIO
+ | CMD_RX | CMD_CE0,
+ &info->reg->command);
+ if (!nand_waitfor_cmd_completion(info->reg))
+ printf("Command timeout\n");
+ }
+
+ dword_read = readl(&info->reg->resp);
+ dword_read = dword_read >> (8 * info->pio_byte_index);
+ info->pio_byte_index++;
+ return (uint8_t)dword_read;
+}
+
+/**
+ * Check NAND status to see if it is ready or not
+ *
+ * @param mtd MTD device structure
+ * @return
+ * 1 - ready
+ * 0 - not ready
+ */
+static int nand_dev_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ int reg_val;
+ struct nand_drv *info;
+
+ info = (struct nand_drv *)chip->priv;
+
+ reg_val = readl(&info->reg->status);
+ if (reg_val & STATUS_RBSY0)
+ return 1;
+ else
+ return 0;
+}
+
+/* Dummy implementation: we don't support multiple chips */
+static void nand_select_chip(struct mtd_info *mtd, int chipnr)
+{
+ switch (chipnr) {
+ case -1:
+ case 0:
+ break;
+
+ default:
+ BUG();
+ }
+}
+
+/**
+ * Clear all interrupt status bits
+ *
+ * @param reg nand_ctlr structure
+ */
+static void nand_clear_interrupt_status(struct nand_ctlr *reg)
+{
+ u32 reg_val;
+
+ /* Clear interrupt status */
+ reg_val = readl(&reg->isr);
+ writel(reg_val, &reg->isr);
+}
+
+/**
+ * Send command to NAND device
+ *
+ * @param mtd MTD device structure
+ * @param command the command to be sent
+ * @param column the column address for this command, -1 if none
+ * @param page_addr the page address for this command, -1 if none
+ */
+static void nand_command(struct mtd_info *mtd, unsigned int command,
+ int column, int page_addr)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct nand_drv *info;
+
+ info = (struct nand_drv *)chip->priv;
+
+ /*
+ * Write out the command to the device.
+ *
+ * Only command NAND_CMD_RESET or NAND_CMD_READID will come
+ * here before mtd->writesize is initialized.
+ */
+
+ /* Emulate NAND_CMD_READOOB */
+ if (command == NAND_CMD_READOOB) {
+ assert(mtd->writesize != 0);
+ column += mtd->writesize;
+ command = NAND_CMD_READ0;
+ }
+
+ /* Adjust columns for 16 bit bus-width */
+ if (column != -1 && (chip->options & NAND_BUSWIDTH_16))
+ column >>= 1;
+
+ nand_clear_interrupt_status(info->reg);
+
+ /* Stop DMA engine, clear DMA completion status */
+ writel(DMA_MST_CTRL_EN_A_DISABLE
+ | DMA_MST_CTRL_EN_B_DISABLE
+ | DMA_MST_CTRL_IS_DMA_DONE,
+ &info->reg->dma_mst_ctrl);
+
+ /*
+ * Program and erase have their own busy handlers
+ * status and sequential in needs no delay
+ */
+ switch (command) {
+ case NAND_CMD_READID:
+ writel(NAND_CMD_READID, &info->reg->cmd_reg1);
+ writel(CMD_GO | CMD_CLE | CMD_ALE | CMD_PIO
+ | CMD_RX |
+ ((4 - 1) << CMD_TRANS_SIZE_SHIFT)
+ | CMD_CE0,
+ &info->reg->command);
+ info->pio_byte_index = 0;
+ break;
+ case NAND_CMD_READ0:
+ writel(NAND_CMD_READ0, &info->reg->cmd_reg1);
+ writel(NAND_CMD_READSTART, &info->reg->cmd_reg2);
+ writel((page_addr << 16) | (column & 0xFFFF),
+ &info->reg->addr_reg1);
+ writel(page_addr >> 16, &info->reg->addr_reg2);
+ return;
+ case NAND_CMD_SEQIN:
+ writel(NAND_CMD_SEQIN, &info->reg->cmd_reg1);
+ writel(NAND_CMD_PAGEPROG, &info->reg->cmd_reg2);
+ writel((page_addr << 16) | (column & 0xFFFF),
+ &info->reg->addr_reg1);
+ writel(page_addr >> 16,
+ &info->reg->addr_reg2);
+ return;
+ case NAND_CMD_PAGEPROG:
+ return;
+ case NAND_CMD_ERASE1:
+ writel(NAND_CMD_ERASE1, &info->reg->cmd_reg1);
+ writel(NAND_CMD_ERASE2, &info->reg->cmd_reg2);
+ writel(page_addr, &info->reg->addr_reg1);
+ writel(CMD_GO | CMD_CLE | CMD_ALE |
+ CMD_SEC_CMD | CMD_CE0 | CMD_ALE_BYTES3,
+ &info->reg->command);
+ break;
+ case NAND_CMD_ERASE2:
+ return;
+ case NAND_CMD_STATUS:
+ writel(NAND_CMD_STATUS, &info->reg->cmd_reg1);
+ writel(CMD_GO | CMD_CLE | CMD_PIO | CMD_RX
+ | ((1 - 0) << CMD_TRANS_SIZE_SHIFT)
+ | CMD_CE0,
+ &info->reg->command);
+ info->pio_byte_index = 0;
+ break;
+ case NAND_CMD_RESET:
+ writel(NAND_CMD_RESET, &info->reg->cmd_reg1);
+ writel(CMD_GO | CMD_CLE | CMD_CE0,
+ &info->reg->command);
+ break;
+ case NAND_CMD_RNDOUT:
+ default:
+ printf("%s: Unsupported command %d\n", __func__, command);
+ return;
+ }
+ if (!nand_waitfor_cmd_completion(info->reg))
+ printf("Command 0x%02X timeout\n", command);
+}
+
+/**
+ * Check whether the pointed buffer are all 0xff (blank).
+ *
+ * @param buf data buffer for blank check
+ * @param len length of the buffer in byte
+ * @return
+ * 1 - blank
+ * 0 - non-blank
+ */
+static int blank_check(u8 *buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (buf[i] != 0xFF)
+ return 0;
+ return 1;
+}
+
+/**
+ * After a DMA transfer for read, we call this function to see whether there
+ * is any uncorrectable error on the pointed data buffer or oob buffer.
+ *
+ * @param reg nand_ctlr structure
+ * @param databuf data buffer
+ * @param a_len data buffer length
+ * @param oobbuf oob buffer
+ * @param b_len oob buffer length
+ * @return
+ * ECC_OK - no ECC error or correctable ECC error
+ * ECC_TAG_ERROR - uncorrectable tag ECC error
+ * ECC_DATA_ERROR - uncorrectable data ECC error
+ * ECC_DATA_ERROR + ECC_TAG_ERROR - uncorrectable data+tag ECC error
+ */
+static int check_ecc_error(struct nand_ctlr *reg, u8 *databuf,
+ int a_len, u8 *oobbuf, int b_len)
+{
+ int return_val = ECC_OK;
+ u32 reg_val;
+
+ if (!(readl(&reg->isr) & ISR_IS_ECC_ERR))
+ return ECC_OK;
+
+ /*
+ * Area A is used for the data block (databuf). Area B is used for
+ * the spare block (oobbuf)
+ */
+ reg_val = readl(&reg->dec_status);
+ if ((reg_val & DEC_STATUS_A_ECC_FAIL) && databuf) {
+ reg_val = readl(&reg->bch_dec_status_buf);
+ /*
+ * If uncorrectable error occurs on data area, then see whether
+ * they are all FF. If all are FF, it's a blank page.
+ * Not error.
+ */
+ if ((reg_val & BCH_DEC_STATUS_FAIL_SEC_FLAG_MASK) &&
+ !blank_check(databuf, a_len))
+ return_val |= ECC_DATA_ERROR;
+ }
+
+ if ((reg_val & DEC_STATUS_B_ECC_FAIL) && oobbuf) {
+ reg_val = readl(&reg->bch_dec_status_buf);
+ /*
+ * If uncorrectable error occurs on tag area, then see whether
+ * they are all FF. If all are FF, it's a blank page.
+ * Not error.
+ */
+ if ((reg_val & BCH_DEC_STATUS_FAIL_TAG_MASK) &&
+ !blank_check(oobbuf, b_len))
+ return_val |= ECC_TAG_ERROR;
+ }
+
+ return return_val;
+}
+
+/**
+ * Set GO bit to send command to device
+ *
+ * @param reg nand_ctlr structure
+ */
+static void start_command(struct nand_ctlr *reg)
+{
+ u32 reg_val;
+
+ reg_val = readl(&reg->command);
+ reg_val |= CMD_GO;
+ writel(reg_val, &reg->command);
+}
+
+/**
+ * Clear command GO bit, DMA GO bit, and DMA completion status
+ *
+ * @param reg nand_ctlr structure
+ */
+static void stop_command(struct nand_ctlr *reg)
+{
+ /* Stop command */
+ writel(0, &reg->command);
+
+ /* Stop DMA engine and clear DMA completion status */
+ writel(DMA_MST_CTRL_GO_DISABLE
+ | DMA_MST_CTRL_IS_DMA_DONE,
+ &reg->dma_mst_ctrl);
+}
+
+/**
+ * Set up NAND bus width and page size
+ *
+ * @param info nand_info structure
+ * @param *reg_val address of reg_val
+ * @return 0 if ok, -1 on error
+ */
+static int set_bus_width_page_size(struct fdt_nand *config,
+ u32 *reg_val)
+{
+ if (config->width == 8)
+ *reg_val = CFG_BUS_WIDTH_8BIT;
+ else if (config->width == 16)
+ *reg_val = CFG_BUS_WIDTH_16BIT;
+ else {
+ debug("%s: Unsupported bus width %d\n", __func__,
+ config->width);
+ return -1;
+ }
+
+ if (our_mtd->writesize == 512)
+ *reg_val |= CFG_PAGE_SIZE_512;
+ else if (our_mtd->writesize == 2048)
+ *reg_val |= CFG_PAGE_SIZE_2048;
+ else if (our_mtd->writesize == 4096)
+ *reg_val |= CFG_PAGE_SIZE_4096;
+ else {
+ debug("%s: Unsupported page size %d\n", __func__,
+ our_mtd->writesize);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Page read/write function
+ *
+ * @param mtd mtd info structure
+ * @param chip nand chip info structure
+ * @param buf data buffer
+ * @param page page number
+ * @param with_ecc 1 to enable ECC, 0 to disable ECC
+ * @param is_writing 0 for read, 1 for write
+ * @return 0 when successfully completed
+ * -EIO when command timeout
+ */
+static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int page, int with_ecc, int is_writing)
+{
+ u32 reg_val;
+ int tag_size;
+ struct nand_oobfree *free = chip->ecc.layout->oobfree;
+ /* 4*128=512 (byte) is the value that our HW can support. */
+ ALLOC_CACHE_ALIGN_BUFFER(u32, tag_buf, 128);
+ char *tag_ptr;
+ struct nand_drv *info;
+ struct fdt_nand *config;
+
+ if ((uintptr_t)buf & 0x03) {
+ printf("buf %p has to be 4-byte aligned\n", buf);
+ return -EINVAL;
+ }
+
+ info = (struct nand_drv *)chip->priv;
+ config = &info->config;
+ if (set_bus_width_page_size(config, &reg_val))
+ return -EINVAL;
+
+ /* Need to be 4-byte aligned */
+ tag_ptr = (char *)tag_buf;
+
+ stop_command(info->reg);
+
+ writel((1 << chip->page_shift) - 1, &info->reg->dma_cfg_a);
+ writel(virt_to_phys(buf), &info->reg->data_block_ptr);
+
+ if (with_ecc) {
+ writel(virt_to_phys(tag_ptr), &info->reg->tag_ptr);
+ if (is_writing)
+ memcpy(tag_ptr, chip->oob_poi + free->offset,
+ chip->ecc.layout->oobavail +
+ TAG_ECC_BYTES);
+ } else {
+ writel(virt_to_phys(chip->oob_poi), &info->reg->tag_ptr);
+ }
+
+ /* Set ECC selection, configure ECC settings */
+ if (with_ecc) {
+ tag_size = chip->ecc.layout->oobavail + TAG_ECC_BYTES;
+ reg_val |= (CFG_SKIP_SPARE_SEL_4
+ | CFG_SKIP_SPARE_ENABLE
+ | CFG_HW_ECC_CORRECTION_ENABLE
+ | CFG_ECC_EN_TAG_DISABLE
+ | CFG_HW_ECC_SEL_RS
+ | CFG_HW_ECC_ENABLE
+ | CFG_TVAL4
+ | (tag_size - 1));
+
+ if (!is_writing)
+ tag_size += SKIPPED_SPARE_BYTES;
+ dma_prepare(tag_ptr, tag_size, is_writing);
+ } else {
+ tag_size = mtd->oobsize;
+ reg_val |= (CFG_SKIP_SPARE_DISABLE
+ | CFG_HW_ECC_CORRECTION_DISABLE
+ | CFG_ECC_EN_TAG_DISABLE
+ | CFG_HW_ECC_DISABLE
+ | (tag_size - 1));
+ dma_prepare(chip->oob_poi, tag_size, is_writing);
+ }
+ writel(reg_val, &info->reg->config);
+
+ dma_prepare(buf, 1 << chip->page_shift, is_writing);
+
+ writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config);
+
+ writel(tag_size - 1, &info->reg->dma_cfg_b);
+
+ nand_clear_interrupt_status(info->reg);
+
+ reg_val = CMD_CLE | CMD_ALE
+ | CMD_SEC_CMD
+ | (CMD_ALE_BYTES5 << CMD_ALE_BYTE_SIZE_SHIFT)
+ | CMD_A_VALID
+ | CMD_B_VALID
+ | (CMD_TRANS_SIZE_PAGE << CMD_TRANS_SIZE_SHIFT)
+ | CMD_CE0;
+ if (!is_writing)
+ reg_val |= (CMD_AFT_DAT_DISABLE | CMD_RX);
+ else
+ reg_val |= (CMD_AFT_DAT_ENABLE | CMD_TX);
+ writel(reg_val, &info->reg->command);
+
+ /* Setup DMA engine */
+ reg_val = DMA_MST_CTRL_GO_ENABLE
+ | DMA_MST_CTRL_BURST_8WORDS
+ | DMA_MST_CTRL_EN_A_ENABLE
+ | DMA_MST_CTRL_EN_B_ENABLE;
+
+ if (!is_writing)
+ reg_val |= DMA_MST_CTRL_DIR_READ;
+ else
+ reg_val |= DMA_MST_CTRL_DIR_WRITE;
+
+ writel(reg_val, &info->reg->dma_mst_ctrl);
+
+ start_command(info->reg);
+
+ if (!nand_waitfor_cmd_completion(info->reg)) {
+ if (!is_writing)
+ printf("Read Page 0x%X timeout ", page);
+ else
+ printf("Write Page 0x%X timeout ", page);
+ if (with_ecc)
+ printf("with ECC");
+ else
+ printf("without ECC");
+ printf("\n");
+ return -EIO;
+ }
+
+ if (with_ecc && !is_writing) {
+ memcpy(chip->oob_poi, tag_ptr,
+ SKIPPED_SPARE_BYTES);
+ memcpy(chip->oob_poi + free->offset,
+ tag_ptr + SKIPPED_SPARE_BYTES,
+ chip->ecc.layout->oobavail);
+ reg_val = (u32)check_ecc_error(info->reg, (u8 *)buf,
+ 1 << chip->page_shift,
+ (u8 *)(tag_ptr + SKIPPED_SPARE_BYTES),
+ chip->ecc.layout->oobavail);
+ if (reg_val & ECC_TAG_ERROR)
+ printf("Read Page 0x%X tag ECC error\n", page);
+ if (reg_val & ECC_DATA_ERROR)
+ printf("Read Page 0x%X data ECC error\n",
+ page);
+ if (reg_val & (ECC_DATA_ERROR | ECC_TAG_ERROR))
+ return -EIO;
+ }
+ return 0;
+}
+
+/**
+ * Hardware ecc based page read function
+ *
+ * @param mtd mtd info structure
+ * @param chip nand chip info structure
+ * @param buf buffer to store read data
+ * @param page page number to read
+ * @return 0 when successfully completed
+ * -EIO when command timeout
+ */
+static int nand_read_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int page)
+{
+ return nand_rw_page(mtd, chip, buf, page, 1, 0);
+}
+
+/**
+ * Hardware ecc based page write function
+ *
+ * @param mtd mtd info structure
+ * @param chip nand chip info structure
+ * @param buf data buffer
+ */
+static void nand_write_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+{
+ int page;
+ struct nand_drv *info;
+
+ info = (struct nand_drv *)chip->priv;
+
+ page = (readl(&info->reg->addr_reg1) >> 16) |
+ (readl(&info->reg->addr_reg2) << 16);
+
+ nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1);
+}
+
+
+/**
+ * Read raw page data without ecc
+ *
+ * @param mtd mtd info structure
+ * @param chip nand chip info structure
+ * @param buf buffer to store read data
+ * @param page page number to read
+ * @return 0 when successfully completed
+ * -EINVAL when chip->oob_poi is not double-word aligned
+ * -EIO when command timeout
+ */
+static int nand_read_page_raw(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int page)
+{
+ return nand_rw_page(mtd, chip, buf, page, 0, 0);
+}
+
+/**
+ * Raw page write function
+ *
+ * @param mtd mtd info structure
+ * @param chip nand chip info structure
+ * @param buf data buffer
+ */
+static void nand_write_page_raw(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+{
+ int page;
+ struct nand_drv *info;
+
+ info = (struct nand_drv *)chip->priv;
+ page = (readl(&info->reg->addr_reg1) >> 16) |
+ (readl(&info->reg->addr_reg2) << 16);
+
+ nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1);
+}
+
+/**
+ * OOB data read/write function
+ *
+ * @param mtd mtd info structure
+ * @param chip nand chip info structure
+ * @param page page number to read
+ * @param with_ecc 1 to enable ECC, 0 to disable ECC
+ * @param is_writing 0 for read, 1 for write
+ * @return 0 when successfully completed
+ * -EINVAL when chip->oob_poi is not double-word aligned
+ * -EIO when command timeout
+ */
+static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int with_ecc, int is_writing)
+{
+ u32 reg_val;
+ int tag_size;
+ struct nand_oobfree *free = chip->ecc.layout->oobfree;
+ struct nand_drv *info;
+
+ if (((int)chip->oob_poi) & 0x03)
+ return -EINVAL;
+ info = (struct nand_drv *)chip->priv;
+ if (set_bus_width_page_size(&info->config, &reg_val))
+ return -EINVAL;
+
+ stop_command(info->reg);
+
+ writel(virt_to_phys(chip->oob_poi), &info->reg->tag_ptr);
+
+ /* Set ECC selection */
+ tag_size = mtd->oobsize;
+ if (with_ecc)
+ reg_val |= CFG_ECC_EN_TAG_ENABLE;
+ else
+ reg_val |= (CFG_ECC_EN_TAG_DISABLE);
+
+ reg_val |= ((tag_size - 1) |
+ CFG_SKIP_SPARE_DISABLE |
+ CFG_HW_ECC_CORRECTION_DISABLE |
+ CFG_HW_ECC_DISABLE);
+ writel(reg_val, &info->reg->config);
+
+ dma_prepare(chip->oob_poi, tag_size, is_writing);
+
+ writel(BCH_CONFIG_BCH_ECC_DISABLE, &info->reg->bch_config);
+
+ if (is_writing && with_ecc)
+ tag_size -= TAG_ECC_BYTES;
+
+ writel(tag_size - 1, &info->reg->dma_cfg_b);
+
+ nand_clear_interrupt_status(info->reg);
+
+ reg_val = CMD_CLE | CMD_ALE
+ | CMD_SEC_CMD
+ | (CMD_ALE_BYTES5 << CMD_ALE_BYTE_SIZE_SHIFT)
+ | CMD_B_VALID
+ | CMD_CE0;
+ if (!is_writing)
+ reg_val |= (CMD_AFT_DAT_DISABLE | CMD_RX);
+ else
+ reg_val |= (CMD_AFT_DAT_ENABLE | CMD_TX);
+ writel(reg_val, &info->reg->command);
+
+ /* Setup DMA engine */
+ reg_val = DMA_MST_CTRL_GO_ENABLE
+ | DMA_MST_CTRL_BURST_8WORDS
+ | DMA_MST_CTRL_EN_B_ENABLE;
+ if (!is_writing)
+ reg_val |= DMA_MST_CTRL_DIR_READ;
+ else
+ reg_val |= DMA_MST_CTRL_DIR_WRITE;
+
+ writel(reg_val, &info->reg->dma_mst_ctrl);
+
+ start_command(info->reg);
+
+ if (!nand_waitfor_cmd_completion(info->reg)) {
+ if (!is_writing)
+ printf("Read OOB of Page 0x%X timeout\n", page);
+ else
+ printf("Write OOB of Page 0x%X timeout\n", page);
+ return -EIO;
+ }
+
+ if (with_ecc && !is_writing) {
+ reg_val = (u32)check_ecc_error(info->reg, 0, 0,
+ (u8 *)(chip->oob_poi + free->offset),
+ chip->ecc.layout->oobavail);
+ if (reg_val & ECC_TAG_ERROR)
+ printf("Read OOB of Page 0x%X tag ECC error\n", page);
+ }
+ return 0;
+}
+
+/**
+ * OOB data read function
+ *
+ * @param mtd mtd info structure
+ * @param chip nand chip info structure
+ * @param page page number to read
+ * @param sndcmd flag whether to issue read command or not
+ * @return 1 - issue read command next time
+ * 0 - not to issue
+ */
+static int nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd)
+{
+ if (sndcmd) {
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ sndcmd = 0;
+ }
+ nand_rw_oob(mtd, chip, page, 0, 0);
+ return sndcmd;
+}
+
+/**
+ * OOB data write function
+ *
+ * @param mtd mtd info structure
+ * @param chip nand chip info structure
+ * @param page page number to write
+ * @return 0 when successfully completed
+ * -EINVAL when chip->oob_poi is not double-word aligned
+ * -EIO when command timeout
+ */
+static int nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+
+ return nand_rw_oob(mtd, chip, page, 0, 1);
+}
+
+/**
+ * Set up NAND memory timings according to the provided parameters
+ *
+ * @param timing Timing parameters
+ * @param reg NAND controller register address
+ */
+static void setup_timing(unsigned timing[FDT_NAND_TIMING_COUNT],
+ struct nand_ctlr *reg)
+{
+ u32 reg_val, clk_rate, clk_period, time_val;
+
+ clk_rate = (u32)clock_get_periph_rate(PERIPH_ID_NDFLASH,
+ CLOCK_ID_PERIPH) / 1000000;
+ clk_period = 1000 / clk_rate;
+ reg_val = ((timing[FDT_NAND_MAX_TRP_TREA] / clk_period) <<
+ TIMING_TRP_RESP_CNT_SHIFT) & TIMING_TRP_RESP_CNT_MASK;
+ reg_val |= ((timing[FDT_NAND_TWB] / clk_period) <<
+ TIMING_TWB_CNT_SHIFT) & TIMING_TWB_CNT_MASK;
+ time_val = timing[FDT_NAND_MAX_TCR_TAR_TRR] / clk_period;
+ if (time_val > 2)
+ reg_val |= ((time_val - 2) << TIMING_TCR_TAR_TRR_CNT_SHIFT) &
+ TIMING_TCR_TAR_TRR_CNT_MASK;
+ reg_val |= ((timing[FDT_NAND_TWHR] / clk_period) <<
+ TIMING_TWHR_CNT_SHIFT) & TIMING_TWHR_CNT_MASK;
+ time_val = timing[FDT_NAND_MAX_TCS_TCH_TALS_TALH] / clk_period;
+ if (time_val > 1)
+ reg_val |= ((time_val - 1) << TIMING_TCS_CNT_SHIFT) &
+ TIMING_TCS_CNT_MASK;
+ reg_val |= ((timing[FDT_NAND_TWH] / clk_period) <<
+ TIMING_TWH_CNT_SHIFT) & TIMING_TWH_CNT_MASK;
+ reg_val |= ((timing[FDT_NAND_TWP] / clk_period) <<
+ TIMING_TWP_CNT_SHIFT) & TIMING_TWP_CNT_MASK;
+ reg_val |= ((timing[FDT_NAND_TRH] / clk_period) <<
+ TIMING_TRH_CNT_SHIFT) & TIMING_TRH_CNT_MASK;
+ reg_val |= ((timing[FDT_NAND_MAX_TRP_TREA] / clk_period) <<
+ TIMING_TRP_CNT_SHIFT) & TIMING_TRP_CNT_MASK;
+ writel(reg_val, &reg->timing);
+
+ reg_val = 0;
+ time_val = timing[FDT_NAND_TADL] / clk_period;
+ if (time_val > 2)
+ reg_val = (time_val - 2) & TIMING2_TADL_CNT_MASK;
+ writel(reg_val, &reg->timing2);
+}
+
+/**
+ * Decode NAND parameters from the device tree
+ *
+ * @param blob Device tree blob
+ * @param node Node containing "nand-flash" compatble node
+ * @return 0 if ok, -ve on error (FDT_ERR_...)
+ */
+static int fdt_decode_nand(const void *blob, int node, struct fdt_nand *config)
+{
+ int err;
+
+ config->reg = (struct nand_ctlr *)fdtdec_get_addr(blob, node, "reg");
+ config->enabled = fdtdec_get_is_enabled(blob, node);
+ config->width = fdtdec_get_int(blob, node, "nvidia,nand-width", 8);
+ err = fdtdec_decode_gpio(blob, node, "nvidia,wp-gpios",
+ &config->wp_gpio);
+ if (err)
+ return err;
+ err = fdtdec_get_int_array(blob, node, "nvidia,timing",
+ config->timing, FDT_NAND_TIMING_COUNT);
+ if (err < 0)
+ return err;
+
+ /* Now look up the controller and decode that */
+ node = fdt_next_node(blob, node, NULL);
+ if (node < 0)
+ return node;
+
+ return 0;
+}
+
+/**
+ * Board-specific NAND initialization
+ *
+ * @param nand nand chip info structure
+ * @return 0, after initialized, -1 on error
+ */
+int tegra_nand_init(struct nand_chip *nand, int devnum)
+{
+ struct nand_drv *info = &nand_ctrl;
+ struct fdt_nand *config = &info->config;
+ int node, ret;
+
+ node = fdtdec_next_compatible(gd->fdt_blob, 0,
+ COMPAT_NVIDIA_TEGRA20_NAND);
+ if (node < 0)
+ return -1;
+ if (fdt_decode_nand(gd->fdt_blob, node, config)) {
+ printf("Could not decode nand-flash in device tree\n");
+ return -1;
+ }
+ if (!config->enabled)
+ return -1;
+ info->reg = config->reg;
+ nand->ecc.mode = NAND_ECC_HW;
+ nand->ecc.layout = &eccoob;
+
+ nand->options = LP_OPTIONS;
+ nand->cmdfunc = nand_command;
+ nand->read_byte = read_byte;
+ nand->ecc.read_page = nand_read_page_hwecc;
+ nand->ecc.write_page = nand_write_page_hwecc;
+ nand->ecc.read_page_raw = nand_read_page_raw;
+ nand->ecc.write_page_raw = nand_write_page_raw;
+ nand->ecc.read_oob = nand_read_oob;
+ nand->ecc.write_oob = nand_write_oob;
+ nand->select_chip = nand_select_chip;
+ nand->dev_ready = nand_dev_ready;
+ nand->priv = &nand_ctrl;
+
+ /* Adjust controller clock rate */
+ clock_start_periph_pll(PERIPH_ID_NDFLASH, CLOCK_ID_PERIPH, 52000000);
+
+ /* Adjust timing for NAND device */
+ setup_timing(config->timing, info->reg);
+
+ funcmux_select(PERIPH_ID_NDFLASH, FUNCMUX_DEFAULT);
+ fdtdec_setup_gpio(&config->wp_gpio);
+ gpio_direction_output(config->wp_gpio.gpio, 1);
+
+ our_mtd = &nand_info[devnum];
+ our_mtd->priv = nand;
+ ret = nand_scan_ident(our_mtd, CONFIG_SYS_NAND_MAX_CHIPS, NULL);
+ if (ret)
+ return ret;
+
+ nand->ecc.size = our_mtd->writesize;
+ nand->ecc.bytes = our_mtd->oobsize;
+
+ ret = nand_scan_tail(our_mtd);
+ if (ret)
+ return ret;
+
+ ret = nand_register(devnum);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void board_nand_init(void)
+{
+ struct nand_chip *nand = &nand_chip[0];
+
+ if (tegra_nand_init(nand, 0))
+ puts("Tegra NAND init failed\n");
+}
diff --git a/drivers/mtd/nand/tegra_nand.h b/drivers/mtd/nand/tegra_nand.h
new file mode 100644
index 0000000..7e74be7
--- /dev/null
+++ b/drivers/mtd/nand/tegra_nand.h
@@ -0,0 +1,257 @@
+/*
+ * (C) Copyright 2011 NVIDIA Corporation <www.nvidia.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* register offset */
+#define COMMAND_0 0x00
+#define CMD_GO (1 << 31)
+#define CMD_CLE (1 << 30)
+#define CMD_ALE (1 << 29)
+#define CMD_PIO (1 << 28)
+#define CMD_TX (1 << 27)
+#define CMD_RX (1 << 26)
+#define CMD_SEC_CMD (1 << 25)
+#define CMD_AFT_DAT_MASK (1 << 24)
+#define CMD_AFT_DAT_DISABLE 0
+#define CMD_AFT_DAT_ENABLE (1 << 24)
+#define CMD_TRANS_SIZE_SHIFT 20
+#define CMD_TRANS_SIZE_PAGE 8
+#define CMD_A_VALID (1 << 19)
+#define CMD_B_VALID (1 << 18)
+#define CMD_RD_STATUS_CHK (1 << 17)
+#define CMD_R_BSY_CHK (1 << 16)
+#define CMD_CE7 (1 << 15)
+#define CMD_CE6 (1 << 14)
+#define CMD_CE5 (1 << 13)
+#define CMD_CE4 (1 << 12)
+#define CMD_CE3 (1 << 11)
+#define CMD_CE2 (1 << 10)
+#define CMD_CE1 (1 << 9)
+#define CMD_CE0 (1 << 8)
+#define CMD_CLE_BYTE_SIZE_SHIFT 4
+enum {
+ CMD_CLE_BYTES1 = 0,
+ CMD_CLE_BYTES2,
+ CMD_CLE_BYTES3,
+ CMD_CLE_BYTES4,
+};
+#define CMD_ALE_BYTE_SIZE_SHIFT 0
+enum {
+ CMD_ALE_BYTES1 = 0,
+ CMD_ALE_BYTES2,
+ CMD_ALE_BYTES3,
+ CMD_ALE_BYTES4,
+ CMD_ALE_BYTES5,
+ CMD_ALE_BYTES6,
+ CMD_ALE_BYTES7,
+ CMD_ALE_BYTES8
+};
+
+#define STATUS_0 0x04
+#define STATUS_RBSY0 (1 << 8)
+
+#define ISR_0 0x08
+#define ISR_IS_CMD_DONE (1 << 5)
+#define ISR_IS_ECC_ERR (1 << 4)
+
+#define IER_0 0x0C
+
+#define CFG_0 0x10
+#define CFG_HW_ECC_MASK (1 << 31)
+#define CFG_HW_ECC_DISABLE 0
+#define CFG_HW_ECC_ENABLE (1 << 31)
+#define CFG_HW_ECC_SEL_MASK (1 << 30)
+#define CFG_HW_ECC_SEL_HAMMING 0
+#define CFG_HW_ECC_SEL_RS (1 << 30)
+#define CFG_HW_ECC_CORRECTION_MASK (1 << 29)
+#define CFG_HW_ECC_CORRECTION_DISABLE 0
+#define CFG_HW_ECC_CORRECTION_ENABLE (1 << 29)
+#define CFG_PIPELINE_EN_MASK (1 << 28)
+#define CFG_PIPELINE_EN_DISABLE 0
+#define CFG_PIPELINE_EN_ENABLE (1 << 28)
+#define CFG_ECC_EN_TAG_MASK (1 << 27)
+#define CFG_ECC_EN_TAG_DISABLE 0
+#define CFG_ECC_EN_TAG_ENABLE (1 << 27)
+#define CFG_TVALUE_MASK (3 << 24)
+enum {
+ CFG_TVAL4 = 0 << 24,
+ CFG_TVAL6 = 1 << 24,
+ CFG_TVAL8 = 2 << 24
+};
+#define CFG_SKIP_SPARE_MASK (1 << 23)
+#define CFG_SKIP_SPARE_DISABLE 0
+#define CFG_SKIP_SPARE_ENABLE (1 << 23)
+#define CFG_COM_BSY_MASK (1 << 22)
+#define CFG_COM_BSY_DISABLE 0
+#define CFG_COM_BSY_ENABLE (1 << 22)
+#define CFG_BUS_WIDTH_MASK (1 << 21)
+#define CFG_BUS_WIDTH_8BIT 0
+#define CFG_BUS_WIDTH_16BIT (1 << 21)
+#define CFG_LPDDR1_MODE_MASK (1 << 20)
+#define CFG_LPDDR1_MODE_DISABLE 0
+#define CFG_LPDDR1_MODE_ENABLE (1 << 20)
+#define CFG_EDO_MODE_MASK (1 << 19)
+#define CFG_EDO_MODE_DISABLE 0
+#define CFG_EDO_MODE_ENABLE (1 << 19)
+#define CFG_PAGE_SIZE_SEL_MASK (7 << 16)
+enum {
+ CFG_PAGE_SIZE_256 = 0 << 16,
+ CFG_PAGE_SIZE_512 = 1 << 16,
+ CFG_PAGE_SIZE_1024 = 2 << 16,
+ CFG_PAGE_SIZE_2048 = 3 << 16,
+ CFG_PAGE_SIZE_4096 = 4 << 16
+};
+#define CFG_SKIP_SPARE_SEL_MASK (3 << 14)
+enum {
+ CFG_SKIP_SPARE_SEL_4 = 0 << 14,
+ CFG_SKIP_SPARE_SEL_8 = 1 << 14,
+ CFG_SKIP_SPARE_SEL_12 = 2 << 14,
+ CFG_SKIP_SPARE_SEL_16 = 3 << 14
+};
+#define CFG_TAG_BYTE_SIZE_MASK 0x1FF
+
+#define TIMING_0 0x14
+#define TIMING_TRP_RESP_CNT_SHIFT 28
+#define TIMING_TRP_RESP_CNT_MASK (0xf << TIMING_TRP_RESP_CNT_SHIFT)
+#define TIMING_TWB_CNT_SHIFT 24
+#define TIMING_TWB_CNT_MASK (0xf << TIMING_TWB_CNT_SHIFT)
+#define TIMING_TCR_TAR_TRR_CNT_SHIFT 20
+#define TIMING_TCR_TAR_TRR_CNT_MASK (0xf << TIMING_TCR_TAR_TRR_CNT_SHIFT)
+#define TIMING_TWHR_CNT_SHIFT 16
+#define TIMING_TWHR_CNT_MASK (0xf << TIMING_TWHR_CNT_SHIFT)
+#define TIMING_TCS_CNT_SHIFT 14
+#define TIMING_TCS_CNT_MASK (3 << TIMING_TCS_CNT_SHIFT)
+#define TIMING_TWH_CNT_SHIFT 12
+#define TIMING_TWH_CNT_MASK (3 << TIMING_TWH_CNT_SHIFT)
+#define TIMING_TWP_CNT_SHIFT 8
+#define TIMING_TWP_CNT_MASK (0xf << TIMING_TWP_CNT_SHIFT)
+#define TIMING_TRH_CNT_SHIFT 4
+#define TIMING_TRH_CNT_MASK (3 << TIMING_TRH_CNT_SHIFT)
+#define TIMING_TRP_CNT_SHIFT 0
+#define TIMING_TRP_CNT_MASK (0xf << TIMING_TRP_CNT_SHIFT)
+
+#define RESP_0 0x18
+
+#define TIMING2_0 0x1C
+#define TIMING2_TADL_CNT_SHIFT 0
+#define TIMING2_TADL_CNT_MASK (0xf << TIMING2_TADL_CNT_SHIFT)
+
+#define CMD_REG1_0 0x20
+#define CMD_REG2_0 0x24
+#define ADDR_REG1_0 0x28
+#define ADDR_REG2_0 0x2C
+
+#define DMA_MST_CTRL_0 0x30
+#define DMA_MST_CTRL_GO_MASK (1 << 31)
+#define DMA_MST_CTRL_GO_DISABLE 0
+#define DMA_MST_CTRL_GO_ENABLE (1 << 31)
+#define DMA_MST_CTRL_DIR_MASK (1 << 30)
+#define DMA_MST_CTRL_DIR_READ 0
+#define DMA_MST_CTRL_DIR_WRITE (1 << 30)
+#define DMA_MST_CTRL_PERF_EN_MASK (1 << 29)
+#define DMA_MST_CTRL_PERF_EN_DISABLE 0
+#define DMA_MST_CTRL_PERF_EN_ENABLE (1 << 29)
+#define DMA_MST_CTRL_REUSE_BUFFER_MASK (1 << 27)
+#define DMA_MST_CTRL_REUSE_BUFFER_DISABLE 0
+#define DMA_MST_CTRL_REUSE_BUFFER_ENABLE (1 << 27)
+#define DMA_MST_CTRL_BURST_SIZE_SHIFT 24
+#define DMA_MST_CTRL_BURST_SIZE_MASK (7 << DMA_MST_CTRL_BURST_SIZE_SHIFT)
+enum {
+ DMA_MST_CTRL_BURST_1WORDS = 2 << DMA_MST_CTRL_BURST_SIZE_SHIFT,
+ DMA_MST_CTRL_BURST_4WORDS = 3 << DMA_MST_CTRL_BURST_SIZE_SHIFT,
+ DMA_MST_CTRL_BURST_8WORDS = 4 << DMA_MST_CTRL_BURST_SIZE_SHIFT,
+ DMA_MST_CTRL_BURST_16WORDS = 5 << DMA_MST_CTRL_BURST_SIZE_SHIFT
+};
+#define DMA_MST_CTRL_IS_DMA_DONE (1 << 20)
+#define DMA_MST_CTRL_EN_A_MASK (1 << 2)
+#define DMA_MST_CTRL_EN_A_DISABLE 0
+#define DMA_MST_CTRL_EN_A_ENABLE (1 << 2)
+#define DMA_MST_CTRL_EN_B_MASK (1 << 1)
+#define DMA_MST_CTRL_EN_B_DISABLE 0
+#define DMA_MST_CTRL_EN_B_ENABLE (1 << 1)
+
+#define DMA_CFG_A_0 0x34
+#define DMA_CFG_B_0 0x38
+#define FIFO_CTRL_0 0x3C
+#define DATA_BLOCK_PTR_0 0x40
+#define TAG_PTR_0 0x44
+#define ECC_PTR_0 0x48
+
+#define DEC_STATUS_0 0x4C
+#define DEC_STATUS_A_ECC_FAIL (1 << 1)
+#define DEC_STATUS_B_ECC_FAIL (1 << 0)
+
+#define BCH_CONFIG_0 0xCC
+#define BCH_CONFIG_BCH_TVALUE_SHIFT 4
+#define BCH_CONFIG_BCH_TVALUE_MASK (3 << BCH_CONFIG_BCH_TVALUE_SHIFT)
+enum {
+ BCH_CONFIG_BCH_TVAL4 = 0 << BCH_CONFIG_BCH_TVALUE_SHIFT,
+ BCH_CONFIG_BCH_TVAL8 = 1 << BCH_CONFIG_BCH_TVALUE_SHIFT,
+ BCH_CONFIG_BCH_TVAL14 = 2 << BCH_CONFIG_BCH_TVALUE_SHIFT,
+ BCH_CONFIG_BCH_TVAL16 = 3 << BCH_CONFIG_BCH_TVALUE_SHIFT
+};
+#define BCH_CONFIG_BCH_ECC_MASK (1 << 0)
+#define BCH_CONFIG_BCH_ECC_DISABLE 0
+#define BCH_CONFIG_BCH_ECC_ENABLE (1 << 0)
+
+#define BCH_DEC_RESULT_0 0xD0
+#define BCH_DEC_RESULT_CORRFAIL_ERR_MASK (1 << 8)
+#define BCH_DEC_RESULT_PAGE_COUNT_MASK 0xFF
+
+#define BCH_DEC_STATUS_BUF_0 0xD4
+#define BCH_DEC_STATUS_FAIL_SEC_FLAG_MASK 0xFF000000
+#define BCH_DEC_STATUS_CORR_SEC_FLAG_MASK 0x00FF0000
+#define BCH_DEC_STATUS_FAIL_TAG_MASK (1 << 14)
+#define BCH_DEC_STATUS_CORR_TAG_MASK (1 << 13)
+#define BCH_DEC_STATUS_MAX_CORR_CNT_MASK (0x1f << 8)
+#define BCH_DEC_STATUS_PAGE_NUMBER_MASK 0xFF
+
+#define LP_OPTIONS (NAND_NO_READRDY | NAND_NO_AUTOINCR)
+
+struct nand_ctlr {
+ u32 command; /* offset 00h */
+ u32 status; /* offset 04h */
+ u32 isr; /* offset 08h */
+ u32 ier; /* offset 0Ch */
+ u32 config; /* offset 10h */
+ u32 timing; /* offset 14h */
+ u32 resp; /* offset 18h */
+ u32 timing2; /* offset 1Ch */
+ u32 cmd_reg1; /* offset 20h */
+ u32 cmd_reg2; /* offset 24h */
+ u32 addr_reg1; /* offset 28h */
+ u32 addr_reg2; /* offset 2Ch */
+ u32 dma_mst_ctrl; /* offset 30h */
+ u32 dma_cfg_a; /* offset 34h */
+ u32 dma_cfg_b; /* offset 38h */
+ u32 fifo_ctrl; /* offset 3Ch */
+ u32 data_block_ptr; /* offset 40h */
+ u32 tag_ptr; /* offset 44h */
+ u32 resv1; /* offset 48h */
+ u32 dec_status; /* offset 4Ch */
+ u32 hwstatus_cmd; /* offset 50h */
+ u32 hwstatus_mask; /* offset 54h */
+ u32 resv2[29];
+ u32 bch_config; /* offset CCh */
+ u32 bch_dec_result; /* offset D0h */
+ u32 bch_dec_status_buf;
+ /* offset D4h */
+};
diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile
index 072b178..cc57354 100644
--- a/drivers/net/fm/Makefile
+++ b/drivers/net/fm/Makefile
@@ -36,10 +36,8 @@ COBJS-y += tgec_phy.o
COBJS-$(CONFIG_P1017) += p1023.o
COBJS-$(CONFIG_P1023) += p1023.o
# The P204x, P304x, and P5020 are the same
-COBJS-$(CONFIG_PPC_P2040) += p5020.o
COBJS-$(CONFIG_PPC_P2041) += p5020.o
COBJS-$(CONFIG_PPC_P3041) += p5020.o
-COBJS-$(CONFIG_PPC_P3060) += p3060.o
COBJS-$(CONFIG_PPC_P4080) += p4080.o
COBJS-$(CONFIG_PPC_P5020) += p5020.o
endif
diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c
index 953c359..736b8b9 100644
--- a/drivers/net/fm/init.c
+++ b/drivers/net/fm/init.c
@@ -50,6 +50,9 @@ struct fm_eth_info fm_info[] = {
#if (CONFIG_SYS_NUM_FM2_DTSEC >= 4)
FM_DTSEC_INFO_INITIALIZER(2, 4),
#endif
+#if (CONFIG_SYS_NUM_FM2_DTSEC >= 5)
+ FM_DTSEC_INFO_INITIALIZER(2, 5),
+#endif
#if (CONFIG_SYS_NUM_FM1_10GEC >= 1)
FM_TGEC_INFO_INITIALIZER(1, 1),
#endif
@@ -152,6 +155,22 @@ void fm_info_set_phy_address(enum fm_port port, int address)
}
/*
+ * Returns the PHY address for a given Fman port
+ *
+ * The port must be set via a prior call to fm_info_set_phy_address().
+ * A negative error code is returned if the port is invalid.
+ */
+int fm_info_get_phy_address(enum fm_port port)
+{
+ int i = fm_port_to_index(port);
+
+ if (i == -1)
+ return -1;
+
+ return fm_info[i].phy_addr;
+}
+
+/*
* Returns the type of the data interface between the given MAC and its PHY.
* This is typically determined by the RCW.
*/
@@ -181,7 +200,8 @@ void board_ft_fman_fixup_port(void *blob, char * prop, phys_addr_t pa,
static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop)
{
- int off, ph;
+ int off;
+ uint32_t ph;
phys_addr_t paddr = CONFIG_SYS_CCSRBAR_PHYS + info->compat_offset;
u64 dtsec1_addr = (u64)CONFIG_SYS_CCSRBAR_PHYS +
CONFIG_SYS_FSL_FM1_DTSEC1_OFFSET;
@@ -198,12 +218,10 @@ static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop)
off = fdt_node_offset_by_compat_reg(blob, prop, paddr);
/* Don't disable FM1-DTSEC1 MAC as its used for MDIO */
- if (paddr != dtsec1_addr) {
- /* disable the mac node */
- fdt_setprop_string(blob, off, "status", "disabled");
- }
+ if (paddr != dtsec1_addr)
+ fdt_status_disabled(blob, off); /* disable the MAC node */
- /* disable the node point to the mac */
+ /* disable the fsl,dpa-ethernet node that points to the MAC */
ph = fdt_get_phandle(blob, off);
do_fixup_by_prop(blob, "fsl,fman-mac", &ph, sizeof(ph),
"status", "disabled", strlen("disabled") + 1, 1);
diff --git a/drivers/net/fm/p3060.c b/drivers/net/fm/p3060.c
deleted file mode 100644
index c9748a9..0000000
--- a/drivers/net/fm/p3060.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2011 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-#include <common.h>
-#include <phy.h>
-#include <fm_eth.h>
-#include <asm/io.h>
-#include <asm/immap_85xx.h>
-#include <asm/fsl_serdes.h>
-
-u32 port_to_devdisr[] = {
- [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
- [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
- [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
- [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
- [FM2_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC2_1,
- [FM2_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC2_2,
- [FM2_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC2_3,
- [FM2_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC2_4,
-};
-
-static int is_device_disabled(enum fm_port port)
-{
- ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
- u32 devdisr2 = in_be32(&gur->devdisr2);
-
- return port_to_devdisr[port] & devdisr2;
-}
-
-void fman_disable_port(enum fm_port port)
-{
- ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
-
- /* don't allow disabling of DTSEC1 as its needed for MDIO */
- if (port == FM1_DTSEC1)
- return;
-
- setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
-}
-
-phy_interface_t fman_port_enet_if(enum fm_port port)
-{
- ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
- u32 rcwsr11 = in_be32(&gur->rcwsr[11]);
-
- if (is_device_disabled(port))
- return PHY_INTERFACE_MODE_NONE;
-
- /* handle RGMII/MII first */
- if ((port == FM1_DTSEC1) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC1) ==
- FSL_CORENET_RCWSR11_EC1_FM1_DTSEC1))
- return PHY_INTERFACE_MODE_RGMII;
-
- if ((port == FM1_DTSEC2) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
- FSL_CORENET_RCWSR11_EC2_FM1_DTSEC2))
- return PHY_INTERFACE_MODE_RGMII;
-
- if ((port == FM2_DTSEC1) && ((rcwsr11 & FSL_CORENET_RCWSR11_EC2) ==
- FSL_CORENET_RCWSR11_EC2_FM2_DTSEC1))
- return PHY_INTERFACE_MODE_RGMII;
-
- switch (port) {
- case FM1_DTSEC1:
- case FM1_DTSEC2:
- case FM1_DTSEC3:
- case FM1_DTSEC4:
- if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
- return PHY_INTERFACE_MODE_SGMII;
- break;
- case FM2_DTSEC1:
- case FM2_DTSEC2:
- case FM2_DTSEC3:
- case FM2_DTSEC4:
- if (is_serdes_configured(SGMII_FM2_DTSEC1 + port - FM2_DTSEC1))
- return PHY_INTERFACE_MODE_SGMII;
- break;
- default:
- return PHY_INTERFACE_MODE_NONE;
- }
-
- return PHY_INTERFACE_MODE_NONE;
-}
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index 08206c8..3103a74 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -483,7 +483,7 @@ int greth_recv(struct eth_device *dev)
greth_regs *regs = greth->regs;
greth_bd *rxbd;
unsigned int status, len = 0, bad;
- unsigned char *d;
+ char *d;
int enable = 0;
int i;
@@ -504,7 +504,7 @@ int greth_recv(struct eth_device *dev)
goto done;
}
- debug("greth_recv: packet 0x%lx, 0x%lx, len: %d\n",
+ debug("greth_recv: packet 0x%x, 0x%x, len: %d\n",
(unsigned int)rxbd, status, status & GRETH_BD_LEN);
/* Check status for errors.
@@ -620,7 +620,7 @@ int greth_initialize(bd_t * bis)
greth->regs = (greth_regs *) apbdev.address;
greth->irq = apbdev.irq;
- debug("Found GRETH at 0x%lx, irq %d\n", greth->regs, greth->irq);
+ debug("Found GRETH at %p, irq %d\n", greth->regs, greth->irq);
dev->priv = (void *)greth;
dev->iobase = (unsigned int)greth->regs;
dev->init = greth_init;
@@ -652,7 +652,7 @@ int greth_initialize(bd_t * bis)
/* initiate PHY, select speed/duplex depending on connected PHY */
if (greth_init_phy(greth, bis)) {
/* Failed to init PHY (timedout) */
- debug("GRETH[0x%08x]: Failed to init PHY\n", greth->regs);
+ debug("GRETH[%p]: Failed to init PHY\n", greth->regs);
return -1;
}
@@ -681,6 +681,6 @@ int greth_initialize(bd_t * bis)
/* set and remember MAC address */
greth_set_hwaddr(greth, addr);
- debug("GRETH[0x%08x]: Initialized successfully\n", greth->regs);
+ debug("GRETH[%p]: Initialized successfully\n", greth->regs);
return 0;
}
diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c
index 1d75a82..0d46c96 100644
--- a/drivers/pci/fsl_pci_init.c
+++ b/drivers/pci/fsl_pci_init.c
@@ -211,6 +211,95 @@ static int fsl_pci_setup_inbound_windows(struct pci_controller *hose,
return 1;
}
+#ifdef CONFIG_FSL_CORENET
+static void fsl_pcie_boot_master(pit_t *pi)
+{
+ /* configure inbound window for slave's u-boot image */
+ debug("PCIEBOOT - MASTER: Inbound window for slave's image; "
+ "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+ struct pci_region r_inbound;
+ u32 sz_inbound = __ilog2_u64(CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE)
+ - 1;
+ pci_set_region(&r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS1,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ sz_inbound,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ set_inbound_window(pi--, &r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+
+ /* configure inbound window for slave's u-boot image */
+ debug("PCIEBOOT - MASTER: Inbound window for slave's image; "
+ "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+ pci_set_region(&r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_BUS2,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_MEM_PHYS,
+ sz_inbound,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ set_inbound_window(pi--, &r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_IMAGE_SIZE);
+
+ /* configure inbound window for slave's ucode and ENV */
+ debug("PCIEBOOT - MASTER: Inbound window for slave's "
+ "ucode and ENV; "
+ "Local = 0x%llx, Bus = 0x%llx, Size = 0x%x\n",
+ (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS,
+ (u64)CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE);
+ sz_inbound = __ilog2_u64(CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE)
+ - 1;
+ pci_set_region(&r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_BUS,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_MEM_PHYS,
+ sz_inbound,
+ PCI_REGION_MEM | PCI_REGION_SYS_MEMORY);
+
+ set_inbound_window(pi--, &r_inbound,
+ CONFIG_SRIO_PCIE_BOOT_UCODE_ENV_SIZE);
+}
+
+static void fsl_pcie_boot_master_release_slave(int port)
+{
+ unsigned long release_addr;
+
+ /* now release slave's core 0 */
+ switch (port) {
+ case 1:
+ release_addr = CONFIG_SYS_PCIE1_MEM_VIRT
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
+ break;
+ case 2:
+ release_addr = CONFIG_SYS_PCIE2_MEM_VIRT
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
+ break;
+ case 3:
+ release_addr = CONFIG_SYS_PCIE3_MEM_VIRT
+ + CONFIG_SRIO_PCIE_BOOT_BRR_OFFSET;
+ break;
+ default:
+ release_addr = 0;
+ break;
+ }
+ if (release_addr != 0) {
+ out_be32((void *)release_addr,
+ CONFIG_SRIO_PCIE_BOOT_RELEASE_MASK);
+ debug("PCIEBOOT - MASTER: "
+ "Release slave successfully! Now the slave should start up!\n");
+ } else {
+ debug("PCIEBOOT - MASTER: "
+ "Release slave failed!\n");
+ }
+}
+#endif
+
void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
{
u32 cfg_addr = (u32)&((ccsr_fsl_pci_t *)pci_info->regs)->cfg_addr;
@@ -295,8 +384,25 @@ void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info)
/* see if we are a PCIe or PCI controller */
pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);
+#ifdef CONFIG_FSL_CORENET
+ /* boot from PCIE --master */
+ char *s = getenv("bootmaster");
+ char pcie[6];
+ sprintf(pcie, "PCIE%d", pci_info->pci_num);
+
+ if (s && (strcmp(s, pcie) == 0)) {
+ debug("PCIEBOOT - MASTER: Master port [ %d ] for pcie boot.\n",
+ pci_info->pci_num);
+ fsl_pcie_boot_master((pit_t *)pi);
+ } else {
+ /* inbound */
+ inbound = fsl_pci_setup_inbound_windows(hose,
+ out_lo, pcie_cap, pi);
+ }
+#else
/* inbound */
inbound = fsl_pci_setup_inbound_windows(hose, out_lo, pcie_cap, pi);
+#endif
for (r = 0; r < hose->region_count; r++)
debug("PCI reg:%d %016llx:%016llx %016llx %08lx\n", r,
@@ -488,6 +594,16 @@ int fsl_pci_init_port(struct fsl_pci_info *pci_info,
if (fsl_is_pci_agent(hose)) {
fsl_pci_config_unlock(hose);
hose->last_busno = hose->first_busno;
+#ifdef CONFIG_FSL_CORENET
+ } else {
+ /* boot from PCIE --master releases slave's core 0 */
+ char *s = getenv("bootmaster");
+ char pcie[6];
+ sprintf(pcie, "PCIE%d", pci_info->pci_num);
+
+ if (s && (strcmp(s, pcie) == 0))
+ fsl_pcie_boot_master_release_slave(pci_info->pci_num);
+#endif
}
pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2a6d0a7..d864f13 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -118,11 +118,11 @@ PCI_WRITE_VIA_DWORD_OP(word, u16, 0x02, 0x0000ffff)
void *pci_map_bar(pci_dev_t pdev, int bar, int flags)
{
pci_addr_t pci_bus_addr;
- pci_addr_t bar_response;
+ u32 bar_response;
/* read BAR address */
pci_read_config_dword(pdev, bar, &bar_response);
- pci_bus_addr = bar_response & ~0xf;
+ pci_bus_addr = (pci_addr_t)(bar_response & ~0xf);
/*
* Pass "0" as the length argument to pci_bus_to_virt. The arg
@@ -389,7 +389,7 @@ int pci_hose_config_device(struct pci_controller *hose,
pci_addr_t mem,
unsigned long command)
{
- pci_addr_t bar_response;
+ u32 bar_response;
unsigned int old_command;
pci_addr_t bar_value;
pci_size_t bar_size;
diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c
index ae61e24..cd78030 100644
--- a/drivers/pci/pci_auto.c
+++ b/drivers/pci/pci_auto.c
@@ -89,7 +89,7 @@ void pciauto_setup_device(struct pci_controller *hose,
struct pci_region *prefetch,
struct pci_region *io)
{
- pci_addr_t bar_response;
+ u32 bar_response;
pci_size_t bar_size;
u16 cmdstat = 0;
int bar, bar_nr = 0;
diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c
index 216c898..e6ae709 100644
--- a/drivers/qe/uec.c
+++ b/drivers/qe/uec.c
@@ -580,8 +580,7 @@ static void phy_change(struct eth_device *dev)
{
uec_private_t *uec = (uec_private_t *)dev->priv;
-#if defined(CONFIG_P1012) || defined(CONFIG_P1016) || \
- defined(CONFIG_P1021) || defined(CONFIG_P1025)
+#if defined(CONFIG_P1012) || defined(CONFIG_P1021) || defined(CONFIG_P1025)
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
/* QE9 and QE12 need to be set for enabling QE MII managment signals */
@@ -592,8 +591,7 @@ static void phy_change(struct eth_device *dev)
/* Update the link, speed, duplex */
uec->mii_info->phyinfo->read_status(uec->mii_info);
-#if defined(CONFIG_P1012) || defined(CONFIG_P1016) || \
- defined(CONFIG_P1021) || defined(CONFIG_P1025)
+#if defined(CONFIG_P1012) || defined(CONFIG_P1021) || defined(CONFIG_P1025)
/*
* QE12 is muxed with LBCTL, it needs to be released for enabling
* LBCTL signal for LBC usage.
@@ -1208,16 +1206,14 @@ static int uec_init(struct eth_device* dev, bd_t *bd)
uec_private_t *uec;
int err, i;
struct phy_info *curphy;
-#if defined(CONFIG_P1012) || defined(CONFIG_P1016) || \
- defined(CONFIG_P1021) || defined(CONFIG_P1025)
+#if defined(CONFIG_P1012) || defined(CONFIG_P1021) || defined(CONFIG_P1025)
ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
#endif
uec = (uec_private_t *)dev->priv;
if (uec->the_first_run == 0) {
-#if defined(CONFIG_P1012) || defined(CONFIG_P1016) || \
- defined(CONFIG_P1021) || defined(CONFIG_P1025)
+#if defined(CONFIG_P1012) || defined(CONFIG_P1021) || defined(CONFIG_P1025)
/* QE9 and QE12 need to be set for enabling QE MII managment signals */
setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE9);
setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12);
@@ -1249,8 +1245,7 @@ static int uec_init(struct eth_device* dev, bd_t *bd)
udelay(100000);
} while (1);
-#if defined(CONFIG_P1012) || defined(CONFIG_P1016) || \
- defined(CONFIG_P1021) || defined(CONFIG_P1025)
+#if defined(CONFIG_P1012) || defined(CONFIG_P1021) || defined(CONFIG_P1025)
/* QE12 needs to be released for enabling LBCTL signal*/
clrbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_QE12);
#endif
diff --git a/drivers/serial/serial_xuartlite.c b/drivers/serial/serial_xuartlite.c
index 3a38f9e..2bdb68b 100644
--- a/drivers/serial/serial_xuartlite.c
+++ b/drivers/serial/serial_xuartlite.c
@@ -89,11 +89,17 @@ int uartlite_serial_tstc(const int port)
return in_be32(&regs->status) & SR_RX_FIFO_VALID_DATA;
}
+static int uartlite_serial_init(const int port)
+{
+ if (userial_ports[port])
+ return 0;
+ return -1;
+}
+
#if !defined(CONFIG_SERIAL_MULTI)
int serial_init(void)
{
- /* FIXME: Nothing for now. We should initialize fifo, etc */
- return 0;
+ return uartlite_serial_init(0);
}
void serial_setbrg(void)
@@ -126,7 +132,7 @@ int serial_tstc(void)
/* Multi serial device functions */
#define DECLARE_ESERIAL_FUNCTIONS(port) \
int userial##port##_init(void) \
- { return(0); } \
+ { return uartlite_serial_init(port); } \
void userial##port##_setbrg(void) {} \
int userial##port##_getc(void) \
{ return uartlite_serial_getc(port); } \
@@ -163,17 +169,15 @@ struct serial_device uartlite_serial3_device =
__weak struct serial_device *default_serial_console(void)
{
-# ifdef XILINX_UARTLITE_BASEADDR
- return &uartlite_serial0_device;
-# endif /* XILINX_UARTLITE_BASEADDR */
-# ifdef XILINX_UARTLITE_BASEADDR1
- return &uartlite_serial1_device;
-# endif /* XILINX_UARTLITE_BASEADDR1 */
-# ifdef XILINX_UARTLITE_BASEADDR2
- return &uartlite_serial2_device;
-# endif /* XILINX_UARTLITE_BASEADDR2 */
-# ifdef XILINX_UARTLITE_BASEADDR3
- return &uartlite_serial3_device;
-# endif /* XILINX_UARTLITE_BASEADDR3 */
+ if (userial_ports[0])
+ return &uartlite_serial0_device;
+ if (userial_ports[1])
+ return &uartlite_serial1_device;
+ if (userial_ports[2])
+ return &uartlite_serial2_device;
+ if (userial_ports[3])
+ return &uartlite_serial3_device;
+
+ return NULL;
}
#endif /* CONFIG_SERIAL_MULTI */
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 80b981f..f0b82c6 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -32,6 +32,7 @@ COBJS-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o
COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o
COBJS-$(CONFIG_CF_SPI) += cf_spi.o
+COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
diff --git a/drivers/spi/cf_qspi.c b/drivers/spi/cf_qspi.c
new file mode 100644
index 0000000..72dd1a5
--- /dev/null
+++ b/drivers/spi/cf_qspi.c
@@ -0,0 +1,373 @@
+/*
+ * Freescale Coldfire Queued SPI driver
+ *
+ * NOTE:
+ * This driver is written to transfer 8 bit at-a-time and uses the dedicated
+ * SPI slave select pins as bit-banged GPIO to work with spi_flash subsystem.
+ *
+ *
+ * Copyright (C) 2011 Ruggedcom, Inc.
+ * Richard Retanubun (richardretanubun@freescale.com)
+ *
+ * See file CREDITS for list of people who contributed to this project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/immap.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define clamp(x, low, high) (min(max(low, x), high))
+#define to_cf_qspi_slave(s) container_of(s, struct cf_qspi_slave, s)
+
+struct cf_qspi_slave {
+ struct spi_slave slave; /* Specific bus:cs ID for each device */
+ qspi_t *regs; /* Pointer to SPI controller registers */
+ u16 qmr; /* QMR: Queued Mode Register */
+ u16 qwr; /* QWR: Queued Wrap Register */
+ u16 qcr; /* QCR: Queued Command Ram */
+};
+
+/* Register write wrapper functions */
+static void write_qmr(volatile qspi_t *qspi, u16 val) { qspi->mr = val; }
+static void write_qdlyr(volatile qspi_t *qspi, u16 val) { qspi->dlyr = val; }
+static void write_qwr(volatile qspi_t *qspi, u16 val) { qspi->wr = val; }
+static void write_qir(volatile qspi_t *qspi, u16 val) { qspi->ir = val; }
+static void write_qar(volatile qspi_t *qspi, u16 val) { qspi->ar = val; }
+static void write_qdr(volatile qspi_t *qspi, u16 val) { qspi->dr = val; }
+/* Register read wrapper functions */
+static u16 read_qdlyr(volatile qspi_t *qspi) { return qspi->dlyr; }
+static u16 read_qwr(volatile qspi_t *qspi) { return qspi->wr; }
+static u16 read_qir(volatile qspi_t *qspi) { return qspi->ir; }
+static u16 read_qdr(volatile qspi_t *qspi) { return qspi->dr; }
+
+/* These call points may be different for each ColdFire CPU */
+extern void cfspi_port_conf(void);
+static void cfspi_cs_activate(uint bus, uint cs, uint cs_active_high);
+static void cfspi_cs_deactivate(uint bus, uint cs, uint cs_active_high);
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ return 0;
+}
+void spi_release_bus(struct spi_slave *slave)
+{
+}
+
+__attribute__((weak))
+void spi_init(void)
+{
+ cfspi_port_conf();
+}
+
+__attribute__((weak))
+void spi_cs_activate(struct spi_slave *slave)
+{
+ struct cf_qspi_slave *dev = to_cf_qspi_slave(slave);
+
+ cfspi_cs_activate(slave->bus, slave->cs, !(dev->qwr & QSPI_QWR_CSIV));
+}
+
+__attribute__((weak))
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+ struct cf_qspi_slave *dev = to_cf_qspi_slave(slave);
+
+ cfspi_cs_deactivate(slave->bus, slave->cs, !(dev->qwr & QSPI_QWR_CSIV));
+}
+
+__attribute__((weak))
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ /* Only 1 bus and 4 chipselect per controller */
+ if (bus == 0 && (cs >= 0 && cs < 4))
+ return 1;
+ else
+ return 0;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct cf_qspi_slave *dev = to_cf_qspi_slave(slave);
+
+ free(dev);
+}
+
+/* Translate information given by spi_setup_slave to members of cf_qspi_slave */
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct cf_qspi_slave *dev = NULL;
+
+ if (!spi_cs_is_valid(bus, cs))
+ return NULL;
+
+ dev = malloc(sizeof(struct cf_qspi_slave));
+ if (!dev)
+ return NULL;
+
+ /* Initialize to known value */
+ dev->slave.bus = bus;
+ dev->slave.cs = cs;
+ dev->regs = (qspi_t *)MMAP_QSPI;
+ dev->qmr = 0;
+ dev->qwr = 0;
+ dev->qcr = 0;
+
+
+ /* Map max_hz to QMR[BAUD] */
+ if (max_hz == 0) /* Go as fast as possible */
+ dev->qmr = 2u;
+ else /* Get the closest baud rate */
+ dev->qmr = clamp(((gd->bus_clk >> 2) + max_hz - 1)/max_hz,
+ 2u, 255u);
+
+ /* Map mode to QMR[CPOL] and QMR[CPHA] */
+ if (mode & SPI_CPOL)
+ dev->qmr |= QSPI_QMR_CPOL;
+
+ if (mode & SPI_CPHA)
+ dev->qmr |= QSPI_QMR_CPHA;
+
+ /* Hardcode bit length to 8 bit per transter */
+ dev->qmr |= QSPI_QMR_BITS_8;
+
+ /* Set QMR[MSTR] to enable QSPI as master */
+ dev->qmr |= QSPI_QMR_MSTR;
+
+ /*
+ * Set QCR and QWR to default values for spi flash operation.
+ * If more custom QCR and QRW are needed, overload mode variable
+ */
+ dev->qcr = (QSPI_QDR_CONT | QSPI_QDR_BITSE);
+
+ if (!(mode & SPI_CS_HIGH))
+ dev->qwr |= QSPI_QWR_CSIV;
+
+ return &dev->slave;
+}
+
+/* Transfer 8 bit at a time */
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
+{
+ struct cf_qspi_slave *dev = to_cf_qspi_slave(slave);
+ volatile qspi_t *qspi = dev->regs;
+ u8 *txbuf = (u8 *)dout;
+ u8 *rxbuf = (u8 *)din;
+ u32 count = ((bitlen / 8) + (bitlen % 8 ? 1 : 0));
+ u32 n, i = 0;
+
+ /* Sanitize arguments */
+ if (slave == NULL) {
+ printf("%s: NULL slave ptr\n", __func__);
+ return -1;
+ }
+
+ if (flags & SPI_XFER_BEGIN)
+ spi_cs_activate(slave);
+
+ /* There is something to send, lets process it. spi_xfer is also called
+ * just to toggle chip select, so bitlen of 0 is valid */
+ if (count > 0) {
+ /*
+ * NOTE: Since chip select is driven as a bit-bang-ed GPIO
+ * using spi_cs_activate() and spi_cs_deactivate(),
+ * the chip select settings inside the controller
+ * (i.e. QCR[CONT] and QWR[CSIV]) are moot. The bits are set to
+ * keep the controller settings consistent with the actual
+ * operation of the bus.
+ */
+
+ /* Write the slave device's settings for the controller.*/
+ write_qmr(qspi, dev->qmr);
+ write_qwr(qspi, dev->qwr);
+
+ /* Limit transfer to 16 at a time */
+ n = min(count, 16u);
+ do {
+ /* Setup queue end point */
+ write_qwr(qspi, ((read_qwr(qspi) & QSPI_QWR_ENDQP_MASK)
+ | QSPI_QWR_ENDQP((n-1))));
+
+ /* Write Command RAM */
+ write_qar(qspi, QSPI_QAR_CMD);
+ for (i = 0; i < n; ++i)
+ write_qdr(qspi, dev->qcr);
+
+ /* Write TxBuf, if none given, fill with ZEROes */
+ write_qar(qspi, QSPI_QAR_TRANS);
+ if (txbuf) {
+ for (i = 0; i < n; ++i)
+ write_qdr(qspi, *txbuf++);
+ } else {
+ for (i = 0; i < n; ++i)
+ write_qdr(qspi, 0);
+ }
+
+ /* Clear QIR[SPIF] by writing a 1 to it */
+ write_qir(qspi, read_qir(qspi) | QSPI_QIR_SPIF);
+ /* Set QDLYR[SPE] to start sending */
+ write_qdlyr(qspi, read_qdlyr(qspi) | QSPI_QDLYR_SPE);
+
+ /* Poll QIR[SPIF] for transfer completion */
+ while ((read_qir(qspi) & QSPI_QIR_SPIF) != 1)
+ udelay(1);
+
+ /* If given read RxBuf, load data to it */
+ if (rxbuf) {
+ write_qar(qspi, QSPI_QAR_RECV);
+ for (i = 0; i < n; ++i)
+ *rxbuf++ = read_qdr(qspi);
+ }
+
+ /* Decrement count */
+ count -= n;
+ } while (count);
+ }
+
+ if (flags & SPI_XFER_END)
+ spi_cs_deactivate(slave);
+
+ return 0;
+}
+
+/* Each MCF CPU may have different pin assignments for chip selects. */
+#if defined(CONFIG_M5271)
+/* Assert chip select, val = [1|0] , dir = out, mode = GPIO */
+void cfspi_cs_activate(uint bus, uint cs, uint cs_active_high)
+{
+ debug("%s: bus %d cs %d cs_active_high %d\n",
+ __func__, bus, cs, cs_active_high);
+
+ switch (cs) {
+ case 0: /* QSPI_CS[0] = PQSPI[3] */
+ if (cs_active_high)
+ mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x08);
+ else
+ mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xF7);
+
+ mbar_writeByte(MCF_GPIO_PDDR_QSPI,
+ mbar_readByte(MCF_GPIO_PDDR_QSPI) | 0x08);
+
+ mbar_writeByte(MCF_GPIO_PAR_QSPI,
+ mbar_readByte(MCF_GPIO_PAR_QSPI) & 0xDF);
+ break;
+ case 1: /* QSPI_CS[1] = PQSPI[4] */
+ if (cs_active_high)
+ mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x10);
+ else
+ mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xEF);
+
+ mbar_writeByte(MCF_GPIO_PDDR_QSPI,
+ mbar_readByte(MCF_GPIO_PDDR_QSPI) | 0x10);
+
+ mbar_writeByte(MCF_GPIO_PAR_QSPI,
+ mbar_readByte(MCF_GPIO_PAR_QSPI) & 0x3F);
+ break;
+ case 2: /* QSPI_CS[2] = PTIMER[7] */
+ if (cs_active_high)
+ mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x80);
+ else
+ mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0x7F);
+
+ mbar_writeByte(MCF_GPIO_PDDR_TIMER,
+ mbar_readByte(MCF_GPIO_PDDR_TIMER) | 0x80);
+
+ mbar_writeShort(MCF_GPIO_PAR_TIMER,
+ mbar_readShort(MCF_GPIO_PAR_TIMER) & 0x3FFF);
+ break;
+ case 3: /* QSPI_CS[3] = PTIMER[3] */
+ if (cs_active_high)
+ mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x08);
+ else
+ mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0xF7);
+
+ mbar_writeByte(MCF_GPIO_PDDR_TIMER,
+ mbar_readByte(MCF_GPIO_PDDR_TIMER) | 0x08);
+
+ mbar_writeShort(MCF_GPIO_PAR_TIMER,
+ mbar_readShort(MCF_GPIO_PAR_TIMER) & 0xFF3F);
+ break;
+ }
+}
+
+/* Deassert chip select, val = [1|0], dir = in, mode = GPIO
+ * direction set as IN to undrive the pin, external pullup/pulldown will bring
+ * bus to deassert state.
+ */
+void cfspi_cs_deactivate(uint bus, uint cs, uint cs_active_high)
+{
+ debug("%s: bus %d cs %d cs_active_high %d\n",
+ __func__, bus, cs, cs_active_high);
+
+ switch (cs) {
+ case 0: /* QSPI_CS[0] = PQSPI[3] */
+ if (cs_active_high)
+ mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xF7);
+ else
+ mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x08);
+
+ mbar_writeByte(MCF_GPIO_PDDR_QSPI,
+ mbar_readByte(MCF_GPIO_PDDR_QSPI) & 0xF7);
+
+ mbar_writeByte(MCF_GPIO_PAR_QSPI,
+ mbar_readByte(MCF_GPIO_PAR_QSPI) & 0xDF);
+ break;
+ case 1: /* QSPI_CS[1] = PQSPI[4] */
+ if (cs_active_high)
+ mbar_writeByte(MCF_GPIO_PCLRR_QSPI, 0xEF);
+ else
+ mbar_writeByte(MCF_GPIO_PPDSDR_QSPI, 0x10);
+
+ mbar_writeByte(MCF_GPIO_PDDR_QSPI,
+ mbar_readByte(MCF_GPIO_PDDR_QSPI) & 0xEF);
+
+ mbar_writeByte(MCF_GPIO_PAR_QSPI,
+ mbar_readByte(MCF_GPIO_PAR_QSPI) & 0x3F);
+ break;
+ case 2: /* QSPI_CS[2] = PTIMER[7] */
+ if (cs_active_high)
+ mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0x7F);
+ else
+ mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x80);
+
+ mbar_writeByte(MCF_GPIO_PDDR_TIMER,
+ mbar_readByte(MCF_GPIO_PDDR_TIMER) & 0x7F);
+
+ mbar_writeShort(MCF_GPIO_PAR_TIMER,
+ mbar_readShort(MCF_GPIO_PAR_TIMER) & 0x3FFF);
+ break;
+ case 3: /* QSPI_CS[3] = PTIMER[3] */
+ if (cs_active_high)
+ mbar_writeByte(MCF_GPIO_PCLRR_TIMER, 0xF7);
+ else
+ mbar_writeByte(MCF_GPIO_PPDSDR_TIMER, 0x08);
+
+ mbar_writeByte(MCF_GPIO_PDDR_TIMER,
+ mbar_readByte(MCF_GPIO_PDDR_TIMER) & 0xF7);
+
+ mbar_writeShort(MCF_GPIO_PAR_TIMER,
+ mbar_readShort(MCF_GPIO_PAR_TIMER) & 0xFF3F);
+ break;
+ }
+}
+#endif /* CONFIG_M5271 */
diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c
index f4523a3..a7cda75 100644
--- a/drivers/spi/kirkwood_spi.c
+++ b/drivers/spi/kirkwood_spi.c
@@ -56,8 +56,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
writel(~KWSPI_CSN_ACT | KWSPI_SMEMRDY, &spireg->ctrl);
/* calculate spi clock prescaller using max_hz */
- data = ((CONFIG_SYS_TCLK / 2) / max_hz) & KWSPI_CLKPRESCL_MASK;
- data |= 0x10;
+ data = ((CONFIG_SYS_TCLK / 2) / max_hz) + 0x10;
+ data = data < KWSPI_CLKPRESCL_MIN ? KWSPI_CLKPRESCL_MIN : data;
+ data = data > KWSPI_CLKPRESCL_MASK ? KWSPI_CLKPRESCL_MASK : data;
/* program spi clock prescaller using max_hz */
writel(KWSPI_ADRLEN_3BYTE | data, &spireg->cfg);
diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c
index 44ab39d..4e46041 100644
--- a/drivers/spi/mpc8xxx_spi.c
+++ b/drivers/spi/mpc8xxx_spi.c
@@ -124,6 +124,8 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
* len > 16 0
*/
+ spi->mode &= ~SPI_MODE_EN;
+
if (bitlen <= 16) {
if (bitlen <= 4)
spi->mode = (spi->mode & 0xff0fffff) |
@@ -138,6 +140,8 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
dout += 4;
}
+ spi->mode |= SPI_MODE_EN;
+
spi->tx = tmpdout; /* Write the data out */
debug("*** spi_xfer: ... %08x written\n", tmpdout);
diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c
index 168dbe4..42e4c99 100644
--- a/drivers/spi/mxs_spi.c
+++ b/drivers/spi/mxs_spi.c
@@ -224,8 +224,10 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
struct mxs_dma_desc *dp;
uint32_t ctrl0;
uint32_t cache_data_count;
+ const uint32_t dstart = (uint32_t)data;
int dmach;
int tl;
+ int ret = 0;
ALLOC_CACHE_ALIGN_BUFFER(struct mxs_dma_desc, desc, desc_count);
@@ -239,17 +241,17 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
if (!write)
ctrl0 |= SSP_CTRL0_READ;
- writel(length, &ssp_regs->hw_ssp_xfer_size);
-
if (length % ARCH_DMA_MINALIGN)
cache_data_count = roundup(length, ARCH_DMA_MINALIGN);
else
cache_data_count = length;
+ /* Flush data to DRAM so DMA can pick them up */
if (write)
- /* Flush data to DRAM so DMA can pick them up */
- flush_dcache_range((uint32_t)data,
- (uint32_t)(data + cache_data_count));
+ flush_dcache_range(dstart, dstart + cache_data_count);
+
+ /* Invalidate the area, so no writeback into the RAM races with DMA */
+ invalidate_dcache_range(dstart, dstart + cache_data_count);
dmach = MXS_DMA_CHANNEL_AHB_APBH_SSP0 + slave->slave.bus;
@@ -281,41 +283,47 @@ static int mxs_spi_xfer_dma(struct mxs_spi_slave *slave,
tl = min(length, xfer_max_sz);
dp->cmd.data |=
- (tl << MXS_DMA_DESC_BYTES_OFFSET) |
- (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) |
+ ((tl & 0xffff) << MXS_DMA_DESC_BYTES_OFFSET) |
+ (4 << MXS_DMA_DESC_PIO_WORDS_OFFSET) |
MXS_DMA_DESC_HALT_ON_TERMINATE |
MXS_DMA_DESC_TERMINATE_FLUSH;
- dp->cmd.pio_words[0] = ctrl0;
data += tl;
length -= tl;
+ if (!length) {
+ dp->cmd.data |= MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM;
+
+ if (flags & SPI_XFER_END) {
+ ctrl0 &= ~SSP_CTRL0_LOCK_CS;
+ ctrl0 |= SSP_CTRL0_IGNORE_CRC;
+ }
+ }
+
+ /*
+ * Write CTRL0, CMD0, CMD1, XFER_SIZE registers. It is
+ * essential that the XFER_SIZE register is written on
+ * a per-descriptor basis with the same size as is the
+ * descriptor!
+ */
+ dp->cmd.pio_words[0] = ctrl0;
+ dp->cmd.pio_words[1] = 0;
+ dp->cmd.pio_words[2] = 0;
+ dp->cmd.pio_words[3] = tl;
+
mxs_dma_desc_append(dmach, dp);
dp++;
}
- dp->address = (dma_addr_t)dp;
- dp->cmd.address = (dma_addr_t)0;
- dp->cmd.data = MXS_DMA_DESC_COMMAND_NO_DMAXFER |
- (1 << MXS_DMA_DESC_PIO_WORDS_OFFSET) |
- MXS_DMA_DESC_IRQ | MXS_DMA_DESC_DEC_SEM;
- if (flags & SPI_XFER_END) {
- ctrl0 &= ~SSP_CTRL0_LOCK_CS;
- dp->cmd.pio_words[0] = ctrl0 | SSP_CTRL0_IGNORE_CRC;
- }
- mxs_dma_desc_append(dmach, dp);
-
if (mxs_dma_go(dmach))
- return -EINVAL;
+ ret = -EINVAL;
/* The data arrived into DRAM, invalidate cache over them */
- if (!write) {
- invalidate_dcache_range((uint32_t)data,
- (uint32_t)(data + cache_data_count));
- }
+ if (!write)
+ invalidate_dcache_range(dstart, dstart + cache_data_count);
- return 0;
+ return ret;
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
diff --git a/drivers/spi/tegra_spi.c b/drivers/spi/tegra_spi.c
index 2355e02..18b00b2 100644
--- a/drivers/spi/tegra_spi.c
+++ b/drivers/spi/tegra_spi.c
@@ -72,9 +72,9 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
return NULL;
}
- if (max_hz > TEGRA20_SPI_MAX_FREQ) {
+ if (max_hz > TEGRA_SPI_MAX_FREQ) {
printf("SPI error: unsupported frequency %d Hz. Max frequency"
- " is %d Hz\n", max_hz, TEGRA20_SPI_MAX_FREQ);
+ " is %d Hz\n", max_hz, TEGRA_SPI_MAX_FREQ);
return NULL;
}
@@ -86,7 +86,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
spi->slave.bus = bus;
spi->slave.cs = cs;
spi->freq = max_hz;
- spi->regs = (struct spi_tegra *)TEGRA20_SPI_BASE;
+ spi->regs = (struct spi_tegra *)NV_PA_SPI_BASE;
spi->mode = mode;
return &spi->slave;
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index e563c19..52a4134 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -78,7 +78,6 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
struct xilinx_spi_slave *xilspi;
- struct xilinx_spi_reg *regs;
if (!spi_cs_is_valid(bus, cs)) {
printf("XILSPI error: %s: unsupported bus %d / cs %d\n",
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 18b4bc6..392e286 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -22,6 +22,7 @@
*/
#include <common.h>
#include <asm/byteorder.h>
+#include <asm/unaligned.h>
#include <usb.h>
#include <asm/io.h>
#include <malloc.h>
@@ -866,10 +867,12 @@ int usb_lowlevel_init(void)
printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
/* Port Indicators */
if (HCS_INDICATOR(reg))
- descriptor.hub.wHubCharacteristics |= 0x80;
+ put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics)
+ | 0x80, &descriptor.hub.wHubCharacteristics);
/* Port Power Control */
if (HCS_PPC(reg))
- descriptor.hub.wHubCharacteristics |= 0x01;
+ put_unaligned(get_unaligned(&descriptor.hub.wHubCharacteristics)
+ | 0x01, &descriptor.hub.wHubCharacteristics);
/* Start the host controller. */
cmd = ehci_readl(&hcor->or_usbcmd);
diff --git a/drivers/video/omap3_dss.c b/drivers/video/omap3_dss.c
index 6686718..b1424bf 100644
--- a/drivers/video/omap3_dss.c
+++ b/drivers/video/omap3_dss.c
@@ -112,7 +112,7 @@ void omap3_dss_panel_config(const struct panel_config *panel_cfg)
writel(panel_cfg->pol_freq, &dispc->pol_freq);
writel(panel_cfg->divisor, &dispc->divisor);
writel(panel_cfg->lcd_size, &dispc->size_lcd);
- writel(panel_cfg->load_mode << FRAME_MODE_SHIFT, &dispc->config);
+ writel(panel_cfg->load_mode << LOADMODE_SHIFT, &dispc->config);
writel(panel_cfg->panel_type << TFTSTN_SHIFT |
panel_cfg->data_lines << DATALINES_SHIFT, &dispc->control);
writel(panel_cfg->panel_color, &dispc->default_color0);
@@ -121,7 +121,6 @@ void omap3_dss_panel_config(const struct panel_config *panel_cfg)
if (!panel_cfg->frame_buffer)
return;
- writel(panel_cfg->load_mode << LOADMODE_SHIFT, &dispc->config);
writel(8 << GFX_FORMAT_SHIFT | GFX_ENABLE, &dispc->gfx_attributes);
writel(1, &dispc->gfx_row_inc);
writel(1, &dispc->gfx_pixel_inc);