]> git.ipfire.org Git - people/ms/u-boot.git/commitdiff
Merge branch 'master' of git://git.denx.de/u-boot-spi
authorTom Rini <trini@konsulko.com>
Tue, 28 Apr 2015 11:28:43 +0000 (07:28 -0400)
committerTom Rini <trini@konsulko.com>
Tue, 28 Apr 2015 11:28:43 +0000 (07:28 -0400)
14 files changed:
README
common/cmd_sf.c
drivers/mtd/spi/sf_internal.h
drivers/mtd/spi/sf_ops.c
drivers/mtd/spi/sf_probe.c
drivers/spi/exynos_spi.c
drivers/spi/omap3_spi.c
drivers/spi/spi-uclass.c
drivers/spi/tegra114_spi.c
drivers/spi/tegra20_sflash.c
drivers/spi/tegra20_slink.c
drivers/spi/zynq_spi.c
include/spi.h
include/spi_flash.h

diff --git a/README b/README
index a70af9864676652bd127fc1cdb1dfc7739472e96..ee65fdb4c6666c5fef1fed2d4abc9e8a740ea471 100644 (file)
--- a/README
+++ b/README
@@ -3096,17 +3096,6 @@ CBFS (Coreboot Filesystem) support
                memories can be connected with a given cs line.
                Currently Xilinx Zynq qspi supports these type of connections.
 
-               CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
-               enable the W#/Vpp signal to disable writing to the status
-               register on ST MICRON flashes like the N25Q128.
-               The status register write enable/disable bit, combined with
-               the W#/VPP signal provides hardware data protection for the
-               device as follows: When the enable/disable bit is set to 1,
-               and the W#/VPP signal is driven LOW, the status register
-               nonvolatile bits become read-only and the WRITE STATUS REGISTER
-               operation will not execute. The only way to exit this
-               hardware-protected mode is to drive W#/VPP HIGH.
-
 - SystemACE Support:
                CONFIG_SYSTEMACE
 
index 6aabf39302ce5e9000d19777a1622b27d1d52189..342021df97e79195aacaba4c756bb3737dcd98be 100644 (file)
@@ -164,6 +164,8 @@ static int do_spi_flash_probe(int argc, char * const argv[])
 static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset,
                size_t len, const char *buf, char *cmp_buf, size_t *skipped)
 {
+       char *ptr = (char *)buf;
+
        debug("offset=%#x, sector_size=%#x, len=%#zx\n",
              offset, flash->sector_size, len);
        /* Read the entire sector so to allow for rewriting */
@@ -179,16 +181,14 @@ static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset,
        /* Erase the entire sector */
        if (spi_flash_erase(flash, offset, flash->sector_size))
                return "erase";
-       /* Write the initial part of the block from the source */
-       if (spi_flash_write(flash, offset, len, buf))
-               return "write";
-       /* If it's a partial sector, rewrite the existing part */
+       /* If it's a partial sector, copy the data into the temp-buffer */
        if (len != flash->sector_size) {
-               /* Rewrite the original data to the end of the sector */
-               if (spi_flash_write(flash, offset + len,
-                                   flash->sector_size - len, &cmp_buf[len]))
-                       return "write";
+               memcpy(cmp_buf, buf, len);
+               ptr = cmp_buf;
        }
+       /* Write one complete sector */
+       if (spi_flash_write(flash, offset, flash->sector_size, ptr))
+               return "write";
 
        return NULL;
 }
index 785f7a96fed28d8d7cb8297fa009705e183c9290..4158e1332286325eaca1306a1c7eaee1b75303a8 100644 (file)
@@ -97,10 +97,6 @@ enum {
 #define STATUS_QEB_MXIC                (1 << 6)
 #define STATUS_PEC                     (1 << 7)
 
-#ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
-#define STATUS_SRWD                    (1 << 7) /* SR write protect */
-#endif
-
 /* Flash timeout values */
 #define SPI_FLASH_PROG_TIMEOUT         (2 * CONFIG_SYS_HZ)
 #define SPI_FLASH_PAGE_ERASE_TIMEOUT           (5 * CONFIG_SYS_HZ)
@@ -123,7 +119,8 @@ int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len,
  * @name:              Device name ([MANUFLETTER][DEVTYPE][DENSITY][EXTRAINFO])
  * @jedec:             Device jedec ID (0x[1byte_manuf_id][2byte_dev_id])
  * @ext_jedec:         Device ext_jedec ID
- * @sector_size:       Sector size of this device
+ * @sector_size:       Isn't necessarily a sector size from vendor,
+ *                     the size listed here is what works with CMD_ERASE_64K
  * @nr_sectors:        No.of sectors on this device
  * @e_rd_cmd:          Enum list for read commands
  * @flags:             Important param, for flash specific behaviour
index 34bc54e73e1f7b74d58d1d47fe87b56471371081..38592f518b72c7f4a7966fb2ad61d1c12242a84a 100644 (file)
@@ -154,21 +154,17 @@ static void spi_flash_dual_flash(struct spi_flash *flash, u32 *addr)
 }
 #endif
 
-int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
+static int spi_flash_poll_status(struct spi_slave *spi, unsigned long timeout,
+                                u8 cmd, u8 poll_bit)
 {
-       struct spi_slave *spi = flash->spi;
        unsigned long timebase;
        unsigned long flags = SPI_XFER_BEGIN;
        int ret;
        u8 status;
        u8 check_status = 0x0;
-       u8 poll_bit = STATUS_WIP;
-       u8 cmd = flash->poll_cmd;
 
-       if (cmd == CMD_FLAG_STATUS) {
-               poll_bit = STATUS_PEC;
+       if (cmd == CMD_FLAG_STATUS)
                check_status = poll_bit;
-       }
 
 #ifdef CONFIG_SF_DUAL_FLASH
        if (spi->flags & SPI_XFER_U_PAGE)
@@ -204,6 +200,28 @@ int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
        return -1;
 }
 
+int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
+{
+       struct spi_slave *spi = flash->spi;
+       int ret;
+       u8 poll_bit = STATUS_WIP;
+       u8 cmd = CMD_READ_STATUS;
+
+       ret = spi_flash_poll_status(spi, timeout, cmd, poll_bit);
+       if (ret < 0)
+               return ret;
+
+       if (flash->poll_cmd == CMD_FLAG_STATUS) {
+               poll_bit = STATUS_PEC;
+               cmd = CMD_FLAG_STATUS;
+               ret = spi_flash_poll_status(spi, timeout, cmd, poll_bit);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
 int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
                size_t cmd_len, const void *buf, size_t buf_len)
 {
index d19138d9071d1365b080610bac46e649691aa84c..201471c392c60897afc403d098898851e5bf5e38 100644 (file)
@@ -132,6 +132,9 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
        flash->name = params->name;
        flash->memory_map = spi->memory_map;
        flash->dual_flash = flash->spi->option;
+#ifdef CONFIG_DM_SPI_FLASH
+       flash->flags = params->flags;
+#endif
 
        /* Assign spi_flash ops */
 #ifndef CONFIG_DM_SPI_FLASH
@@ -184,6 +187,9 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode,
                flash->erase_size = flash->sector_size;
        }
 
+       /* Now erase size becomes valid sector size */
+       flash->sector_size = flash->erase_size;
+
        /* Look for the fastest read cmd */
        cmd = fls(params->e_rd_cmd & flash->spi->op_mode_rx);
        if (cmd) {
@@ -288,34 +294,6 @@ int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
 }
 #endif /* CONFIG_OF_CONTROL */
 
-#ifdef CONFIG_SYS_SPI_ST_ENABLE_WP_PIN
-/* enable the W#/Vpp signal to disable writing to the status register */
-static int spi_enable_wp_pin(struct spi_flash *flash)
-{
-       u8 status;
-       int ret;
-
-       ret = spi_flash_cmd_read_status(flash, &status);
-       if (ret < 0)
-               return ret;
-
-       ret = spi_flash_cmd_write_status(flash, STATUS_SRWD);
-       if (ret < 0)
-               return ret;
-
-       ret = spi_flash_cmd_write_disable(flash);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-#else
-static int spi_enable_wp_pin(struct spi_flash *flash)
-{
-       return 0;
-}
-#endif
-
 /**
  * spi_flash_probe_slave() - Probe for a SPI flash device on a bus
  *
@@ -394,8 +372,6 @@ int spi_flash_probe_slave(struct spi_slave *spi, struct spi_flash *flash)
                puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
        }
 #endif
-       if (spi_enable_wp_pin(flash))
-               puts("Enable WP pin failed\n");
 
        /* Release spi bus */
        spi_release_bus(spi);
@@ -434,6 +410,8 @@ struct spi_flash *spi_flash_probe(unsigned int busnum, unsigned int cs,
        struct spi_slave *bus;
 
        bus = spi_setup_slave(busnum, cs, max_hz, spi_mode);
+       if (!bus)
+               return NULL;
        return spi_flash_probe_tail(bus);
 }
 
@@ -444,6 +422,8 @@ struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node,
        struct spi_slave *bus;
 
        bus = spi_setup_slave_fdt(blob, slave_node, spi_node);
+       if (!bus)
+               return NULL;
        return spi_flash_probe_tail(bus);
 }
 #endif
@@ -469,6 +449,15 @@ int spi_flash_std_write(struct udevice *dev, u32 offset, size_t len,
 {
        struct spi_flash *flash = dev_get_uclass_priv(dev);
 
+#if defined(CONFIG_SPI_FLASH_SST)
+       if (flash->flags & SST_WR) {
+               if (flash->spi->op_mode_tx & SPI_OPM_TX_BP)
+                       return sst_write_bp(flash, offset, len, buf);
+               else
+                       return sst_write_wp(flash, offset, len, buf);
+       }
+#endif
+
        return spi_flash_cmd_write_ops(flash, offset, len, buf);
 }
 
index a46d8c187668cff8560eea31c7189c7dfa3b4161..67f6b2d7cdaa871b97f170d78476c658a622a94e 100644 (file)
@@ -296,8 +296,9 @@ static int exynos_spi_probe(struct udevice *bus)
        return 0;
 }
 
-static int exynos_spi_claim_bus(struct udevice *bus)
+static int exynos_spi_claim_bus(struct udevice *dev)
 {
+       struct udevice *bus = dev->parent;
        struct exynos_spi_priv *priv = dev_get_priv(bus);
 
        exynos_pinmux_config(priv->periph_id, PINMUX_FLAG_NONE);
@@ -308,8 +309,9 @@ static int exynos_spi_claim_bus(struct udevice *bus)
        return 0;
 }
 
-static int exynos_spi_release_bus(struct udevice *bus)
+static int exynos_spi_release_bus(struct udevice *dev)
 {
+       struct udevice *bus = dev->parent;
        struct exynos_spi_priv *priv = dev_get_priv(bus);
 
        spi_flush_fifo(priv->regs);
index 651e46e4bd20b345b83dcd9a87d89a5196c583bf..85f9e85fd4b92ff6af8d48bf8bb1d452ac68256e 100644 (file)
@@ -20,7 +20,7 @@
 #include <asm/io.h>
 #include "omap3_spi.h"
 
-#define SPI_WAIT_TIMEOUT 3000000
+#define SPI_WAIT_TIMEOUT 10
 
 static void spi_reset(struct omap3_spi_slave *ds)
 {
@@ -227,7 +227,7 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp,
 {
        struct omap3_spi_slave *ds = to_omap3_spi(slave);
        int i;
-       int timeout = SPI_WAIT_TIMEOUT;
+       ulong start;
        int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
 
        /* Enable the channel */
@@ -241,9 +241,10 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp,
 
        for (i = 0; i < len; i++) {
                /* wait till TX register is empty (TXS == 1) */
+               start = get_timer(0);
                while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
                         OMAP3_MCSPI_CHSTAT_TXS)) {
-                       if (--timeout <= 0) {
+                       if (get_timer(start) > SPI_WAIT_TIMEOUT) {
                                printf("SPI TXS timed out, status=0x%08x\n",
                                       readl(&ds->regs->channel[ds->slave.cs].chstat));
                                return -1;
@@ -280,7 +281,7 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp,
 {
        struct omap3_spi_slave *ds = to_omap3_spi(slave);
        int i;
-       int timeout = SPI_WAIT_TIMEOUT;
+       ulong start;
        int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
 
        /* Enable the channel */
@@ -295,10 +296,11 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp,
        writel(0, &ds->regs->channel[ds->slave.cs].tx);
 
        for (i = 0; i < len; i++) {
+               start = get_timer(0);
                /* Wait till RX register contains data (RXS == 1) */
                while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
                         OMAP3_MCSPI_CHSTAT_RXS)) {
-                       if (--timeout <= 0) {
+                       if (get_timer(start) > SPI_WAIT_TIMEOUT) {
                                printf("SPI RXS timed out, status=0x%08x\n",
                                       readl(&ds->regs->channel[ds->slave.cs].chstat));
                                return -1;
@@ -332,7 +334,7 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
                   const void *txp, void *rxp, unsigned long flags)
 {
        struct omap3_spi_slave *ds = to_omap3_spi(slave);
-       int timeout = SPI_WAIT_TIMEOUT;
+       ulong start;
        int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf);
        int irqstatus = readl(&ds->regs->irqstatus);
        int i=0;
@@ -350,9 +352,10 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
        for (i=0; i < len; i++){
                /* Write: wait for TX empty (TXS == 1)*/
                irqstatus |= (1<< (4*(ds->slave.bus)));
+               start = get_timer(0);
                while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
                         OMAP3_MCSPI_CHSTAT_TXS)) {
-                       if (--timeout <= 0) {
+                       if (get_timer(start) > SPI_WAIT_TIMEOUT) {
                                printf("SPI TXS timed out, status=0x%08x\n",
                                       readl(&ds->regs->channel[ds->slave.cs].chstat));
                                return -1;
@@ -368,9 +371,10 @@ int omap3_spi_txrx(struct spi_slave *slave, unsigned int len,
                        writel(((u8 *)txp)[i], tx);
 
                /*Read: wait for RX containing data (RXS == 1)*/
+               start = get_timer(0);
                while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) &
                         OMAP3_MCSPI_CHSTAT_RXS)) {
-                       if (--timeout <= 0) {
+                       if (get_timer(start) > SPI_WAIT_TIMEOUT) {
                                printf("SPI RXS timed out, status=0x%08x\n",
                                       readl(&ds->regs->channel[ds->slave.cs].chstat));
                                return -1;
index 866c48f243929406ed6f12512be481603644cb86..83fe8e0d69ae9d8d6972f99a72e4294fa4aa0848 100644 (file)
@@ -67,7 +67,7 @@ int spi_claim_bus(struct spi_slave *slave)
        if (ret)
                return ret;
 
-       return ops->claim_bus ? ops->claim_bus(bus) : 0;
+       return ops->claim_bus ? ops->claim_bus(dev) : 0;
 }
 
 void spi_release_bus(struct spi_slave *slave)
@@ -77,7 +77,7 @@ void spi_release_bus(struct spi_slave *slave)
        struct dm_spi_ops *ops = spi_get_ops(bus);
 
        if (ops->release_bus)
-               ops->release_bus(bus);
+               ops->release_bus(dev);
 }
 
 int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
index 53ff9ea22105353180159203def640905b5fecf8..4bec66309e9b6fbc54138dc7d3bc05458a3a3baf 100644 (file)
@@ -153,8 +153,9 @@ static int tegra114_spi_probe(struct udevice *bus)
        return 0;
 }
 
-static int tegra114_spi_claim_bus(struct udevice *bus)
+static int tegra114_spi_claim_bus(struct udevice *dev)
 {
+       struct udevice *bus = dev->parent;
        struct tegra114_spi_priv *priv = dev_get_priv(bus);
        struct spi_regs *regs = priv->regs;
 
index 78c74cdf37fe095d8efa34c26ab5df0093e305bd..82c1b84f3bd953ec50dfdb0b4197448da3043584 100644 (file)
@@ -125,8 +125,9 @@ static int tegra20_sflash_probe(struct udevice *bus)
        return 0;
 }
 
-static int tegra20_sflash_claim_bus(struct udevice *bus)
+static int tegra20_sflash_claim_bus(struct udevice *dev)
 {
+       struct udevice *bus = dev->parent;
        struct tegra20_sflash_priv *priv = dev_get_priv(bus);
        struct spi_regs *regs = priv->regs;
        u32 reg;
index 597d6ad5ccecb8e36818bb6d2d555c2f3b14294f..f6fb89b393f0881e624e006baf9f16cd056d2474 100644 (file)
@@ -141,8 +141,9 @@ static int tegra30_spi_probe(struct udevice *bus)
        return 0;
 }
 
-static int tegra30_spi_claim_bus(struct udevice *bus)
+static int tegra30_spi_claim_bus(struct udevice *dev)
 {
+       struct udevice *bus = dev->parent;
        struct tegra30_spi_priv *priv = dev_get_priv(bus);
        struct spi_regs *regs = priv->regs;
        u32 reg;
index 5da87591ceef3f530edf4bbc45b95263b53d28bf..e9129da79d99825b9d88c7bc893d3de0f9700feb 100644 (file)
@@ -227,9 +227,6 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
        debug("spi_xfer: bus:%i cs:%i bitlen:%i len:%i flags:%lx\n",
              slave->bus, slave->cs, bitlen, len, flags);
 
-       if (bitlen == 0)
-               return -1;
-
        if (bitlen % 8) {
                debug("spi_xfer: Non byte aligned SPI transfer\n");
                return -1;
index c58e453559616eb1cbbca36ee20704afcd4ebecc..9495ca53c9b6649acd7e04879261eb40c4344d8e 100644 (file)
 
 /* SPI RX operation modes */
 #define SPI_OPM_RX_AS          (1 << 0)
-#define SPI_OPM_RX_DOUT        (1 << 1)
-#define SPI_OPM_RX_DIO         (1 << 2)
-#define SPI_OPM_RX_QOF         (1 << 3)
-#define SPI_OPM_RX_QIOF        (1 << 4)
-#define SPI_OPM_RX_EXTN        (SPI_OPM_RX_AS | SPI_OPM_RX_DOUT | \
+#define SPI_OPM_RX_AF          (1 << 1)
+#define SPI_OPM_RX_DOUT                (1 << 2)
+#define SPI_OPM_RX_DIO         (1 << 3)
+#define SPI_OPM_RX_QOF         (1 << 4)
+#define SPI_OPM_RX_QIOF                (1 << 5)
+#define SPI_OPM_RX_EXTN        (SPI_OPM_RX_AS | SPI_OPM_RX_AF | SPI_OPM_RX_DOUT | \
                                SPI_OPM_RX_DIO | SPI_OPM_RX_QOF | \
                                SPI_OPM_RX_QIOF)
 
@@ -385,12 +386,12 @@ struct dm_spi_ops {
         * allowed to claim the same bus for several slaves without releasing
         * the bus in between.
         *
-        * @bus:        The SPI slave
+        * @dev:        The SPI slave
         *
         * Returns: 0 if the bus was claimed successfully, or a negative value
         * if it wasn't.
         */
-       int (*claim_bus)(struct udevice *bus);
+       int (*claim_bus)(struct udevice *dev);
 
        /**
         * Release the SPI bus
@@ -399,9 +400,9 @@ struct dm_spi_ops {
         * all transfers have finished. It may disable any SPI hardware as
         * appropriate.
         *
-        * @bus:        The SPI slave
+        * @dev:        The SPI slave
         */
-       int (*release_bus)(struct udevice *bus);
+       int (*release_bus)(struct udevice *dev);
 
        /**
         * Set the word length for SPI transactions
@@ -413,7 +414,7 @@ struct dm_spi_ops {
         *
         * Returns: 0 on success, -ve on failure.
         */
-       int (*set_wordlen)(struct udevice *bus, unsigned int wordlen);
+       int (*set_wordlen)(struct udevice *dev, unsigned int wordlen);
 
        /**
         * SPI transfer
index 218283fc987cc6380f86695a1f17cbb7679f0421..f2814ef41a0b3c27b2e82352190de831559422c9 100644 (file)
@@ -62,11 +62,10 @@ struct spi_slave;
  * return 0 - Success, 1 - Failure
  */
 struct spi_flash {
-#ifdef CONFIG_DM_SPI_FLASH
        struct spi_slave *spi;
+#ifdef CONFIG_DM_SPI_FLASH
        struct udevice *dev;
-#else
-       struct spi_slave *spi;
+       u16 flags;
 #endif
        const char *name;
        u8 dual_flash;
@@ -91,13 +90,13 @@ struct spi_flash {
 #ifndef CONFIG_DM_SPI_FLASH
        /*
         * These are not strictly needed for driver model, but keep them here
-        * whilt the transition is in progress.
+        * while the transition is in progress.
         *
         * Normally each driver would provide its own operations, but for
         * SPI flash most chips use the same algorithms. One approach is
         * to create a 'common' SPI flash device which knows how to talk
         * to most devices, and then allow other drivers to be used instead
-        * if requird, perhaps with a way of scanning through the list to
+        * if required, perhaps with a way of scanning through the list to
         * find the driver that matches the device.
         */
        int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);