diff options
author | Tom Rini <trini@ti.com> | 2012-09-21 14:53:13 -0700 |
---|---|---|
committer | Tom Rini <trini@ti.com> | 2012-09-21 14:53:13 -0700 |
commit | 495dbd72dd1172de866ba323263a5b62cf454972 (patch) | |
tree | 3ecfb8ae44c871055115941890fd93f175f8761d /drivers | |
parent | 50d924b45911b24eeb7623bed11b9297d99b840a (diff) | |
parent | d193c1b6eb05041c94ad9aacd8c94189d1dbc5f8 (diff) |
Merge branch 'master' of git://git.denx.de/u-boot-arm
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/tegra_gpio.c | 8 | ||||
-rw-r--r-- | drivers/i2c/tegra_i2c.c | 12 | ||||
-rw-r--r-- | drivers/input/Makefile | 2 | ||||
-rw-r--r-- | drivers/mmc/mxsmmc.c | 4 | ||||
-rw-r--r-- | drivers/mmc/tegra_mmc.c | 34 | ||||
-rw-r--r-- | drivers/mmc/tegra_mmc.h | 131 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/mxs_nand.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/tegra_nand.c | 1026 | ||||
-rw-r--r-- | drivers/mtd/nand/tegra_nand.h | 257 | ||||
-rw-r--r-- | drivers/spi/kirkwood_spi.c | 5 | ||||
-rw-r--r-- | drivers/spi/mxs_spi.c | 58 | ||||
-rw-r--r-- | drivers/spi/tegra_spi.c | 6 | ||||
-rw-r--r-- | drivers/video/omap3_dss.c | 3 |
15 files changed, 1359 insertions, 193 deletions
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 8cfcf8283b3..747f4cf9212 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/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index b4eb49127eb..e3be14e3cf3 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 68c6a16bcc2..0805e866787 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/mmc/mxsmmc.c b/drivers/mmc/mxsmmc.c index 9a98c6b85be..c80b41b1925 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/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index ddfa7279c22..ca8fad86572 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 b1f25641978..00000000000 --- 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 29dc20ef5e2..beb99cacb66 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/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c index bf9414fef1e..4701be846c6 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 390ff902127..71f5027889f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2934,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/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c new file mode 100644 index 00000000000..8c1de34455e --- /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(®->command) & CMD_GO) || + !(readl(®->status) & STATUS_RBSY0) || + !(readl(®->isr) & ISR_IS_CMD_DONE)) { + udelay(1); + continue; + } + reg_val = readl(®->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(®->isr); + writel(reg_val, ®->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(®->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(®->dec_status); + if ((reg_val & DEC_STATUS_A_ECC_FAIL) && databuf) { + reg_val = readl(®->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(®->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(®->command); + reg_val |= CMD_GO; + writel(reg_val, ®->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, ®->command); + + /* Stop DMA engine and clear DMA completion status */ + writel(DMA_MST_CTRL_GO_DISABLE + | DMA_MST_CTRL_IS_DMA_DONE, + ®->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, ®_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, ®_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, ®->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, ®->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 00000000000..7e74be75f81 --- /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/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c index f4523a39291..a7cda751bd0 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/mxs_spi.c b/drivers/spi/mxs_spi.c index 168dbe497e6..42e4c9952ed 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 2355e022b02..18b00b2cae9 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/video/omap3_dss.c b/drivers/video/omap3_dss.c index 6686718b0a7..b1424bfd038 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); |