summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorWolfgang Denk <wd@denx.de>2012-07-08 19:26:33 +0200
committerWolfgang Denk <wd@denx.de>2012-07-08 19:26:33 +0200
commit50cd93b25033764dcda9bb47aa68be778f94d36e (patch)
treeb8606a377b805952d533300dfa1e98e42951678e /drivers
parent8246ff864de38935ff34108856a37a2caf6cbefc (diff)
parentd702b0811df53a1fc2d8049e35431e4591d093c6 (diff)
downloadu-boot-imx-50cd93b25033764dcda9bb47aa68be778f94d36e.zip
u-boot-imx-50cd93b25033764dcda9bb47aa68be778f94d36e.tar.gz
u-boot-imx-50cd93b25033764dcda9bb47aa68be778f94d36e.tar.bz2
Merge branch 'master' of git://git.denx.de/u-boot-arm
* 'master' of git://git.denx.de/u-boot-arm: (212 commits) ARM: cache: Move the cp15 CR register read before flushing the cache. ARM: introduce arch_early_init_r() PXA: Enable CONFIG_PREBOOT on zipitz2 ARM: mx28: Remove CONFIG_ARCH_CPU_INIT No need to define CONFIG_ARCH_CPU_INIT. add new board vl_ma2sc MTD: SPEAr SMI: Add write support for length < 4 bytes i2c: designware_i2c.c: Add support for the "i2c probe" command rtc/m41t62: Add support for M41T82 with HT (Halt Update) SPL: ARM: spear: Add SPL support for SPEAr600 platform Makefile: Add u-boot.spr build target (SPEAr) SPL: ARM: spear: Remove some objects from SPL build SPL: lib/Makefile: Add crc32.c to SPL build SPL: common/Makefile: Add image.c to SPL build arm: Don't use printf() in SPL builds GPIO: Add SPEAr GPIO driver net: Multiple updates/enhancements to designware.c cleanup/SPEAr: Define configuration flags more elegantly cleanup/SPEAr: Remove unnecessary parenthesis SPEAr: Correct SoC ID offset in misc configuration space SPEAr: explicitly select clk src for UART SPEAr: Remove CONFIG_MTD_NAND_VERIFY_WRITE to speed up NAND access SPEAr: Enable ONFI nand flash detection for spear3xx and 6xx and evb SPEAr: Enable CONFIG_SYS_FLASH_EMPTY_INFO macro SPEAr: Correct the definition of CONFIG_SYS_MONITOR_BASE SPEAr: Enable CONFIG_SYS_FLASH_PROTECTION SPEAr: Enable dcache for fast file transfer SPEAr: Enable autoneg for ethernet SPEAr: Enable udc and usb-console support only for usbtty configuration SPEAr: Enable usb device high speed support SPEAr: Initialize SNOR in early_board_init_f SPEAr: Change the default environment variables SPEAr: Remove unused flag (CONFIG_SYS_HZ_CLOCK) SPEAr: Add configuration options for spear3xx and spear6xx boards SPEAr: Add basic arch related support for SPEAr SoCs SPEAr: Add interface information in initialization SPEAr: Add macb driver support for spear310 and spear320 SPEAr: Configure network support for spear SoCs SPEAr: Place ethaddr write and read within CONFIG_CMD_NET SPEAr: Eliminate dependency on Xloader table SPEAr: Fix ARM relocation support st_smi: Fixed page size for Winbond W25Q128FV flash st_smi: Change timeout loop implementation st_smi: Fix bug in flash_print_info() st_smi: Change the flash probing method st_smi: Removed no needed dependency on ST_M25Pxx_ID st_smi: Fix smi read status st_smi: Move status register read before modifying ctrl register st_smi: Read status until timeout happens st_smi: Enhance the error handling st_smi: Change SMI timeout values st_smi: Return error in case TFF is not set st_smi: Add support for SPEAr SMI driver mtd/NAND: Remove obsolete SPEAr specific NAND drivers SPEAr: Configure FSMC driver for NAND interface mtd/NAND: Add FSMC driver support arm/km: remove calls to kw_gpio_* in board_early_init_f arm/km: add implementation for read_dip_switch arm/km: support the 2 PCIe fpga resets arm/km: skip FPGA config when already configured arm/km: redefine piggy 4 reg names to avoid conflicts arm/km: cleanup km_kirkwood boards arm/km: enable BOCO2 FPGA download support arm/km: remove portl2.h and use km_kirkwood instead arm/km: convert mgcoge3un target to km_kirkwood arm/km: add kmcoge5un board support arm/km: add kmnusa board support arm: bugfix: save_boot_params_default accesses uninitalized stack when -O0 cm-t35: fix incorrect NAND_ECC layout selection ARM: OMAP4/5: Do not configure non essential pads, clocks, dplls. ARM: OMAP4/5: Move USB pads to essential list. ARM: OMAP4/5: Move USB clocks to essential group. ARM: OMAP4/5: Move gpmc clocks to essential group. ARM: OMAP4+: Move external phy initialisations to arch specific place. omap4: Use a smaller M,N couple for IVA DPLL da850/omap-l138: Enable auto negotiation in RMII mode omap: am33xx: accomodate input clocks other than 24 Mhz omap: emif: fix bug in manufacturer code test omap: emif: deal with rams that return duplicate mr data on all byte lanes OMAP4+: Force DDR in self-refresh after warm reset OMAP4+: Handle sdram init after warm reset ARM: OMAP3+: Detect reset type arm: bugfix: Move vector table before jumping relocated code Kirkwood: Add support for Ka-Ro TK71 arm/km: use spi claim bus to switch between SPI and NAND arm/kirkwood: protect the ENV_SPI #defines ARM: don't probe PHY address for LaCie boards lacie_kw: fix CONFIG_SYS_KWD_CONFIG for inetspace_v2 lacie_kw: fix SDRAM banks number for net2big_v2 Kirkwood: add lschlv2 and lsxhl board support net: add helper to generate random mac address net: use common rand()/srand() functions lib: add rand() function kwboot: boot kirkwood SoCs over a serial link kw_spi: add weak functions board_spi_claim/release_bus kw_spi: support spi_claim/release_bus functions kw_spi: backup and reset the MPP of the chosen CS pin kirkwood: fix calls to kirkwood_mpp_conf kirkwood: add save functionality kirkwood_mpp_conf function km_arm: use filesize for erase in update command arm/km: enable mii cmd arm/km: remove CONFIG_RESET_PHY_R arm/km: change maintainer for mgcoge3un arm/km: fix wrong comment in SDRAM config for mgcoge3un arm/km: use ARRAY_SIZE macro arm/km: rename CONFIG option CONFIG_KM_DEF_ENV_UPDATE arm/km: add piggy mac adress offset for mgcoge3un arm/km: add board type to boards.cfg AT91SAM9*: Change kernel address in dataflash to match u-boot's size ATMEL/PIO: Enable new feature of PIO on Atmel device ehci-atmel: fix compiler warning AT91: at91sam9m10g45ek : Enable EHCI instead OHCI Atmel : usb : add EHCI driver for Atmel SoC Fix: AT91SAM9263 nor flash usage Fix: broken boot message at serial line on AT91SAM9263-EK board i.MX6 USDHC: Use the ESDHC clock mx28evk: Fix boot by adjusting HW_DRAM_CTL29 register i.MX28: Add function to adjust memory parameters mx28evk: Fix PSWITCH key position mx53smd: Remove CONFIG_SYS_I2C_SLAVE definition mx53loco: Remove CONFIG_SYS_I2C_SLAVE definition mx53evk: Remove CONFIG_SYS_I2C_SLAVE definition mx53ard: Remove CONFIG_SYS_I2C_SLAVE definition mx35pdk: Remove CONFIG_SYS_I2C_SLAVE definition imx31_phycore: Remove CONFIG_SYS_I2C_SLAVE definition mx53ard: Remove unused CONFIG_MII_GASKET mx6: Avoid writing to read-only bits in imximage.cfg m28evk: use same notation to alloc the 128kB stack ... Signed-off-by: Wolfgang Denk <wd@denx.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Makefile3
-rw-r--r--drivers/gpio/at91_gpio.c125
-rw-r--r--drivers/gpio/spear_gpio.c102
-rw-r--r--drivers/gpio/tegra_gpio.c (renamed from drivers/gpio/tegra2_gpio.c)2
-rw-r--r--drivers/i2c/designware_i2c.c16
-rw-r--r--drivers/i2c/omap24xx_i2c.c46
-rw-r--r--drivers/mmc/Makefile2
-rw-r--r--drivers/mmc/tegra_mmc.c (renamed from drivers/mmc/tegra2_mmc.c)4
-rw-r--r--drivers/mmc/tegra_mmc.h (renamed from drivers/mmc/tegra2_mmc.h)8
-rw-r--r--drivers/mtd/Makefile2
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/fsmc_nand.c486
-rw-r--r--drivers/mtd/nand/spr_nand.c124
-rw-r--r--drivers/mtd/spi/winbond.c8
-rw-r--r--drivers/mtd/st_smi.c (renamed from drivers/mtd/spr_smi.c)255
-rw-r--r--drivers/net/davinci_emac.c8
-rw-r--r--drivers/net/designware.c126
-rw-r--r--drivers/net/designware.h2
-rw-r--r--drivers/rtc/m41t62.c10
-rw-r--r--drivers/spi/Makefile2
-rw-r--r--drivers/spi/kirkwood_spi.c64
-rw-r--r--drivers/spi/tegra_spi.c (renamed from drivers/spi/tegra2_spi.c)17
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-atmel.c89
-rw-r--r--drivers/video/exynos_fb.c3
25 files changed, 1168 insertions, 338 deletions
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fb3b09a..32a2474 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -35,7 +35,8 @@ COBJS-$(CONFIG_PCA953X) += pca953x.o
COBJS-$(CONFIG_PCA9698) += pca9698.o
COBJS-$(CONFIG_S5P) += s5p_gpio.o
COBJS-$(CONFIG_SANDBOX_GPIO) += sandbox.o
-COBJS-$(CONFIG_TEGRA2_GPIO) += tegra2_gpio.o
+COBJS-$(CONFIG_SPEAR_GPIO) += spear_gpio.o
+COBJS-$(CONFIG_TEGRA_GPIO) += tegra_gpio.o
COBJS-$(CONFIG_DA8XX_GPIO) += da8xx_gpio.o
COBJS-$(CONFIG_ALTERA_PIO) += altera_pio.o
COBJS-$(CONFIG_MPC83XX_GPIO) += mpc83xx_gpio.o
diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c
index be2a026..ac3b322 100644
--- a/drivers/gpio/at91_gpio.c
+++ b/drivers/gpio/at91_gpio.c
@@ -86,7 +86,14 @@ int at91_set_a_periph(unsigned port, unsigned pin, int use_pullup)
mask = 1 << pin;
writel(mask, &pio->port[port].idr);
at91_set_pio_pullup(port, pin, use_pullup);
+#if defined(CPU_HAS_PIO3)
+ writel(readl(&pio->port[port].abcdsr1) & ~mask,
+ &pio->port[port].abcdsr1);
+ writel(readl(&pio->port[port].abcdsr2) & ~mask,
+ &pio->port[port].abcdsr2);
+#else
writel(mask, &pio->port[port].asr);
+#endif
writel(mask, &pio->port[port].pdr);
}
return 0;
@@ -104,12 +111,63 @@ int at91_set_b_periph(unsigned port, unsigned pin, int use_pullup)
mask = 1 << pin;
writel(mask, &pio->port[port].idr);
at91_set_pio_pullup(port, pin, use_pullup);
+#if defined(CPU_HAS_PIO3)
+ writel(readl(&pio->port[port].abcdsr1) | mask,
+ &pio->port[port].abcdsr1);
+ writel(readl(&pio->port[port].abcdsr2) & ~mask,
+ &pio->port[port].abcdsr2);
+#else
writel(mask, &pio->port[port].bsr);
+#endif
writel(mask, &pio->port[port].pdr);
}
return 0;
}
+#if defined(CPU_HAS_PIO3)
+/*
+ * mux the pin to the "C" internal peripheral role.
+ */
+int at91_set_c_periph(unsigned port, unsigned pin, int use_pullup)
+{
+ at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA;
+ u32 mask;
+
+ if ((port < ATMEL_PIO_PORTS) && (pin < 32)) {
+ mask = 1 << pin;
+ writel(mask, &pio->port[port].idr);
+ at91_set_pio_pullup(port, pin, use_pullup);
+ writel(readl(&pio->port[port].abcdsr1) & ~mask,
+ &pio->port[port].abcdsr1);
+ writel(readl(&pio->port[port].abcdsr2) | mask,
+ &pio->port[port].abcdsr2);
+ writel(mask, &pio->port[port].pdr);
+ }
+ return 0;
+}
+
+/*
+ * mux the pin to the "D" internal peripheral role.
+ */
+int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup)
+{
+ at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA;
+ u32 mask;
+
+ if ((port < ATMEL_PIO_PORTS) && (pin < 32)) {
+ mask = 1 << pin;
+ writel(mask, &pio->port[port].idr);
+ at91_set_pio_pullup(port, pin, use_pullup);
+ writel(readl(&pio->port[port].abcdsr1) | mask,
+ &pio->port[port].abcdsr1);
+ writel(readl(&pio->port[port].abcdsr2) | mask,
+ &pio->port[port].abcdsr2);
+ writel(mask, &pio->port[port].pdr);
+ }
+ return 0;
+}
+#endif
+
/*
* mux the pin to the gpio controller (instead of "A" or "B" peripheral), and
* configure it for an input.
@@ -162,13 +220,76 @@ int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on)
if ((port < ATMEL_PIO_PORTS) && (pin < 32)) {
mask = 1 << pin;
- if (is_on)
+ if (is_on) {
+#if defined(CPU_HAS_PIO3)
+ writel(mask, &pio->port[port].ifscdr);
+#endif
writel(mask, &pio->port[port].ifer);
- else
+ } else {
writel(mask, &pio->port[port].ifdr);
+ }
+ }
+ return 0;
+}
+
+#if defined(CPU_HAS_PIO3)
+/*
+ * enable/disable the debounce filter.
+ */
+int at91_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div)
+{
+ at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA;
+ u32 mask;
+
+ if ((port < ATMEL_PIO_PORTS) && (pin < 32)) {
+ mask = 1 << pin;
+ if (is_on) {
+ writel(mask, &pio->port[port].ifscer);
+ writel(div & PIO_SCDR_DIV, &pio->port[port].scdr);
+ writel(mask, &pio->port[port].ifer);
+ } else {
+ writel(mask, &pio->port[port].ifdr);
+ }
+ }
+ return 0;
+}
+
+/*
+ * enable/disable the pull-down.
+ * If pull-up already enabled while calling the function, we disable it.
+ */
+int at91_set_pio_pulldown(unsigned port, unsigned pin, int is_on)
+{
+ at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA;
+ u32 mask;
+
+ if ((port < ATMEL_PIO_PORTS) && (pin < 32)) {
+ mask = 1 << pin;
+ writel(mask, &pio->port[port].pudr);
+ if (is_on)
+ writel(mask, &pio->port[port].ppder);
+ else
+ writel(mask, &pio->port[port].ppddr);
+ }
+ return 0;
+}
+
+/*
+ * disable Schmitt trigger
+ */
+int at91_set_pio_disable_schmitt_trig(unsigned port, unsigned pin)
+{
+ at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA;
+ u32 mask;
+
+ if ((port < ATMEL_PIO_PORTS) && (pin < 32)) {
+ mask = 1 << pin;
+ writel(readl(&pio->port[port].schmitt) | mask,
+ &pio->port[port].schmitt);
}
return 0;
}
+#endif
/*
* enable/disable the multi-driver. This is only valid for output and
diff --git a/drivers/gpio/spear_gpio.c b/drivers/gpio/spear_gpio.c
new file mode 100644
index 0000000..d3c728e
--- /dev/null
+++ b/drivers/gpio/spear_gpio.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2012 Stefan Roese <sr@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Driver for SPEAr600 GPIO controller
+ */
+
+#include <common.h>
+#include <asm/arch/hardware.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <errno.h>
+
+static int gpio_direction(unsigned gpio,
+ enum gpio_direction direction)
+{
+ struct gpio_regs *regs = (struct gpio_regs *)CONFIG_GPIO_BASE;
+ u32 val;
+
+ val = readl(&regs->gpiodir);
+
+ if (direction == GPIO_DIRECTION_OUT)
+ val |= 1 << gpio;
+ else
+ val &= ~(1 << gpio);
+
+ writel(val, &regs->gpiodir);
+
+ return 0;
+}
+
+int gpio_set_value(unsigned gpio, int value)
+{
+ struct gpio_regs *regs = (struct gpio_regs *)CONFIG_GPIO_BASE;
+
+ writel(1 << gpio, &regs->gpiodata[DATA_REG_ADDR(gpio)]);
+
+ return 0;
+}
+
+int gpio_get_value(unsigned gpio)
+{
+ struct gpio_regs *regs = (struct gpio_regs *)CONFIG_GPIO_BASE;
+ u32 val;
+
+ val = readl(&regs->gpiodata[DATA_REG_ADDR(gpio)]);
+
+ return !!val;
+}
+
+int gpio_request(unsigned gpio, const char *label)
+{
+ if (gpio >= SPEAR_GPIO_COUNT)
+ return -EINVAL;
+
+ return 0;
+}
+
+int gpio_free(unsigned gpio)
+{
+ return 0;
+}
+
+void gpio_toggle_value(unsigned gpio)
+{
+ gpio_set_value(gpio, !gpio_get_value(gpio));
+}
+
+int gpio_direction_input(unsigned gpio)
+{
+ return gpio_direction(gpio, GPIO_DIRECTION_IN);
+}
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ int ret = gpio_direction(gpio, GPIO_DIRECTION_OUT);
+
+ if (ret < 0)
+ return ret;
+
+ gpio_set_value(gpio, value);
+ return 0;
+}
diff --git a/drivers/gpio/tegra2_gpio.c b/drivers/gpio/tegra_gpio.c
index 70ca46f..60ec6e3 100644
--- a/drivers/gpio/tegra2_gpio.c
+++ b/drivers/gpio/tegra_gpio.c
@@ -1,6 +1,6 @@
/*
* NVIDIA Tegra2 GPIO handling.
- * (C) Copyright 2010,2011
+ * (C) Copyright 2010-2012
* NVIDIA Corporation <www.nvidia.com>
*
* See file CREDITS for list of people who contributed to this
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index 6d118ac..bf64a2a 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -90,7 +90,7 @@ static void set_speed(int i2c_spd)
*
* Set the i2c speed.
*/
-void i2c_set_bus_speed(int speed)
+int i2c_set_bus_speed(int speed)
{
if (speed >= I2C_MAX_SPEED)
set_speed(IC_SPEED_MODE_MAX);
@@ -98,6 +98,8 @@ void i2c_set_bus_speed(int speed)
set_speed(IC_SPEED_MODE_FAST);
else
set_speed(IC_SPEED_MODE_STANDARD);
+
+ return 0;
}
/*
@@ -215,10 +217,8 @@ static int check_params(uint addr, int alen, uchar *buffer, int len)
static int i2c_xfer_init(uchar chip, uint addr)
{
- if (i2c_wait_for_bb()) {
- printf("Timed out waiting for bus\n");
+ if (i2c_wait_for_bb())
return 1;
- }
i2c_setaddress(chip);
writel(addr, &i2c_regs_p->ic_cmd_data);
@@ -282,7 +282,6 @@ int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
start_time_rx = get_timer(0);
} else if (get_timer(start_time_rx) > I2C_BYTE_TO) {
- printf("Timed out. i2c read Failed\n");
return 1;
}
}
@@ -334,9 +333,14 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
int i2c_probe(uchar chip)
{
u32 tmp;
+ int ret;
/*
* Try to read the first location of the chip.
*/
- return i2c_read(chip, 0, 1, (uchar *)&tmp, 1);
+ ret = i2c_read(chip, 0, 1, (uchar *)&tmp, 1);
+ if (ret)
+ i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
+
+ return ret;
}
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index a7ffd95..81193b0 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -202,7 +202,7 @@ static int i2c_read_byte(u8 devaddr, u8 regoffset, u8 *value)
}
if (status & I2C_STAT_RRDY) {
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
- defined(CONFIG_OMAP44XX)
+ defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
*value = readb(&i2c_base->data);
#else
*value = readw(&i2c_base->data);
@@ -232,7 +232,7 @@ static void flush_fifo(void)
stat = readw(&i2c_base->stat);
if (stat == I2C_STAT_RRDY) {
#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
- defined(CONFIG_OMAP44XX)
+ defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
readb(&i2c_base->data);
#else
readw(&i2c_base->data);
@@ -255,23 +255,43 @@ int i2c_probe(uchar chip)
/* wait until bus not busy */
wait_for_bb();
- /* try to write one byte */
+ /* try to read one byte */
writew(1, &i2c_base->cnt);
/* set slave address */
writew(chip, &i2c_base->sa);
/* stop bit needed here */
- writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
- I2C_CON_STP, &i2c_base->con);
-
- status = wait_for_pin();
+ writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con);
- /* check for ACK (!NAK) */
- if (!(status & I2C_STAT_NACK))
- res = 0;
-
- /* abort transfer (force idle state) */
- writew(0, &i2c_base->con);
+ while (1) {
+ status = wait_for_pin();
+ if (status == 0 || status & I2C_STAT_AL) {
+ res = 1;
+ goto probe_exit;
+ }
+ if (status & I2C_STAT_NACK) {
+ res = 1;
+ writew(0xff, &i2c_base->stat);
+ writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con);
+ wait_for_bb ();
+ break;
+ }
+ if (status & I2C_STAT_ARDY) {
+ writew(I2C_STAT_ARDY, &i2c_base->stat);
+ break;
+ }
+ if (status & I2C_STAT_RRDY) {
+ res = 0;
+#if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \
+ defined(CONFIG_OMAP44XX) || defined(CONFIG_AM33XX)
+ readb(&i2c_base->data);
+#else
+ readw(&i2c_base->data);
+#endif
+ writew(I2C_STAT_RRDY, &i2c_base->stat);
+ }
+ }
+probe_exit:
flush_fifo();
/* don't allow any more data in... we don't want it. */
writew(0, &i2c_base->cnt);
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index a8e681c..c567737 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -42,7 +42,7 @@ COBJS-$(CONFIG_PXA_MMC_GENERIC) += pxa_mmc_gen.o
COBJS-$(CONFIG_SDHCI) += sdhci.o
COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o
-COBJS-$(CONFIG_TEGRA2_MMC) += tegra2_mmc.o
+COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/mmc/tegra2_mmc.c b/drivers/mmc/tegra_mmc.c
index fb8a57d..29bf583 100644
--- a/drivers/mmc/tegra2_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -2,7 +2,7 @@
* (C) Copyright 2009 SAMSUNG Electronics
* Minkyu Kang <mk7.kang@samsung.com>
* Jaehoon Chung <jh80.chung@samsung.com>
- * Portions Copyright 2011 NVIDIA Corporation
+ * Portions Copyright 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
@@ -25,7 +25,7 @@
#include <asm/io.h>
#include <asm/arch/clk_rst.h>
#include <asm/arch/clock.h>
-#include "tegra2_mmc.h"
+#include "tegra_mmc.h"
/* support 4 mmc hosts */
struct mmc mmc_dev[4];
diff --git a/drivers/mmc/tegra2_mmc.h b/drivers/mmc/tegra_mmc.h
index 67c00db..f9cdcaa 100644
--- a/drivers/mmc/tegra2_mmc.h
+++ b/drivers/mmc/tegra_mmc.h
@@ -1,7 +1,7 @@
/*
* (C) Copyright 2009 SAMSUNG Electronics
* Minkyu Kang <mk7.kang@samsung.com>
- * Portions Copyright (C) 2011 NVIDIA Corporation
+ * 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
@@ -19,8 +19,8 @@
*
*/
-#ifndef __TEGRA2_MMC_H_
-#define __TEGRA2_MMC_H_
+#ifndef __TEGRA_MMC_H_
+#define __TEGRA_MMC_H_
#define TEGRA2_SDMMC1_BASE 0xC8000000
#define TEGRA2_SDMMC2_BASE 0xC8000200
@@ -128,4 +128,4 @@ struct mmc_host {
};
#endif /* __ASSEMBLY__ */
-#endif /* __TEGRA2_MMC_H_ */
+#endif /* __TEGRA_MMC_H_ */
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 5a5ecdf..543c845 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -35,7 +35,7 @@ COBJS-$(CONFIG_HAS_DATAFLASH) += dataflash.o
COBJS-$(CONFIG_FTSMC020) += ftsmc020.o
COBJS-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o
COBJS-$(CONFIG_MW_EEPROM) += mw_eeprom.o
-COBJS-$(CONFIG_SPEARSMI) += spr_smi.o
+COBJS-$(CONFIG_ST_SMI) += st_smi.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 1d1b628..29dc20e 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -49,6 +49,7 @@ COBJS-$(CONFIG_NAND_DAVINCI) += davinci_nand.o
COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
+COBJS-$(CONFIG_NAND_FSMC) += fsmc_nand.o
COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c
new file mode 100644
index 0000000..7a61d88
--- /dev/null
+++ b/drivers/mtd/nand/fsmc_nand.c
@@ -0,0 +1,486 @@
+/*
+ * (C) Copyright 2010
+ * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com.
+ *
+ * (C) Copyright 2012
+ * Amit Virdi, ST Microelectronics, amit.virdi@st.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 <nand.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/fsmc_nand.h>
+#include <asm/arch/hardware.h>
+
+static u32 fsmc_version;
+static struct fsmc_regs *const fsmc_regs_p = (struct fsmc_regs *)
+ CONFIG_SYS_FSMC_BASE;
+
+/*
+ * ECC4 and ECC1 have 13 bytes and 3 bytes of ecc respectively for 512 bytes of
+ * data. ECC4 can correct up to 8 bits in 512 bytes of data while ECC1 can
+ * correct 1 bit in 512 bytes
+ */
+
+static struct nand_ecclayout fsmc_ecc4_lp_layout = {
+ .eccbytes = 104,
+ .eccpos = { 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14,
+ 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30,
+ 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46,
+ 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62,
+ 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78,
+ 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94,
+ 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110,
+ 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126
+ },
+ .oobfree = {
+ {.offset = 15, .length = 3},
+ {.offset = 31, .length = 3},
+ {.offset = 47, .length = 3},
+ {.offset = 63, .length = 3},
+ {.offset = 79, .length = 3},
+ {.offset = 95, .length = 3},
+ {.offset = 111, .length = 3},
+ {.offset = 127, .length = 1}
+ }
+};
+
+/*
+ * ECC4 layout for NAND of pagesize 4096 bytes & OOBsize 224 bytes. 13*8 bytes
+ * of OOB size is reserved for ECC, Byte no. 0 & 1 reserved for bad block & 118
+ * bytes are free for use.
+ */
+static struct nand_ecclayout fsmc_ecc4_224_layout = {
+ .eccbytes = 104,
+ .eccpos = { 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14,
+ 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30,
+ 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46,
+ 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62,
+ 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78,
+ 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94,
+ 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110,
+ 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126
+ },
+ .oobfree = {
+ {.offset = 15, .length = 3},
+ {.offset = 31, .length = 3},
+ {.offset = 47, .length = 3},
+ {.offset = 63, .length = 3},
+ {.offset = 79, .length = 3},
+ {.offset = 95, .length = 3},
+ {.offset = 111, .length = 3},
+ {.offset = 127, .length = 97}
+ }
+};
+
+/*
+ * ECC placement definitions in oobfree type format
+ * There are 13 bytes of ecc for every 512 byte block and it has to be read
+ * consecutively and immediately after the 512 byte data block for hardware to
+ * generate the error bit offsets in 512 byte data
+ * Managing the ecc bytes in the following way makes it easier for software to
+ * read ecc bytes consecutive to data bytes. This way is similar to
+ * oobfree structure maintained already in u-boot nand driver
+ */
+static struct fsmc_eccplace fsmc_eccpl_lp = {
+ .eccplace = {
+ {.offset = 2, .length = 13},
+ {.offset = 18, .length = 13},
+ {.offset = 34, .length = 13},
+ {.offset = 50, .length = 13},
+ {.offset = 66, .length = 13},
+ {.offset = 82, .length = 13},
+ {.offset = 98, .length = 13},
+ {.offset = 114, .length = 13}
+ }
+};
+
+static struct nand_ecclayout fsmc_ecc4_sp_layout = {
+ .eccbytes = 13,
+ .eccpos = { 0, 1, 2, 3, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14
+ },
+ .oobfree = {
+ {.offset = 15, .length = 1},
+ }
+};
+
+static struct fsmc_eccplace fsmc_eccpl_sp = {
+ .eccplace = {
+ {.offset = 0, .length = 4},
+ {.offset = 6, .length = 9}
+ }
+};
+
+static struct nand_ecclayout fsmc_ecc1_layout = {
+ .eccbytes = 24,
+ .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52,
+ 66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116},
+ .oobfree = {
+ {.offset = 8, .length = 8},
+ {.offset = 24, .length = 8},
+ {.offset = 40, .length = 8},
+ {.offset = 56, .length = 8},
+ {.offset = 72, .length = 8},
+ {.offset = 88, .length = 8},
+ {.offset = 104, .length = 8},
+ {.offset = 120, .length = 8}
+ }
+};
+
+/* Count the number of 0's in buff upto a max of max_bits */
+static int count_written_bits(uint8_t *buff, int size, int max_bits)
+{
+ int k, written_bits = 0;
+
+ for (k = 0; k < size; k++) {
+ written_bits += hweight8(~buff[k]);
+ if (written_bits > max_bits)
+ break;
+ }
+
+ return written_bits;
+}
+
+static void fsmc_nand_hwcontrol(struct mtd_info *mtd, int cmd, uint ctrl)
+{
+ struct nand_chip *this = mtd->priv;
+ ulong IO_ADDR_W;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ IO_ADDR_W = (ulong)this->IO_ADDR_W;
+
+ IO_ADDR_W &= ~(CONFIG_SYS_NAND_CLE | CONFIG_SYS_NAND_ALE);
+ if (ctrl & NAND_CLE)
+ IO_ADDR_W |= CONFIG_SYS_NAND_CLE;
+ if (ctrl & NAND_ALE)
+ IO_ADDR_W |= CONFIG_SYS_NAND_ALE;
+
+ if (ctrl & NAND_NCE) {
+ writel(readl(&fsmc_regs_p->pc) |
+ FSMC_ENABLE, &fsmc_regs_p->pc);
+ } else {
+ writel(readl(&fsmc_regs_p->pc) &
+ ~FSMC_ENABLE, &fsmc_regs_p->pc);
+ }
+ this->IO_ADDR_W = (void *)IO_ADDR_W;
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, this->IO_ADDR_W);
+}
+
+static int fsmc_bch8_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
+{
+ /* The calculated ecc is actually the correction index in data */
+ u32 err_idx[8];
+ u32 num_err, i;
+ u32 ecc1, ecc2, ecc3, ecc4;
+
+ num_err = (readl(&fsmc_regs_p->sts) >> 10) & 0xF;
+
+ if (likely(num_err == 0))
+ return 0;
+
+ if (unlikely(num_err > 8)) {
+ /*
+ * This is a temporary erase check. A newly erased page read
+ * would result in an ecc error because the oob data is also
+ * erased to FF and the calculated ecc for an FF data is not
+ * FF..FF.
+ * This is a workaround to skip performing correction in case
+ * data is FF..FF
+ *
+ * Logic:
+ * For every page, each bit written as 0 is counted until these
+ * number of bits are greater than 8 (the maximum correction
+ * capability of FSMC for each 512 + 13 bytes)
+ */
+
+ int bits_ecc = count_written_bits(read_ecc, 13, 8);
+ int bits_data = count_written_bits(dat, 512, 8);
+
+ if ((bits_ecc + bits_data) <= 8) {
+ if (bits_data)
+ memset(dat, 0xff, 512);
+ return bits_data + bits_ecc;
+ }
+
+ return -EBADMSG;
+ }
+
+ ecc1 = readl(&fsmc_regs_p->ecc1);
+ ecc2 = readl(&fsmc_regs_p->ecc2);
+ ecc3 = readl(&fsmc_regs_p->ecc3);
+ ecc4 = readl(&fsmc_regs_p->sts);
+
+ err_idx[0] = (ecc1 >> 0) & 0x1FFF;
+ err_idx[1] = (ecc1 >> 13) & 0x1FFF;
+ err_idx[2] = (((ecc2 >> 0) & 0x7F) << 6) | ((ecc1 >> 26) & 0x3F);
+ err_idx[3] = (ecc2 >> 7) & 0x1FFF;
+ err_idx[4] = (((ecc3 >> 0) & 0x1) << 12) | ((ecc2 >> 20) & 0xFFF);
+ err_idx[5] = (ecc3 >> 1) & 0x1FFF;
+ err_idx[6] = (ecc3 >> 14) & 0x1FFF;
+ err_idx[7] = (((ecc4 >> 16) & 0xFF) << 5) | ((ecc3 >> 27) & 0x1F);
+
+ i = 0;
+ while (i < num_err) {
+ err_idx[i] ^= 3;
+
+ if (err_idx[i] < 512 * 8)
+ __change_bit(err_idx[i], dat);
+
+ i++;
+ }
+
+ return num_err;
+}
+
+static int fsmc_read_hwecc(struct mtd_info *mtd,
+ const u_char *data, u_char *ecc)
+{
+ u_int ecc_tmp;
+ int timeout = CONFIG_SYS_HZ;
+ ulong start;
+
+ switch (fsmc_version) {
+ case FSMC_VER8:
+ start = get_timer(0);
+ while (get_timer(start) < timeout) {
+ /*
+ * Busy waiting for ecc computation
+ * to finish for 512 bytes
+ */
+ if (readl(&fsmc_regs_p->sts) & FSMC_CODE_RDY)
+ break;
+ }
+
+ ecc_tmp = readl(&fsmc_regs_p->ecc1);
+ ecc[0] = (u_char) (ecc_tmp >> 0);
+ ecc[1] = (u_char) (ecc_tmp >> 8);
+ ecc[2] = (u_char) (ecc_tmp >> 16);
+ ecc[3] = (u_char) (ecc_tmp >> 24);
+
+ ecc_tmp = readl(&fsmc_regs_p->ecc2);
+ ecc[4] = (u_char) (ecc_tmp >> 0);
+ ecc[5] = (u_char) (ecc_tmp >> 8);
+ ecc[6] = (u_char) (ecc_tmp >> 16);
+ ecc[7] = (u_char) (ecc_tmp >> 24);
+
+ ecc_tmp = readl(&fsmc_regs_p->ecc3);
+ ecc[8] = (u_char) (ecc_tmp >> 0);
+ ecc[9] = (u_char) (ecc_tmp >> 8);
+ ecc[10] = (u_char) (ecc_tmp >> 16);
+ ecc[11] = (u_char) (ecc_tmp >> 24);
+
+ ecc_tmp = readl(&fsmc_regs_p->sts);
+ ecc[12] = (u_char) (ecc_tmp >> 16);
+ break;
+
+ default:
+ ecc_tmp = readl(&fsmc_regs_p->ecc1);
+ ecc[0] = (u_char) (ecc_tmp >> 0);
+ ecc[1] = (u_char) (ecc_tmp >> 8);
+ ecc[2] = (u_char) (ecc_tmp >> 16);
+ break;
+ }
+
+ return 0;
+}
+
+void fsmc_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ writel(readl(&fsmc_regs_p->pc) & ~FSMC_ECCPLEN_256,
+ &fsmc_regs_p->pc);
+ writel(readl(&fsmc_regs_p->pc) & ~FSMC_ECCEN,
+ &fsmc_regs_p->pc);
+ writel(readl(&fsmc_regs_p->pc) | FSMC_ECCEN,
+ &fsmc_regs_p->pc);
+}
+
+/*
+ * fsmc_read_page_hwecc
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ * @page: page number to read
+ *
+ * This routine is needed for fsmc verison 8 as reading from NAND chip has to be
+ * performed in a strict sequence as follows:
+ * data(512 byte) -> ecc(13 byte)
+ * After this read, fsmc hardware generates and reports error data bits(upto a
+ * max of 8 bits)
+ */
+static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf, int page)
+{
+ struct fsmc_eccplace *fsmc_eccpl;
+ int i, j, s, stat, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ int off, len, group = 0;
+ uint8_t oob[13] __attribute__ ((aligned (2)));
+
+ /* Differentiate between small and large page ecc place definitions */
+ if (mtd->writesize == 512)
+ fsmc_eccpl = &fsmc_eccpl_sp;
+ else
+ fsmc_eccpl = &fsmc_eccpl_lp;
+
+ for (i = 0, s = 0; s < eccsteps; s++, i += eccbytes, p += eccsize) {
+
+ chip->cmdfunc(mtd, NAND_CMD_READ0, s * eccsize, page);
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+
+ for (j = 0; j < eccbytes;) {
+ off = fsmc_eccpl->eccplace[group].offset;
+ len = fsmc_eccpl->eccplace[group].length;
+ group++;
+
+ /*
+ * length is intentionally kept a higher multiple of 2
+ * to read at least 13 bytes even in case of 16 bit NAND
+ * devices
+ */
+ if (chip->options & NAND_BUSWIDTH_16)
+ len = roundup(len, 2);
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, off, page);
+ chip->read_buf(mtd, oob + j, len);
+ j += len;
+ }
+
+ memcpy(&ecc_code[i], oob, 13);
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i],
+ &ecc_calc[i]);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+
+ return 0;
+}
+
+int fsmc_nand_init(struct nand_chip *nand)
+{
+ static int chip_nr;
+ struct mtd_info *mtd;
+ int i;
+ u32 peripid2 = readl(&fsmc_regs_p->peripid2);
+
+ fsmc_version = (peripid2 >> FSMC_REVISION_SHFT) &
+ FSMC_REVISION_MSK;
+
+ writel(readl(&fsmc_regs_p->ctrl) | FSMC_WP, &fsmc_regs_p->ctrl);
+
+#if defined(CONFIG_SYS_FSMC_NAND_16BIT)
+ writel(FSMC_DEVWID_16 | FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON,
+ &fsmc_regs_p->pc);
+#elif defined(CONFIG_SYS_FSMC_NAND_8BIT)
+ writel(FSMC_DEVWID_8 | FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON,
+ &fsmc_regs_p->pc);
+#else
+#error Please define CONFIG_SYS_FSMC_NAND_16BIT or CONFIG_SYS_FSMC_NAND_8BIT
+#endif
+ writel(readl(&fsmc_regs_p->pc) | FSMC_TCLR_1 | FSMC_TAR_1,
+ &fsmc_regs_p->pc);
+ writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0,
+ &fsmc_regs_p->comm);
+ writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0,
+ &fsmc_regs_p->attrib);
+
+ nand->options = 0;
+#if defined(CONFIG_SYS_FSMC_NAND_16BIT)
+ nand->options |= NAND_BUSWIDTH_16;
+#endif
+ nand->ecc.mode = NAND_ECC_HW;
+ nand->ecc.size = 512;
+ nand->ecc.calculate = fsmc_read_hwecc;
+ nand->ecc.hwctl = fsmc_enable_hwecc;
+ nand->cmd_ctrl = fsmc_nand_hwcontrol;
+ nand->IO_ADDR_R = nand->IO_ADDR_W =
+ (void __iomem *)CONFIG_SYS_NAND_BASE;
+ nand->badblockbits = 7;
+
+ mtd = &nand_info[chip_nr++];
+ mtd->priv = nand;
+
+ switch (fsmc_version) {
+ case FSMC_VER8:
+ nand->ecc.bytes = 13;
+ nand->ecc.correct = fsmc_bch8_correct_data;
+ nand->ecc.read_page = fsmc_read_page_hwecc;
+ if (mtd->writesize == 512)
+ nand->ecc.layout = &fsmc_ecc4_sp_layout;
+ else {
+ if (mtd->oobsize == 224)
+ nand->ecc.layout = &fsmc_ecc4_224_layout;
+ else
+ nand->ecc.layout = &fsmc_ecc4_lp_layout;
+ }
+
+ break;
+ default:
+ nand->ecc.bytes = 3;
+ nand->ecc.layout = &fsmc_ecc1_layout;
+ nand->ecc.correct = nand_correct_data;
+ break;
+ }
+
+ /* Detect NAND chips */
+ if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL))
+ return -ENXIO;
+
+ if (nand_scan_tail(mtd))
+ return -ENXIO;
+
+ for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
+ if (nand_register(i))
+ return -ENXIO;
+
+ return 0;
+}
diff --git a/drivers/mtd/nand/spr_nand.c b/drivers/mtd/nand/spr_nand.c
deleted file mode 100644
index 097d0c6..0000000
--- a/drivers/mtd/nand/spr_nand.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * (C) Copyright 2009
- * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.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 <nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <asm/io.h>
-#include <asm/arch/hardware.h>
-#include <asm/arch/spr_nand.h>
-
-static struct fsmc_regs *const fsmc_regs_p =
- (struct fsmc_regs *)CONFIG_SPEAR_FSMCBASE;
-
-static struct nand_ecclayout spear_nand_ecclayout = {
- .eccbytes = 24,
- .eccpos = {2, 3, 4, 18, 19, 20, 34, 35, 36, 50, 51, 52,
- 66, 67, 68, 82, 83, 84, 98, 99, 100, 114, 115, 116},
- .oobfree = {
- {.offset = 8, .length = 8},
- {.offset = 24, .length = 8},
- {.offset = 40, .length = 8},
- {.offset = 56, .length = 8},
- {.offset = 72, .length = 8},
- {.offset = 88, .length = 8},
- {.offset = 104, .length = 8},
- {.offset = 120, .length = 8}
- }
-};
-
-static void spear_nand_hwcontrol(struct mtd_info *mtd, int cmd, uint ctrl)
-{
- struct nand_chip *this = mtd->priv;
- ulong IO_ADDR_W;
-
- if (ctrl & NAND_CTRL_CHANGE) {
- IO_ADDR_W = (ulong)this->IO_ADDR_W;
-
- IO_ADDR_W &= ~(CONFIG_SYS_NAND_CLE | CONFIG_SYS_NAND_ALE);
- if (ctrl & NAND_CLE)
- IO_ADDR_W |= CONFIG_SYS_NAND_CLE;
- if (ctrl & NAND_ALE)
- IO_ADDR_W |= CONFIG_SYS_NAND_ALE;
-
- if (ctrl & NAND_NCE) {
- writel(readl(&fsmc_regs_p->genmemctrl_pc) |
- FSMC_ENABLE, &fsmc_regs_p->genmemctrl_pc);
- } else {
- writel(readl(&fsmc_regs_p->genmemctrl_pc) &
- ~FSMC_ENABLE, &fsmc_regs_p->genmemctrl_pc);
- }
- this->IO_ADDR_W = (void *)IO_ADDR_W;
- }
-
- if (cmd != NAND_CMD_NONE)
- writeb(cmd, this->IO_ADDR_W);
-}
-
-static int spear_read_hwecc(struct mtd_info *mtd,
- const u_char *data, u_char ecc[3])
-{
- u_int ecc_tmp;
-
- /* read the h/w ECC */
- ecc_tmp = readl(&fsmc_regs_p->genmemctrl_ecc);
-
- ecc[0] = (u_char) (ecc_tmp & 0xFF);
- ecc[1] = (u_char) ((ecc_tmp & 0xFF00) >> 8);
- ecc[2] = (u_char) ((ecc_tmp & 0xFF0000) >> 16);
-
- return 0;
-}
-
-void spear_enable_hwecc(struct mtd_info *mtd, int mode)
-{
- writel(readl(&fsmc_regs_p->genmemctrl_pc) & ~0x80,
- &fsmc_regs_p->genmemctrl_pc);
- writel(readl(&fsmc_regs_p->genmemctrl_pc) & ~FSMC_ECCEN,
- &fsmc_regs_p->genmemctrl_pc);
- writel(readl(&fsmc_regs_p->genmemctrl_pc) | FSMC_ECCEN,
- &fsmc_regs_p->genmemctrl_pc);
-}
-
-int spear_nand_init(struct nand_chip *nand)
-{
- writel(FSMC_DEVWID_8 | FSMC_DEVTYPE_NAND | FSMC_ENABLE | FSMC_WAITON,
- &fsmc_regs_p->genmemctrl_pc);
- writel(readl(&fsmc_regs_p->genmemctrl_pc) | FSMC_TCLR_1 | FSMC_TAR_1,
- &fsmc_regs_p->genmemctrl_pc);
- writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0,
- &fsmc_regs_p->genmemctrl_comm);
- writel(FSMC_THIZ_1 | FSMC_THOLD_4 | FSMC_TWAIT_6 | FSMC_TSET_0,
- &fsmc_regs_p->genmemctrl_attrib);
-
- nand->options = 0;
- nand->ecc.mode = NAND_ECC_HW;
- nand->ecc.layout = &spear_nand_ecclayout;
- nand->ecc.size = 512;
- nand->ecc.bytes = 3;
- nand->ecc.calculate = spear_read_hwecc;
- nand->ecc.hwctl = spear_enable_hwecc;
- nand->ecc.correct = nand_correct_data;
- nand->cmd_ctrl = spear_nand_hwcontrol;
- return 0;
-}
diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c
index a6a6653..c20faa2 100644
--- a/drivers/mtd/spi/winbond.c
+++ b/drivers/mtd/spi/winbond.c
@@ -68,6 +68,14 @@ static const struct winbond_spi_flash_params winbond_spi_flash_table[] = {
.name = "W25X64",
},
{
+ .id = 0x4014,
+ .l2_page_size = 8,
+ .pages_per_sector = 16,
+ .sectors_per_block = 16,
+ .nr_blocks = 16,
+ .name = "W25Q80BL",
+ },
+ {
.id = 0x4015,
.l2_page_size = 8,
.pages_per_sector = 16,
diff --git a/drivers/mtd/spr_smi.c b/drivers/mtd/st_smi.c
index 6d4257a..7507e5d 100644
--- a/drivers/mtd/spr_smi.c
+++ b/drivers/mtd/st_smi.c
@@ -1,6 +1,6 @@
/*
* (C) Copyright 2009
- * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com.
*
* See file CREDITS for list of people who contributed to this
* project.
@@ -24,10 +24,10 @@
#include <common.h>
#include <flash.h>
#include <linux/err.h>
+#include <linux/mtd/st_smi.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
-#include <asm/arch/spr_smi.h>
#if !defined(CONFIG_SYS_NO_FLASH)
@@ -37,19 +37,61 @@ static ulong bank_base[CONFIG_SYS_MAX_FLASH_BANKS] =
CONFIG_SYS_FLASH_ADDR_BASE;
flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
-#define ST_M25Pxx_ID 0x00002020
-
-static struct flash_dev flash_ids[] = {
- {0x10, 0x10000, 2}, /* 64K Byte */
- {0x11, 0x20000, 4}, /* 128K Byte */
- {0x12, 0x40000, 4}, /* 256K Byte */
- {0x13, 0x80000, 8}, /* 512K Byte */
- {0x14, 0x100000, 16}, /* 1M Byte */
- {0x15, 0x200000, 32}, /* 2M Byte */
- {0x16, 0x400000, 64}, /* 4M Byte */
- {0x17, 0x800000, 128}, /* 8M Byte */
- {0x18, 0x1000000, 64}, /* 16M Byte */
- {0x00,}
+/* data structure to maintain flash ids from different vendors */
+struct flash_device {
+ char *name;
+ u8 erase_cmd;
+ u32 device_id;
+ u32 pagesize;
+ unsigned long sectorsize;
+ unsigned long size_in_bytes;
+};
+
+#define FLASH_ID(n, es, id, psize, ssize, size) \
+{ \
+ .name = n, \
+ .erase_cmd = es, \
+ .device_id = id, \
+ .pagesize = psize, \
+ .sectorsize = ssize, \
+ .size_in_bytes = size \
+}
+
+/*
+ * List of supported flash devices.
+ * Currently the erase_cmd field is not used in this driver.
+ */
+static struct flash_device flash_devices[] = {
+ FLASH_ID("st m25p16" , 0xd8, 0x00152020, 0x100, 0x10000, 0x200000),
+ FLASH_ID("st m25p32" , 0xd8, 0x00162020, 0x100, 0x10000, 0x400000),
+ FLASH_ID("st m25p64" , 0xd8, 0x00172020, 0x100, 0x10000, 0x800000),
+ FLASH_ID("st m25p128" , 0xd8, 0x00182020, 0x100, 0x40000, 0x1000000),
+ FLASH_ID("st m25p05" , 0xd8, 0x00102020, 0x80 , 0x8000 , 0x10000),
+ FLASH_ID("st m25p10" , 0xd8, 0x00112020, 0x80 , 0x8000 , 0x20000),
+ FLASH_ID("st m25p20" , 0xd8, 0x00122020, 0x100, 0x10000, 0x40000),
+ FLASH_ID("st m25p40" , 0xd8, 0x00132020, 0x100, 0x10000, 0x80000),
+ FLASH_ID("st m25p80" , 0xd8, 0x00142020, 0x100, 0x10000, 0x100000),
+ FLASH_ID("st m45pe10" , 0xd8, 0x00114020, 0x100, 0x10000, 0x20000),
+ FLASH_ID("st m45pe20" , 0xd8, 0x00124020, 0x100, 0x10000, 0x40000),
+ FLASH_ID("st m45pe40" , 0xd8, 0x00134020, 0x100, 0x10000, 0x80000),
+ FLASH_ID("st m45pe80" , 0xd8, 0x00144020, 0x100, 0x10000, 0x100000),
+ FLASH_ID("sp s25fl004" , 0xd8, 0x00120201, 0x100, 0x10000, 0x80000),
+ FLASH_ID("sp s25fl008" , 0xd8, 0x00130201, 0x100, 0x10000, 0x100000),
+ FLASH_ID("sp s25fl016" , 0xd8, 0x00140201, 0x100, 0x10000, 0x200000),
+ FLASH_ID("sp s25fl032" , 0xd8, 0x00150201, 0x100, 0x10000, 0x400000),
+ FLASH_ID("sp s25fl064" , 0xd8, 0x00160201, 0x100, 0x10000, 0x800000),
+ FLASH_ID("mac 25l512" , 0xd8, 0x001020C2, 0x010, 0x10000, 0x10000),
+ FLASH_ID("mac 25l1005" , 0xd8, 0x001120C2, 0x010, 0x10000, 0x20000),
+ FLASH_ID("mac 25l2005" , 0xd8, 0x001220C2, 0x010, 0x10000, 0x40000),
+ FLASH_ID("mac 25l4005" , 0xd8, 0x001320C2, 0x010, 0x10000, 0x80000),
+ FLASH_ID("mac 25l4005a" , 0xd8, 0x001320C2, 0x010, 0x10000, 0x80000),
+ FLASH_ID("mac 25l8005" , 0xd8, 0x001420C2, 0x010, 0x10000, 0x100000),
+ FLASH_ID("mac 25l1605" , 0xd8, 0x001520C2, 0x100, 0x10000, 0x200000),
+ FLASH_ID("mac 25l1605a" , 0xd8, 0x001520C2, 0x010, 0x10000, 0x200000),
+ FLASH_ID("mac 25l3205" , 0xd8, 0x001620C2, 0x100, 0x10000, 0x400000),
+ FLASH_ID("mac 25l3205a" , 0xd8, 0x001620C2, 0x100, 0x10000, 0x400000),
+ FLASH_ID("mac 25l6405" , 0xd8, 0x001720C2, 0x100, 0x10000, 0x800000),
+ FLASH_ID("wbd w25q128" , 0xd8, 0x001840EF, 0x100, 0x10000, 0x1000000),
};
/*
@@ -58,13 +100,19 @@ static struct flash_dev flash_ids[] = {
*
* Wait until TFF is set in status register
*/
-static void smi_wait_xfer_finish(int timeout)
+static int smi_wait_xfer_finish(int timeout)
{
- while (timeout--) {
+ ulong start = get_timer(0);
+
+ while (get_timer(start) < timeout) {
if (readl(&smicntl->smi_sr) & TFF)
- break;
- udelay(1000);
- }
+ return 0;
+
+ /* Try after 10 ms */
+ udelay(10);
+ };
+
+ return -1;
}
/*
@@ -82,7 +130,9 @@ static unsigned int smi_read_id(flash_info_t *info, int banknum)
writel(READ_ID, &smicntl->smi_tr);
writel((banknum << BANKSEL_SHIFT) | SEND | TX_LEN_1 | RX_LEN_3,
&smicntl->smi_cr2);
- smi_wait_xfer_finish(XFER_FINISH_TOUT);
+
+ if (smi_wait_xfer_finish(XFER_FINISH_TOUT))
+ return -EIO;
value = (readl(&smicntl->smi_rr) & 0x00FFFFFF);
@@ -103,30 +153,30 @@ static unsigned int smi_read_id(flash_info_t *info, int banknum)
static ulong flash_get_size(ulong base, int banknum)
{
flash_info_t *info = &flash_info[banknum];
- struct flash_dev *dev;
- unsigned int value;
- unsigned int density;
+ int value;
int i;
value = smi_read_id(info, banknum);
- density = (value >> 16) & 0xff;
-
- for (i = 0, dev = &flash_ids[0]; dev->density != 0x0;
- i++, dev = &flash_ids[i]) {
- if (dev->density == density) {
- info->size = dev->size;
- info->sector_count = dev->sector_count;
- break;
- }
- }
- if (dev->density == 0x0)
+ if (value < 0) {
+ printf("Flash id could not be read\n");
return 0;
+ }
- info->flash_id = value & 0xffff;
- info->start[0] = base;
+ /* Matches chip-id to entire list of 'serial-nor flash' ids */
+ for (i = 0; i < ARRAY_SIZE(flash_devices); i++) {
+ if (flash_devices[i].device_id == value) {
+ info->size = flash_devices[i].size_in_bytes;
+ info->flash_id = value;
+ info->start[0] = base;
+ info->sector_count =
+ info->size/flash_devices[i].sectorsize;
- return info->size;
+ return info->size;
+ }
+ }
+
+ return 0;
}
/*
@@ -136,9 +186,9 @@ static ulong flash_get_size(ulong base, int banknum)
* This routine will get the status register of the flash chip present at the
* given bank
*/
-static unsigned int smi_read_sr(int bank)
+static int smi_read_sr(int bank)
{
- u32 ctrlreg1;
+ u32 ctrlreg1, val;
/* store the CTRL REG1 state */
ctrlreg1 = readl(&smicntl->smi_cr1);
@@ -150,12 +200,15 @@ static unsigned int smi_read_sr(int bank)
/* Performing a RSR instruction in HW mode */
writel((bank << BANKSEL_SHIFT) | RD_STATUS_REG, &smicntl->smi_cr2);
- smi_wait_xfer_finish(XFER_FINISH_TOUT);
+ if (smi_wait_xfer_finish(XFER_FINISH_TOUT))
+ return -1;
+
+ val = readl(&smicntl->smi_sr);
/* Restore the CTRL REG1 state */
writel(ctrlreg1, &smicntl->smi_cr1);
- return readl(&smicntl->smi_sr);
+ return val;
}
/*
@@ -169,22 +222,20 @@ static unsigned int smi_read_sr(int bank)
*/
static int smi_wait_till_ready(int bank, int timeout)
{
- int count;
- unsigned int sr;
+ int sr;
+ ulong start = get_timer(0);
/* One chip guarantees max 5 msec wait here after page writes,
but potentially three seconds (!) after page erase. */
- for (count = 0; count < timeout; count++) {
-
+ while (get_timer(start) < timeout) {
sr = smi_read_sr(bank);
- if (sr < 0)
- break;
- else if (!(sr & WIP_BIT))
+ if ((sr >= 0) && (!(sr & WIP_BIT)))
return 0;
- /* Try again after 1m-sec */
- udelay(1000);
- }
+ /* Try again after 10 usec */
+ udelay(10);
+ } while (timeout--);
+
printf("SMI controller is still in wait, timeout=%d\n", timeout);
return -EIO;
}
@@ -199,7 +250,9 @@ static int smi_wait_till_ready(int bank, int timeout)
static int smi_write_enable(int bank)
{
u32 ctrlreg1;
+ u32 start;
int timeout = WMODE_TOUT;
+ int sr;
/* Store the CTRL REG1 state */
ctrlreg1 = readl(&smicntl->smi_cr1);
@@ -210,19 +263,21 @@ static int smi_write_enable(int bank)
/* Give the Flash, Write Enable command */
writel((bank << BANKSEL_SHIFT) | WE, &smicntl->smi_cr2);
- smi_wait_xfer_finish(XFER_FINISH_TOUT);
+ if (smi_wait_xfer_finish(XFER_FINISH_TOUT))
+ return -1;
/* Restore the CTRL REG1 state */
writel(ctrlreg1, &smicntl->smi_cr1);
- while (timeout--) {
- if (smi_read_sr(bank) & (1 << (bank + WM_SHIFT)))
- break;
- udelay(1000);
- }
+ start = get_timer(0);
+ while (get_timer(start) < timeout) {
+ sr = smi_read_sr(bank);
+ if ((sr >= 0) && (sr & (1 << (bank + WM_SHIFT))))
+ return 0;
- if (timeout)
- return 0;
+ /* Try again after 10 usec */
+ udelay(10);
+ };
return -1;
}
@@ -232,7 +287,7 @@ static int smi_write_enable(int bank)
*
* SMI initialization routine. Sets SMI control register1.
*/
-static void smi_init(void)
+void smi_init(void)
{
/* Setting the fast mode values. SMI working at 166/4 = 41.5 MHz */
writel(HOLD1 | FAST_MODE | BANK_EN | DSEL_TIME | PRESCAL4,
@@ -275,45 +330,39 @@ static int smi_sector_erase(flash_info_t *info, unsigned int sector)
writel(readl(&smicntl->smi_sr) & ~(ERF1 | ERF2), &smicntl->smi_sr);
- if (info->flash_id == ST_M25Pxx_ID) {
- /* Wait until finished previous write command. */
- if (smi_wait_till_ready(bank, CONFIG_SYS_FLASH_ERASE_TOUT))
- return -EBUSY;
+ /* Wait until finished previous write command. */
+ if (smi_wait_till_ready(bank, CONFIG_SYS_FLASH_ERASE_TOUT))
+ return -EBUSY;
- /* Send write enable, before erase commands. */
- if (smi_write_enable(bank))
- return -EIO;
+ /* Send write enable, before erase commands. */
+ if (smi_write_enable(bank))
+ return -EIO;
- /* Put SMI in SW mode */
- writel(readl(&smicntl->smi_cr1) | SW_MODE, &smicntl->smi_cr1);
+ /* Put SMI in SW mode */
+ writel(readl(&smicntl->smi_cr1) | SW_MODE, &smicntl->smi_cr1);
- /* Send Sector Erase command in SW Mode */
- writel(instruction, &smicntl->smi_tr);
- writel((bank << BANKSEL_SHIFT) | SEND | TX_LEN_4,
+ /* Send Sector Erase command in SW Mode */
+ writel(instruction, &smicntl->smi_tr);
+ writel((bank << BANKSEL_SHIFT) | SEND | TX_LEN_4,
&smicntl->smi_cr2);
- smi_wait_xfer_finish(XFER_FINISH_TOUT);
+ if (smi_wait_xfer_finish(XFER_FINISH_TOUT))
+ return -EIO;
- if (smi_wait_till_ready(bank, CONFIG_SYS_FLASH_ERASE_TOUT))
- return -EBUSY;
+ if (smi_wait_till_ready(bank, CONFIG_SYS_FLASH_ERASE_TOUT))
+ return -EBUSY;
- /* Put SMI in HW mode */
- writel(readl(&smicntl->smi_cr1) & ~SW_MODE,
+ /* Put SMI in HW mode */
+ writel(readl(&smicntl->smi_cr1) & ~SW_MODE,
&smicntl->smi_cr1);
- return 0;
- } else {
- /* Put SMI in HW mode */
- writel(readl(&smicntl->smi_cr1) & ~SW_MODE,
- &smicntl->smi_cr1);
- return -EINVAL;
- }
+ return 0;
}
/*
* smi_write - Write to SMI flash
* @src_addr: source buffer
* @dst_addr: destination buffer
- * @length: length to write in words
+ * @length: length to write in bytes
* @bank: bank base address
*
* Write to SMI flash
@@ -321,7 +370,10 @@ static int smi_sector_erase(flash_info_t *info, unsigned int sector)
static int smi_write(unsigned int *src_addr, unsigned int *dst_addr,
unsigned int length, ulong bank_addr)
{
+ u8 *src_addr8 = (u8 *)src_addr;
+ u8 *dst_addr8 = (u8 *)dst_addr;
int banknum;
+ int i;
switch (bank_addr) {
case SMIBANK0_BASE:
@@ -350,7 +402,7 @@ static int smi_write(unsigned int *src_addr, unsigned int *dst_addr,
return -EIO;
/* Perform the write command */
- while (length--) {
+ for (i = 0; i < length; i += 4) {
if (((ulong) (dst_addr) % SFLASH_PAGE_SIZE) == 0) {
if (smi_wait_till_ready(banknum,
CONFIG_SYS_FLASH_WRITE_TOUT))
@@ -360,7 +412,18 @@ static int smi_write(unsigned int *src_addr, unsigned int *dst_addr,
return -EIO;
}
- *dst_addr++ = *src_addr++;
+ if (length < 4) {
+ int k;
+
+ /*
+ * Handle special case, where length < 4 (redundant env)
+ */
+ for (k = 0; k < length; k++)
+ *dst_addr8++ = *src_addr8++;
+ } else {
+ /* Normal 32bit write */
+ *dst_addr++ = *src_addr++;
+ }
if ((readl(&smicntl->smi_sr) & (ERF1 | ERF2)))
return -EIO;
@@ -386,7 +449,7 @@ static int smi_write(unsigned int *src_addr, unsigned int *dst_addr,
int write_buff(flash_info_t *info, uchar *src, ulong dest_addr, ulong length)
{
return smi_write((unsigned int *)src, (unsigned int *)dest_addr,
- (length + 3) / 4, info->start[0]);
+ length, info->start[0]);
}
/*
@@ -429,8 +492,13 @@ void flash_print_info(flash_info_t *info)
puts("missing or unknown FLASH type\n");
return;
}
- printf(" Size: %ld MB in %d Sectors\n",
- info->size >> 20, info->sector_count);
+
+ if (info->size >= 0x100000)
+ printf(" Size: %ld MB in %d Sectors\n",
+ info->size >> 20, info->sector_count);
+ else
+ printf(" Size: %ld KB in %d Sectors\n",
+ info->size >> 10, info->sector_count);
puts(" Sector Start Addresses:");
for (i = 0; i < info->sector_count; ++i) {
@@ -483,11 +551,6 @@ int flash_erase(flash_info_t *info, int s_first, int s_last)
int prot = 0;
flash_sect_t sect;
- if (info->flash_id != ST_M25Pxx_ID) {
- puts("Can't erase unknown flash type - aborted\n");
- return 1;
- }
-
if ((s_first < 0) || (s_first > s_last)) {
puts("- no sectors to erase\n");
return 1;
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index e471d2c..b2516d1 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -895,5 +895,13 @@ int davinci_emac_initialize(void)
miiphy_register(phy[i].name, davinci_mii_phy_read,
davinci_mii_phy_write);
}
+
+#if defined(CONFIG_DRIVER_TI_EMAC_USE_RMII) && \
+ defined(CONFIG_MACH_DAVINCI_DA850_EVM)
+ for (i = 0; i < num_phy; i++) {
+ if (phy[i].is_phy_connected(i))
+ phy[i].auto_negotiate(i);
+ }
+#endif
return(1);
}
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 9b17db4..326d550 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -28,6 +28,7 @@
#include <common.h>
#include <miiphy.h>
#include <malloc.h>
+#include <linux/compiler.h>
#include <linux/err.h>
#include <asm/io.h>
#include "designware.h"
@@ -153,6 +154,13 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
if (priv->phy_configured != 1)
configure_phy(dev);
+ /* Print link status only once */
+ if (!priv->link_printed) {
+ printf("ENET Speed is %d Mbps - %s duplex connection\n",
+ priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
+ priv->link_printed = 1;
+ }
+
/* Reset ethernet hardware */
if (mac_reset(dev) < 0)
return -1;
@@ -168,10 +176,17 @@ static int dw_eth_init(struct eth_device *dev, bd_t *bis)
conf = FRAMEBURSTENABLE | DISABLERXOWN;
- if (priv->speed != SPEED_1000M)
+ if (priv->speed != 1000)
conf |= MII_PORTSELECT;
- if (priv->duplex == FULL_DUPLEX)
+ if ((priv->interface != PHY_INTERFACE_MODE_MII) &&
+ (priv->interface != PHY_INTERFACE_MODE_GMII)) {
+
+ if (priv->speed == 100)
+ conf |= FES_100;
+ }
+
+ if (priv->duplex == FULL)
conf |= FULLDPLXMODE;
writel(conf, &mac_p->conf);
@@ -389,6 +404,16 @@ static int dw_reset_phy(struct eth_device *dev)
return 0;
}
+/*
+ * Add weak default function for board specific PHY configuration
+ */
+int __weak designware_board_phy_init(struct eth_device *dev, int phy_addr,
+ int (*mii_write)(struct eth_device *, u8, u8, u16),
+ int dw_reset_phy(struct eth_device *))
+{
+ return 0;
+}
+
static int configure_phy(struct eth_device *dev)
{
struct dw_eth_dev *priv = dev->priv;
@@ -398,9 +423,6 @@ static int configure_phy(struct eth_device *dev)
u16 bmsr;
u32 timeout;
ulong start;
- u16 anlpar, btsr;
-#else
- u16 ctrl;
#endif
#if defined(CONFIG_DW_SEARCH_PHY)
@@ -412,6 +434,16 @@ static int configure_phy(struct eth_device *dev)
#else
phy_addr = priv->address;
#endif
+
+ /*
+ * Some boards need board specific PHY initialization. This is
+ * after the main driver init code but before the auto negotiation
+ * is run.
+ */
+ if (designware_board_phy_init(dev, phy_addr,
+ eth_mdio_write, dw_reset_phy) < 0)
+ return -1;
+
if (dw_reset_phy(dev) < 0)
return -1;
@@ -437,72 +469,32 @@ static int configure_phy(struct eth_device *dev)
#if defined(CONFIG_DW_AUTONEG)
timeout = CONFIG_AUTONEG_TIMEOUT;
start = get_timer(0);
-
+ puts("Waiting for PHY auto negotiation to complete");
while (get_timer(start) < timeout) {
eth_mdio_read(dev, phy_addr, MII_BMSR, &bmsr);
- if (bmsr & BMSR_ANEGCOMPLETE)
+ if (bmsr & BMSR_ANEGCOMPLETE) {
+ priv->phy_configured = 1;
break;
-
- /* Try again after 10usec */
- udelay(10);
- };
-
- eth_mdio_read(dev, phy_addr, MII_LPA, &anlpar);
- eth_mdio_read(dev, phy_addr, MII_STAT1000, &btsr);
-
- if (bmsr & BMSR_ANEGCOMPLETE) {
- if (btsr & PHY_1000BTSR_1000FD) {
- priv->speed = SPEED_1000M;
- bmcr |= BMCR_SPEED1000;
- priv->duplex = FULL_DUPLEX;
- bmcr |= BMCR_FULLDPLX;
- } else if (btsr & PHY_1000BTSR_1000HD) {
- priv->speed = SPEED_1000M;
- bmcr |= BMCR_SPEED1000;
- priv->duplex = HALF_DUPLEX;
- bmcr &= ~BMCR_FULLDPLX;
- } else if (anlpar & LPA_100FULL) {
- priv->speed = SPEED_100M;
- bmcr |= BMCR_SPEED100;
- priv->duplex = FULL_DUPLEX;
- bmcr |= BMCR_FULLDPLX;
- } else if (anlpar & LPA_100HALF) {
- priv->speed = SPEED_100M;
- bmcr |= BMCR_SPEED100;
- priv->duplex = HALF_DUPLEX;
- bmcr &= ~BMCR_FULLDPLX;
- } else if (anlpar & LPA_10FULL) {
- priv->speed = SPEED_10M;
- bmcr &= ~BMCR_SPEED100;
- priv->duplex = FULL_DUPLEX;
- bmcr |= BMCR_FULLDPLX;
- } else {
- priv->speed = SPEED_10M;
- bmcr &= ~BMCR_SPEED100;
- priv->duplex = HALF_DUPLEX;
- bmcr &= ~BMCR_FULLDPLX;
}
- if (eth_mdio_write(dev, phy_addr, MII_BMCR, bmcr) < 0)
- return -1;
- } else
- return -1;
-#else
- if (eth_mdio_read(dev, phy_addr, MII_BMCR, &ctrl) < 0)
- return -1;
- if (ctrl & BMCR_FULLDPLX)
- priv->duplex = FULL_DUPLEX;
- else
- priv->duplex = HALF_DUPLEX;
+ /* Print dot all 1s to show progress */
+ if ((get_timer(start) % 1000) == 0)
+ putc('.');
- if (ctrl & BMCR_SPEED1000)
- priv->speed = SPEED_1000M;
- else if (ctrl & BMCR_SPEED100)
- priv->speed = SPEED_100M;
+ /* Try again after 1msec */
+ udelay(1000);
+ };
+
+ if (!(bmsr & BMSR_ANEGCOMPLETE))
+ puts(" TIMEOUT!\n");
else
- priv->speed = SPEED_10M;
-#endif
+ puts(" done\n");
+#else
priv->phy_configured = 1;
+#endif
+
+ priv->speed = miiphy_speed(dev->name, phy_addr);
+ priv->duplex = miiphy_duplex(dev->name, phy_addr);
return 0;
}
@@ -531,7 +523,7 @@ static int dw_mii_write(const char *devname, u8 addr, u8 reg, u16 val)
}
#endif
-int designware_initialize(u32 id, ulong base_addr, u32 phy_addr)
+int designware_initialize(u32 id, ulong base_addr, u32 phy_addr, u32 interface)
{
struct eth_device *dev;
struct dw_eth_dev *priv;
@@ -565,11 +557,7 @@ int designware_initialize(u32 id, ulong base_addr, u32 phy_addr)
DW_DMA_BASE_OFFSET);
priv->address = phy_addr;
priv->phy_configured = 0;
-
- if (mac_reset(dev) < 0)
- return -1;
-
- configure_phy(dev);
+ priv->interface = interface;
dev->init = dw_eth_init;
dev->send = dw_eth_send;
diff --git a/drivers/net/designware.h b/drivers/net/designware.h
index abf729d..d668f8f 100644
--- a/drivers/net/designware.h
+++ b/drivers/net/designware.h
@@ -234,11 +234,13 @@ struct dmamacdescr {
struct dw_eth_dev {
u32 address;
+ u32 interface;
u32 speed;
u32 duplex;
u32 tx_currdescnum;
u32 rx_currdescnum;
u32 phy_configured;
+ int link_printed;
u32 padding;
struct dmamacdescr tx_mac_descrtable[CONFIG_TX_DESCR_NUM];
diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c
index 62c2446..8721e74 100644
--- a/drivers/rtc/m41t62.c
+++ b/drivers/rtc/m41t62.c
@@ -63,6 +63,8 @@
#define M41T62_FEATURE_HT (1 << 0)
#define M41T62_FEATURE_BL (1 << 1)
+#define M41T80_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */
+
int rtc_get(struct rtc_time *tm)
{
u8 buf[M41T62_DATETIME_REG_SIZE];
@@ -132,9 +134,15 @@ int rtc_set(struct rtc_time *tm)
void rtc_reset(void)
{
+ u8 val;
+
/*
- * Nothing to do
+ * M41T82: Make sure HT (Halt Update) bit is cleared.
+ * This bit is 0 in M41T62 so its save to clear it always.
*/
+ i2c_read(CONFIG_SYS_I2C_RTC_ADDR, M41T62_REG_ALARM_HOUR, 1, &val, 1);
+ val &= ~M41T80_ALHOUR_HT;
+ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, M41T62_REG_ALARM_HOUR, 1, &val, 1);
}
#endif
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index c967d87..c20f1f2 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -43,7 +43,7 @@ COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o
COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
COBJS-$(CONFIG_SH_SPI) += sh_spi.o
COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o
-COBJS-$(CONFIG_TEGRA2_SPI) += tegra2_spi.o
+COBJS-$(CONFIG_TEGRA_SPI) += tegra_spi.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c
index db8ba8b..f4523a3 100644
--- a/drivers/spi/kirkwood_spi.c
+++ b/drivers/spi/kirkwood_spi.c
@@ -34,16 +34,14 @@
static struct kwspi_registers *spireg = (struct kwspi_registers *)KW_SPI_BASE;
+u32 cs_spi_mpp_back[2];
+
struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int mode)
{
struct spi_slave *slave;
u32 data;
- u32 kwspi_mpp_config[] = {
- MPP0_GPIO,
- MPP7_SPI_SCn,
- 0
- };
+ u32 kwspi_mpp_config[] = { 0, 0 };
if (!spi_cs_is_valid(bus, cs))
return NULL;
@@ -70,29 +68,75 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
/* program mpp registers to select SPI_CSn */
if (cs) {
- kwspi_mpp_config[0] = MPP0_GPIO;
- kwspi_mpp_config[1] = MPP7_SPI_SCn;
+ kwspi_mpp_config[0] = MPP7_SPI_SCn;
} else {
kwspi_mpp_config[0] = MPP0_SPI_SCn;
- kwspi_mpp_config[1] = MPP7_GPO;
}
- kirkwood_mpp_conf(kwspi_mpp_config);
+ kirkwood_mpp_conf(kwspi_mpp_config, cs_spi_mpp_back);
return slave;
}
void spi_free_slave(struct spi_slave *slave)
{
+ kirkwood_mpp_conf(cs_spi_mpp_back, NULL);
free(slave);
}
-int spi_claim_bus(struct spi_slave *slave)
+#if defined(CONFIG_SYS_KW_SPI_MPP)
+u32 spi_mpp_backup[4];
+#endif
+
+__attribute__((weak)) int board_spi_claim_bus(struct spi_slave *slave)
{
return 0;
}
+int spi_claim_bus(struct spi_slave *slave)
+{
+#if defined(CONFIG_SYS_KW_SPI_MPP)
+ u32 config;
+ u32 spi_mpp_config[4];
+
+ config = CONFIG_SYS_KW_SPI_MPP;
+
+ if (config & MOSI_MPP6)
+ spi_mpp_config[0] = MPP6_SPI_MOSI;
+ else
+ spi_mpp_config[0] = MPP1_SPI_MOSI;
+
+ if (config & SCK_MPP10)
+ spi_mpp_config[1] = MPP10_SPI_SCK;
+ else
+ spi_mpp_config[1] = MPP2_SPI_SCK;
+
+ if (config & MISO_MPP11)
+ spi_mpp_config[2] = MPP11_SPI_MISO;
+ else
+ spi_mpp_config[2] = MPP3_SPI_MISO;
+
+ spi_mpp_config[3] = 0;
+ spi_mpp_backup[3] = 0;
+
+ /* set new spi mpp and save current mpp config */
+ kirkwood_mpp_conf(spi_mpp_config, spi_mpp_backup);
+
+#endif
+
+ return board_spi_claim_bus(slave);
+}
+
+__attribute__((weak)) void board_spi_release_bus(struct spi_slave *slave)
+{
+}
+
void spi_release_bus(struct spi_slave *slave)
{
+#if defined(CONFIG_SYS_KW_SPI_MPP)
+ kirkwood_mpp_conf(spi_mpp_backup, NULL);
+#endif
+
+ board_spi_release_bus(slave);
}
#ifndef CONFIG_SPI_CS_IS_VALID
diff --git a/drivers/spi/tegra2_spi.c b/drivers/spi/tegra_spi.c
index 56cb229..4a3e799 100644
--- a/drivers/spi/tegra2_spi.c
+++ b/drivers/spi/tegra_spi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2011 NVIDIA Corporation
+ * Copyright (c) 2010-2012 NVIDIA Corporation
* With help from the mpc8xxx SPI driver
* With more help from omap3_spi SPI driver
*
@@ -28,12 +28,17 @@
#include <spi.h>
#include <asm/io.h>
#include <asm/gpio.h>
-#include <ns16550.h>
#include <asm/arch/clk_rst.h>
#include <asm/arch/clock.h>
#include <asm/arch/pinmux.h>
#include <asm/arch/uart-spi-switch.h>
-#include <asm/arch/tegra2_spi.h>
+#include <asm/arch/tegra_spi.h>
+
+#if defined(CONFIG_SPI_CORRUPTS_UART)
+ #define corrupt_delay() udelay(CONFIG_SPI_CORRUPTS_UART_DLY);
+#else
+ #define corrupt_delay()
+#endif
struct tegra_spi_slave {
struct spi_slave slave;
@@ -161,14 +166,20 @@ void spi_cs_activate(struct spi_slave *slave)
/* CS is negated on Tegra, so drive a 1 to get a 0 */
setbits_le32(&spi->regs->command, SPI_CMD_CS_VAL);
+
+ corrupt_delay(); /* Let UART settle */
}
void spi_cs_deactivate(struct spi_slave *slave)
{
struct tegra_spi_slave *spi = to_tegra_spi(slave);
+ pinmux_select_uart();
+
/* CS is negated on Tegra, so drive a 0 to get a 1 */
clrbits_le32(&spi->regs->command, SPI_CMD_CS_VAL);
+
+ corrupt_delay(); /* Let SPI settle */
}
int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 59c3e57..4547f37 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -36,6 +36,7 @@ COBJS-$(CONFIG_USB_SL811HS) += sl811-hcd.o
# echi
COBJS-$(CONFIG_USB_EHCI) += ehci-hcd.o
COBJS-$(CONFIG_USB_EHCI_ARMADA100) += ehci-armada100.o utmi-armada100.o
+COBJS-$(CONFIG_USB_EHCI_ATMEL) += ehci-atmel.o
ifdef CONFIG_MPC512X
COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
else
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
new file mode 100644
index 0000000..15b9b60
--- /dev/null
+++ b/drivers/usb/host/ehci-atmel.c
@@ -0,0 +1,89 @@
+/*
+ * (C) Copyright 2012
+ * Atmel Semiconductor <www.atmel.com>
+ * Written-by: Bo Shen <voice.shen@atmel.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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <usb.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/clk.h>
+
+#include "ehci.h"
+#include "ehci-core.h"
+
+/* Enable UTMI PLL time out 500us
+ * 10 times as datasheet specified
+ */
+#define EN_UPLL_TIMEOUT 500UL
+
+int ehci_hcd_init(void)
+{
+ at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
+ ulong start_time, tmp_time;
+
+ start_time = get_timer(0);
+ /* Enable UTMI PLL */
+ writel(AT91_PMC_UPLLEN | AT91_PMC_BIASEN, &pmc->uckr);
+ while ((readl(&pmc->sr) & AT91_PMC_LOCKU) != AT91_PMC_LOCKU) {
+ WATCHDOG_RESET();
+ tmp_time = get_timer(0);
+ if ((tmp_time - start_time) > EN_UPLL_TIMEOUT) {
+ printf("ERROR: failed to enable UPLL\n");
+ return -1;
+ }
+ }
+
+ /* Enable USB Host clock */
+ writel(1 << ATMEL_ID_UHPHS, &pmc->pcer);
+
+ hccr = (struct ehci_hccr *)ATMEL_BASE_EHCI;
+ hcor = (struct ehci_hcor *)((uint32_t)hccr +
+ HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ return 0;
+}
+
+int ehci_hcd_stop(void)
+{
+ at91_pmc_t *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
+ ulong start_time, tmp_time;
+
+ /* Disable USB Host Clock */
+ writel(1 << ATMEL_ID_UHPHS, &pmc->pcdr);
+
+ start_time = get_timer(0);
+ /* Disable UTMI PLL */
+ writel(readl(&pmc->uckr) & ~AT91_PMC_UPLLEN, &pmc->uckr);
+ while ((readl(&pmc->sr) & AT91_PMC_LOCKU) == AT91_PMC_LOCKU) {
+ WATCHDOG_RESET();
+ tmp_time = get_timer(0);
+ if ((tmp_time - start_time) > EN_UPLL_TIMEOUT) {
+ printf("ERROR: failed to stop UPLL\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c
index 92be4ea..49fdfec 100644
--- a/drivers/video/exynos_fb.c
+++ b/drivers/video/exynos_fb.c
@@ -44,9 +44,6 @@ short console_row;
static unsigned int panel_width, panel_height;
-/* LCD Panel data */
-vidinfo_t panel_info;
-
static void exynos_lcd_init_mem(void *lcdbase, vidinfo_t *vid)
{
unsigned long palette_size;