Merge branch 'master' of git://git.denx.de/u-boot-spi
authorTom Rini <trini@konsulko.com>
Wed, 5 Dec 2018 20:06:24 +0000 (15:06 -0500)
committerTom Rini <trini@konsulko.com>
Wed, 5 Dec 2018 20:06:24 +0000 (15:06 -0500)
- Various MTD fixes from Boris
- Zap various unused / legacy paths.
- pxa3xx NAND update from Miquel

Signed-off-by: Tom Rini <trini@konsulko.com>
56 files changed:
README
arch/powerpc/include/asm/config.h
board/freescale/mpc8349emds/mpc8349emds.c
board/ids/ids8313/ids8313.c
cmd/eeprom.c
cmd/ubi.c
common/board_f.c
common/board_r.c
doc/driver-model/spi-howto.txt
drivers/mtd/mtd_uboot.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/raw/pxa3xx_nand.c
drivers/mtd/spi/sf_mtd.c
drivers/mtd/spi/sf_probe.c
drivers/net/e1000_spi.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/atmel_spi.c
drivers/spi/davinci_spi.c
drivers/spi/fsl_dspi.c
drivers/spi/fsl_espi.c
drivers/spi/lpc32xx_ssp.c
drivers/spi/meson_spifc.c [new file with mode: 0644]
drivers/spi/mtk_qspi.c [new file with mode: 0644]
drivers/spi/mxc_spi.c
drivers/spi/mxs_spi.c
drivers/spi/omap3_spi.c
drivers/spi/pl022_spi.c
drivers/spi/sh_qspi.c
drivers/spi/sh_spi.c
drivers/spi/soft_spi_legacy.c
examples/standalone/atmel_df_pow2.c
include/_exports.h
include/common.h
include/configs/M52277EVB.h
include/configs/M54418TWR.h
include/configs/M54451EVB.h
include/configs/M54455EVB.h
include/configs/MPC8536DS.h
include/configs/P1022DS.h
include/configs/UCP1020.h
include/configs/controlcenterd.h
include/configs/ids8313.h
include/configs/mx31pdk.h
include/configs/mxs.h
include/configs/p1_p2_rdb_pc.h
include/configs/p1_twr.h
include/configs/stmark2.h
include/configs/ts4800.h
include/dm/platform_data/spi_pl022.h [moved from include/dm/platform_data/pl022_spi.h with 64% similarity]
include/linux/mtd/mtd.h
include/regmap.h
include/spi.h
scripts/config_whitelist.txt
test/dm/regmap.c

diff --git a/README b/README
index a46c7c6..17d56b8 100644 (file)
--- a/README
+++ b/README
@@ -1932,14 +1932,6 @@ The following options need to be configured:
                SPI configuration items (port pins to use, etc). For
                an example, see include/configs/sacsng.h.
 
-               CONFIG_HARD_SPI
-
-               Enables a hardware SPI driver for general-purpose reads
-               and writes.  As with CONFIG_SOFT_SPI, the board configuration
-               must define a list of chip-select function pointers.
-               Currently supported on some MPC8xxx processors.  For an
-               example, see include/configs/mpc8349emds.h.
-
                CONFIG_SYS_SPI_MXC_WAIT
                Timeout for waiting until spi transfer completed.
                default: (CONFIG_SYS_HZ/100)     /* 10 ms */
index 849a69a..c9c9964 100644 (file)
   #define HWCONFIG_BUFFER_SIZE 256
 #endif
 
-/* CONFIG_HARD_SPI triggers SPI bus initialization in PowerPC */
-#if defined(CONFIG_MPC8XXX_SPI) || defined(CONFIG_FSL_ESPI)
-# ifndef CONFIG_HARD_SPI
-#  define CONFIG_HARD_SPI
-# endif
-#endif
-
 #define CONFIG_LMB
 #define CONFIG_SYS_BOOT_RAMDISK_HIGH
 
index 4ec0af4..d40ed37 100644 (file)
@@ -273,7 +273,7 @@ void spi_cs_deactivate(struct spi_slave *slave)
 
        iopd->dat |=  SPI_CS_MASK;
 }
-#endif /* CONFIG_HARD_SPI */
+#endif
 
 #if defined(CONFIG_OF_BOARD_SETUP)
 int ft_board_setup(void *blob, bd_t *bd)
index a411d4e..d547af4 100644 (file)
@@ -208,4 +208,4 @@ void spi_cs_deactivate(struct spi_slave *slave)
        /* deactivate the spi_cs */
        setbits_be32(&iopd->dat, IDSCPLD_SPI_CS_MASK);
 }
-#endif /* CONFIG_HARD_SPI */
+#endif
index e88cb13..6c29b33 100644 (file)
@@ -66,11 +66,6 @@ __weak int eeprom_write_enable(unsigned dev_addr, int state)
 
 void eeprom_init(int bus)
 {
-       /* SPI EEPROM */
-#if defined(CONFIG_MPC8XX_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
-       spi_init_f();
-#endif
-
        /* I2C EEPROM */
 #if defined(CONFIG_SYS_I2C)
        if (bus >= 0)
@@ -129,14 +124,6 @@ static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen,
 {
        int ret = 0;
 
-       /* SPI */
-#if defined(CONFIG_MPC8XX_SPI) && !defined(CONFIG_ENV_EEPROM_IS_ON_I2C)
-       if (read)
-               spi_read(addr, alen, buffer, len);
-       else
-               spi_write(addr, alen, buffer, len);
-#else  /* I2C */
-
 #if defined(CONFIG_DM_I2C) && defined(CONFIG_SYS_I2C_EEPROM_BUS)
        struct udevice *dev;
 
@@ -162,7 +149,6 @@ static int eeprom_rw_block(unsigned offset, uchar *addr, unsigned alen,
                ret = i2c_read(addr[0], offset, alen - 1, buffer, len);
        else
                ret = i2c_write(addr[0], offset, alen - 1, buffer, len);
-#endif
 #endif /* CONFIG_DM_I2C && CONFIG_SYS_I2C_EEPROM_BUS */
        if (ret)
                ret = CMD_RET_FAILURE;
index 2b74a98..a12ac70 100644 (file)
--- a/cmd/ubi.c
+++ b/cmd/ubi.c
@@ -101,7 +101,6 @@ static int ubi_check(char *name)
        return 1;
 }
 
-
 static int verify_mkvol_req(const struct ubi_device *ubi,
                            const struct ubi_mkvol_req *req)
 {
@@ -415,7 +414,7 @@ static int ubi_dev_scan(struct mtd_info *info, const char *vid_header_offset)
        return 0;
 }
 
-int ubi_detach(void)
+static int ubi_detach(void)
 {
 #ifdef CONFIG_CMD_UBIFS
        /*
@@ -473,7 +472,6 @@ static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
        if (argc < 2)
                return CMD_RET_USAGE;
 
-
        if (strcmp(argv[1], "detach") == 0) {
                if (argc < 2)
                        return CMD_RET_USAGE;
@@ -481,7 +479,6 @@ static int do_ubi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                return ubi_detach();
        }
 
-
        if (strcmp(argv[1], "part") == 0) {
                const char *vid_header_offset = NULL;
 
index 835b724..149a722 100644 (file)
@@ -24,7 +24,6 @@
 #include <os.h>
 #include <post.h>
 #include <relocate.h>
-#include <spi.h>
 #ifdef CONFIG_SPL
 #include <spl.h>
 #endif
@@ -262,16 +261,6 @@ __weak int init_func_vid(void)
 }
 #endif
 
-#if defined(CONFIG_HARD_SPI)
-static int init_func_spi(void)
-{
-       puts("SPI:   ");
-       spi_init();
-       puts("ready\n");
-       return 0;
-}
-#endif
-
 static int setup_mon_len(void)
 {
 #if defined(__ARM__) || defined(__MICROBLAZE__)
@@ -913,9 +902,6 @@ static const init_fnc_t init_sequence_f[] = {
 #if defined(CONFIG_VID) && !defined(CONFIG_SPL)
        init_func_vid,
 #endif
-#if defined(CONFIG_HARD_SPI)
-       init_func_spi,
-#endif
        announce_dram_init,
        dram_init,              /* configure available RAM banks */
 #ifdef CONFIG_POST
index 21d3b3c..5f3d27a 100644 (file)
@@ -36,7 +36,6 @@
 #include <onenand_uboot.h>
 #include <scsi.h>
 #include <serial.h>
-#include <spi.h>
 #include <stdio_dev.h>
 #include <timer.h>
 #include <trace.h>
@@ -379,20 +378,6 @@ static int initr_flash(void)
 }
 #endif
 
-#if defined(CONFIG_PPC) && !defined(CONFIG_DM_SPI)
-static int initr_spi(void)
-{
-       /* MPC8xx does this here */
-#ifdef CONFIG_MPC8XX_SPI
-#if !defined(CONFIG_ENV_IS_IN_EEPROM)
-       spi_init_f();
-#endif
-       spi_init_r();
-#endif
-       return 0;
-}
-#endif
-
 #ifdef CONFIG_CMD_NAND
 /* go init the NAND */
 static int initr_nand(void)
@@ -744,9 +729,6 @@ static init_fnc_t init_sequence_r[] = {
        /* initialize higher level parts of CPU like time base and timers */
        cpu_init_r,
 #endif
-#if defined(CONFIG_PPC) && !defined(CONFIG_DM_SPI)
-       initr_spi,
-#endif
 #ifdef CONFIG_CMD_NAND
        initr_nand,
 #endif
index 1955ffe..38c26f6 100644 (file)
@@ -163,11 +163,6 @@ At this point you should be able to build U-Boot for your board with the
 empty SPI driver. You still have empty methods in your driver, but we will
 write these one by one.
 
-If you have spi_init() functions or the like that are called from your
-board then the build will fail. Remove these calls and make a note of the
-init that needs to be done.
-
-
 7. Set up your platform data structure
 
 This will hold the information your driver to operate, like its hardware
index 5ca560c..d638f70 100644 (file)
 
 #define MTD_NAME_MAX_LEN 20
 
+void board_mtdparts_default(const char **mtdids, const char **mtdparts);
+
+static const char *get_mtdids(void)
+{
+       __maybe_unused const char *mtdparts = NULL;
+       const char *mtdids = env_get("mtdids");
+
+       if (mtdids)
+               return mtdids;
+
+#if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
+       board_mtdparts_default(&mtdids, &mtdparts);
+#elif defined(MTDIDS_DEFAULT)
+       mtdids = MTDIDS_DEFAULT;
+#elif defined(CONFIG_MTDIDS_DEFAULT)
+       mtdids = CONFIG_MTDIDS_DEFAULT;
+#endif
+
+       if (mtdids)
+               env_set("mtdids", mtdids);
+
+       return mtdids;
+}
 
 /**
  * mtd_search_alternate_name - Search an alternate name for @mtdname thanks to
@@ -34,7 +57,7 @@ int mtd_search_alternate_name(const char *mtdname, char *altname,
        const char *mtdids, *equal, *comma, *dev_id, *mtd_id;
        int dev_id_len, mtd_id_len;
 
-       mtdids = env_get("mtdids");
+       mtdids = get_mtdids();
        if (!mtdids)
                return -EINVAL;
 
@@ -92,30 +115,6 @@ static void mtd_probe_uclass_mtd_devs(void) { }
 #endif
 
 #if defined(CONFIG_MTD_PARTITIONS)
-extern void board_mtdparts_default(const char **mtdids,
-                                  const char **mtdparts);
-
-static const char *get_mtdids(void)
-{
-       __maybe_unused const char *mtdparts = NULL;
-       const char *mtdids = env_get("mtdids");
-
-       if (mtdids)
-               return mtdids;
-
-#if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
-       board_mtdparts_default(&mtdids, &mtdparts);
-#elif defined(MTDIDS_DEFAULT)
-       mtdids = MTDIDS_DEFAULT;
-#elif defined(CONFIG_MTDIDS_DEFAULT)
-       mtdids = CONFIG_MTDIDS_DEFAULT;
-#endif
-
-       if (mtdids)
-               env_set("mtdids", mtdids);
-
-       return mtdids;
-}
 
 #define MTDPARTS_MAXLEN         512
 
@@ -150,20 +149,74 @@ static const char *get_mtdparts(void)
        return mtdparts;
 }
 
+static int mtd_del_parts(struct mtd_info *mtd, bool quiet)
+{
+       int ret;
+
+       if (!mtd_has_partitions(mtd))
+               return 0;
+
+       /* do not delete partitions if they are in use. */
+       if (mtd_partitions_used(mtd)) {
+               if (!quiet)
+                       printf("\"%s\" partitions still in use, can't delete them\n",
+                              mtd->name);
+               return -EACCES;
+       }
+
+       ret = del_mtd_partitions(mtd);
+       if (ret)
+               return ret;
+
+       return 1;
+}
+
+static bool mtd_del_all_parts_failed;
+
+static void mtd_del_all_parts(void)
+{
+       struct mtd_info *mtd;
+       int ret = 0;
+
+       mtd_del_all_parts_failed = false;
+
+       /*
+        * It is not safe to remove entries from the mtd_for_each_device loop
+        * as it uses idr indexes and the partitions removal is done in bulk
+        * (all partitions of one device at the same time), so break and
+        * iterate from start each time a new partition is found and deleted.
+        */
+       do {
+               mtd_for_each_device(mtd) {
+                       ret = mtd_del_parts(mtd, false);
+                       if (ret > 0)
+                               break;
+                       else if (ret < 0)
+                               mtd_del_all_parts_failed = true;
+               }
+       } while (ret > 0);
+}
+
 int mtd_probe_devices(void)
 {
        static char *old_mtdparts;
        static char *old_mtdids;
        const char *mtdparts = get_mtdparts();
        const char *mtdids = get_mtdids();
-       bool remaining_partitions = true;
+       const char *mtdparts_next = mtdparts;
        struct mtd_info *mtd;
 
        mtd_probe_uclass_mtd_devs();
 
-       /* Check if mtdparts/mtdids changed since last call, otherwise: exit */
+       /*
+        * Check if mtdparts/mtdids changed, if the MTD dev list was updated
+        * or if our previous attempt to delete existing partititions failed.
+        * In any of these cases we want to update the partitions, otherwise,
+        * everything is up-to-date and we can return 0 directly.
+        */
        if ((!mtdparts && !old_mtdparts && !mtdids && !old_mtdids) ||
            (mtdparts && old_mtdparts && mtdids && old_mtdids &&
+            !mtd_dev_list_updated() && !mtd_del_all_parts_failed &&
             !strcmp(mtdparts, old_mtdparts) &&
             !strcmp(mtdids, old_mtdids)))
                return 0;
@@ -174,55 +227,55 @@ int mtd_probe_devices(void)
        old_mtdparts = strdup(mtdparts);
        old_mtdids = strdup(mtdids);
 
-       /* If at least one partition is still in use, do not delete anything */
-       mtd_for_each_device(mtd) {
-               if (mtd->usecount) {
-                       printf("Partition \"%s\" already in use, aborting\n",
-                              mtd->name);
-                       return -EACCES;
-               }
-       }
+       /*
+        * Remove all old parts. Note that partition removal can fail in case
+        * one of the partition is still being used by an MTD user, so this
+        * does not guarantee that all old partitions are gone.
+        */
+       mtd_del_all_parts();
 
        /*
-        * Everything looks clear, remove all partitions. It is not safe to
-        * remove entries from the mtd_for_each_device loop as it uses idr
-        * indexes and the partitions removal is done in bulk (all partitions of
-        * one device at the same time), so break and iterate from start each
-        * time a new partition is found and deleted.
+        * Call mtd_dev_list_updated() to clear updates generated by our own
+        * parts removal loop.
         */
-       while (remaining_partitions) {
-               remaining_partitions = false;
-               mtd_for_each_device(mtd) {
-                       if (!mtd_is_partition(mtd) && mtd_has_partitions(mtd)) {
-                               del_mtd_partitions(mtd);
-                               remaining_partitions = true;
-                               break;
-                       }
-               }
-       }
+       mtd_dev_list_updated();
 
        /* If either mtdparts or mtdids is empty, then exit */
        if (!mtdparts || !mtdids)
                return 0;
 
        /* Start the parsing by ignoring the extra 'mtdparts=' prefix, if any */
-       if (strstr(mtdparts, "mtdparts="))
+       if (!strncmp(mtdparts, "mtdparts=", sizeof("mtdparts=") - 1))
                mtdparts += 9;
 
        /* For each MTD device in mtdparts */
-       while (mtdparts[0] != '\0') {
+       for (; mtdparts[0] != '\0'; mtdparts = mtdparts_next) {
                char mtd_name[MTD_NAME_MAX_LEN], *colon;
                struct mtd_partition *parts;
-               int mtd_name_len, nparts;
-               int ret;
+               unsigned int mtd_name_len;
+               int nparts, ret;
+
+               mtdparts_next = strchr(mtdparts, ';');
+               if (!mtdparts_next)
+                       mtdparts_next = mtdparts + strlen(mtdparts);
+               else
+                       mtdparts_next++;
 
                colon = strchr(mtdparts, ':');
+               if (colon > mtdparts_next)
+                       colon = NULL;
+
                if (!colon) {
                        printf("Wrong mtdparts: %s\n", mtdparts);
                        return -EINVAL;
                }
 
-               mtd_name_len = colon - mtdparts;
+               mtd_name_len = (unsigned int)(colon - mtdparts);
+               if (mtd_name_len + 1 > sizeof(mtd_name)) {
+                       printf("MTD name too long: %s\n", mtdparts);
+                       return -EINVAL;
+               }
+
                strncpy(mtd_name, mtdparts, mtd_name_len);
                mtd_name[mtd_name_len] = '\0';
                /* Move the pointer forward (including the ':') */
@@ -249,15 +302,23 @@ int mtd_probe_devices(void)
                        if (ret || IS_ERR_OR_NULL(mtd)) {
                                printf("Could not find a valid device for %s\n",
                                       mtd_name);
-                               mtdparts = strchr(mtdparts, ';');
-                               if (mtdparts)
-                                       mtdparts++;
-
+                               mtdparts = mtdparts_next;
                                continue;
                        }
                }
 
                /*
+                * Call mtd_del_parts() again, even if it's already been called
+                * in mtd_del_all_parts(). We need to know if old partitions are
+                * still around (because they are still being used by someone),
+                * and if they are, we shouldn't create new partitions, so just
+                * skip this MTD device and try the next one.
+                */
+               ret = mtd_del_parts(mtd, true);
+               if (ret < 0)
+                       continue;
+
+               /*
                 * Parse the MTD device partitions. It will update the mtdparts
                 * pointer, create an array of parts (that must be freed), and
                 * return the number of partition structures in the array.
@@ -281,6 +342,12 @@ int mtd_probe_devices(void)
                put_mtd_device(mtd);
        }
 
+       /*
+        * Call mtd_dev_list_updated() to clear updates generated by our own
+        * parts registration loop.
+        */
+       mtd_dev_list_updated();
+
        return 0;
 }
 #else
index fb6c779..cb7ca38 100644 (file)
@@ -87,14 +87,17 @@ struct idr_layer {
 
 struct idr {
        struct idr_layer id[MAX_IDR_ID];
+       bool updated;
 };
 
 #define DEFINE_IDR(name)       struct idr name;
 
 void idr_remove(struct idr *idp, int id)
 {
-       if (idp->id[id].used)
+       if (idp->id[id].used) {
                idp->id[id].used = 0;
+               idp->updated = true;
+       }
 
        return;
 }
@@ -134,6 +137,7 @@ int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t gfp_mask)
                if (idl->used == 0) {
                        idl->used = 1;
                        idl->ptr = ptr;
+                       idp->updated = true;
                        return i;
                }
                i++;
@@ -155,6 +159,16 @@ struct mtd_info *__mtd_next_device(int i)
 }
 EXPORT_SYMBOL_GPL(__mtd_next_device);
 
+bool mtd_dev_list_updated(void)
+{
+       if (mtd_idr.updated) {
+               mtd_idr.updated = false;
+               return true;
+       }
+
+       return false;
+}
+
 #ifndef __UBOOT__
 static LIST_HEAD(mtd_notifiers);
 
@@ -514,6 +528,13 @@ int del_mtd_device(struct mtd_info *mtd)
        struct mtd_notifier *not;
 #endif
 
+       ret = del_mtd_partitions(mtd);
+       if (ret) {
+               debug("Failed to delete MTD partitions attached to %s (err %d)\n",
+                     mtd->name, ret);
+               return ret;
+       }
+
        mutex_lock(&mtd_table_mutex);
 
        if (idr_find(&mtd_idr, mtd->index) != mtd) {
index 4d2ac81..fd8d8e5 100644 (file)
@@ -63,6 +63,18 @@ char *kstrdup(const char *s, gfp_t gfp)
 #define MTD_SIZE_REMAINING             (~0LLU)
 #define MTD_OFFSET_NOT_SPECIFIED       (~0LLU)
 
+bool mtd_partitions_used(struct mtd_info *master)
+{
+       struct mtd_info *slave;
+
+       list_for_each_entry(slave, &master->partitions, node) {
+               if (slave->usecount)
+                       return true;
+       }
+
+       return false;
+}
+
 /**
  * mtd_parse_partition - Parse @mtdparts partition definition, fill @partition
  *                       with it and update the @mtdparts string pointer.
index 4c783f1..4d2712d 100644 (file)
@@ -195,6 +195,7 @@ struct pxa3xx_nand_info {
 
        int                     cs;
        int                     use_ecc;        /* use HW ECC ? */
+       int                     force_raw;      /* prevent use_ecc to be set */
        int                     ecc_bch;        /* using BCH ECC? */
        int                     use_spare;      /* use spare ? */
        int                     need_wait;
@@ -326,14 +327,14 @@ static struct nand_ecclayout ecc_layout_2KB_bch4bit = {
 static struct nand_ecclayout ecc_layout_2KB_bch8bit = {
        .eccbytes = 64,
        .eccpos = {
-               64,  65,  66,  67,  68,  69,  70,  71,
-               72,  73,  74,  75,  76,  77,  78,  79,
-               80,  81,  82,  83,  84,  85,  86,  87,
-               88,  89,  90,  91,  92,  93,  94,  95,
-               96,  97,  98,  99,  100, 101, 102, 103,
-               104, 105, 106, 107, 108, 109, 110, 111,
-               112, 113, 114, 115, 116, 117, 118, 119,
-               120, 121, 122, 123, 124, 125, 126, 127},
+               32, 33, 34, 35, 36, 37, 38, 39,
+               40, 41, 42, 43, 44, 45, 46, 47,
+               48, 49, 50, 51, 52, 53, 54, 55,
+               56, 57, 58, 59, 60, 61, 62, 63,
+               64, 65, 66, 67, 68, 69, 70, 71,
+               72, 73, 74, 75, 76, 77, 78, 79,
+               80, 81, 82, 83, 84, 85, 86, 87,
+               88, 89, 90, 91, 92, 93, 94, 95},
        .oobfree = { {1, 4}, {6, 26} }
 };
 
@@ -579,7 +580,7 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
 
 static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
 {
-       if (info->ecc_bch) {
+       if (info->ecc_bch && !info->force_raw) {
                u32 ts;
 
                /*
@@ -612,12 +613,22 @@ static void drain_fifo(struct pxa3xx_nand_info *info, void *data, int len)
 
 static void handle_data_pio(struct pxa3xx_nand_info *info)
 {
+       int data_len = info->step_chunk_size;
+
+       /*
+        * In raw mode, include the spare area and the ECC bytes that are not
+        * consumed by the controller in the data section. Do not reorganize
+        * here, do it in the ->read_page_raw() handler instead.
+        */
+       if (info->force_raw)
+               data_len += info->step_spare_size + info->ecc_size;
+
        switch (info->state) {
        case STATE_PIO_WRITING:
                if (info->step_chunk_size)
                        writesl(info->mmio_base + NDDB,
                                info->data_buff + info->data_buff_pos,
-                               DIV_ROUND_UP(info->step_chunk_size, 4));
+                               DIV_ROUND_UP(data_len, 4));
 
                if (info->step_spare_size)
                        writesl(info->mmio_base + NDDB,
@@ -628,7 +639,10 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
                if (info->step_chunk_size)
                        drain_fifo(info,
                                   info->data_buff + info->data_buff_pos,
-                                  DIV_ROUND_UP(info->step_chunk_size, 4));
+                                  DIV_ROUND_UP(data_len, 4));
+
+               if (info->force_raw)
+                       break;
 
                if (info->step_spare_size)
                        drain_fifo(info,
@@ -642,7 +656,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
        }
 
        /* Update buffer pointers for multi-page read/write */
-       info->data_buff_pos += info->step_chunk_size;
+       info->data_buff_pos += data_len;
        info->oob_buff_pos += info->step_spare_size;
 }
 
@@ -796,7 +810,8 @@ static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
        case NAND_CMD_READ0:
        case NAND_CMD_READOOB:
        case NAND_CMD_PAGEPROG:
-               info->use_ecc = 1;
+               if (!info->force_raw)
+                       info->use_ecc = 1;
                break;
        case NAND_CMD_PARAM:
                info->use_spare = 0;
@@ -866,7 +881,13 @@ static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
                 * which is either naked-read or last-read according to the
                 * state.
                 */
-               if (mtd->writesize == info->chunk_size) {
+               if (info->force_raw) {
+                       info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8) |
+                                      NDCB0_LEN_OVRD |
+                                      NDCB0_EXT_CMD_TYPE(ext_cmd_type);
+                       info->ndcb3 = info->step_chunk_size +
+                                     info->step_spare_size + info->ecc_size;
+               } else if (mtd->writesize == info->chunk_size) {
                        info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
                } else if (mtd->writesize > info->chunk_size) {
                        info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
@@ -1216,6 +1237,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
 {
        struct pxa3xx_nand_host *host = nand_get_controller_data(chip);
        struct pxa3xx_nand_info *info = host->info_data;
+       int bf;
 
        chip->read_buf(mtd, buf, mtd->writesize);
        chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
@@ -1223,12 +1245,30 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
        if (info->retcode == ERR_CORERR && info->use_ecc) {
                mtd->ecc_stats.corrected += info->ecc_err_cnt;
 
-       } else if (info->retcode == ERR_UNCORERR) {
+       } else if (info->retcode == ERR_UNCORERR && info->ecc_bch) {
                /*
-                * for blank page (all 0xff), HW will calculate its ECC as
-                * 0, which is different from the ECC information within
-                * OOB, ignore such uncorrectable errors
+                * Empty pages will trigger uncorrectable errors. Re-read the
+                * entire page in raw mode and check for bits not being "1".
+                * If there are more than the supported strength, then it means
+                * this is an actual uncorrectable error.
                 */
+               chip->ecc.read_page_raw(mtd, chip, buf, oob_required, page);
+               bf = nand_check_erased_ecc_chunk(buf, mtd->writesize,
+                                                chip->oob_poi, mtd->oobsize,
+                                                NULL, 0, chip->ecc.strength);
+               if (bf < 0) {
+                       mtd->ecc_stats.failed++;
+               } else if (bf) {
+                       mtd->ecc_stats.corrected += bf;
+                       info->max_bitflips = max_t(unsigned int,
+                                                  info->max_bitflips, bf);
+                       info->retcode = ERR_CORERR;
+               } else {
+                       info->retcode = ERR_NONE;
+               }
+
+       } else if (info->retcode == ERR_UNCORERR && !info->ecc_bch) {
+               /* Raw read is not supported with Hamming ECC engine */
                if (is_buf_blank(buf, mtd->writesize))
                        info->retcode = ERR_NONE;
                else
@@ -1238,6 +1278,69 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
        return info->max_bitflips;
 }
 
+static int pxa3xx_nand_read_page_raw(struct mtd_info *mtd,
+                                    struct nand_chip *chip, uint8_t *buf,
+                                    int oob_required, int page)
+{
+       struct pxa3xx_nand_host *host = chip->priv;
+       struct pxa3xx_nand_info *info = host->info_data;
+       int chunk, ecc_off_buf;
+
+       if (!info->ecc_bch)
+               return -ENOTSUPP;
+
+       /*
+        * Set the force_raw boolean, then re-call ->cmdfunc() that will run
+        * pxa3xx_nand_start(), which will actually disable the ECC engine.
+        */
+       info->force_raw = true;
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
+
+       ecc_off_buf = (info->nfullchunks * info->spare_size) +
+                     info->last_spare_size;
+       for (chunk = 0; chunk < info->nfullchunks; chunk++) {
+               chip->read_buf(mtd,
+                              buf + (chunk * info->chunk_size),
+                              info->chunk_size);
+               chip->read_buf(mtd,
+                              chip->oob_poi +
+                              (chunk * (info->spare_size)),
+                              info->spare_size);
+               chip->read_buf(mtd,
+                              chip->oob_poi + ecc_off_buf +
+                              (chunk * (info->ecc_size)),
+                              info->ecc_size - 2);
+       }
+
+       if (info->ntotalchunks > info->nfullchunks) {
+               chip->read_buf(mtd,
+                              buf + (info->nfullchunks * info->chunk_size),
+                              info->last_chunk_size);
+               chip->read_buf(mtd,
+                              chip->oob_poi +
+                              (info->nfullchunks * (info->spare_size)),
+                              info->last_spare_size);
+               chip->read_buf(mtd,
+                              chip->oob_poi + ecc_off_buf +
+                              (info->nfullchunks * (info->ecc_size)),
+                              info->ecc_size - 2);
+       }
+
+       info->force_raw = false;
+
+       return 0;
+}
+
+static int pxa3xx_nand_read_oob_raw(struct mtd_info *mtd,
+                                   struct nand_chip *chip, int page)
+{
+       /* Invalidate page cache */
+       chip->pagebuf = -1;
+
+       return chip->ecc.read_page_raw(mtd, chip, chip->buffers->databuf, true,
+                                      page);
+}
+
 static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
 {
        struct nand_chip *chip = mtd_to_nand(mtd);
@@ -1488,7 +1591,7 @@ static int pxa_ecc_init(struct pxa3xx_nand_info *info,
                info->chunk_size = 1024;
                info->spare_size = 0;
                info->last_chunk_size = 1024;
-               info->last_spare_size = 64;
+               info->last_spare_size = 32;
                info->ecc_size = 32;
                ecc->mode = NAND_ECC_HW;
                ecc->size = info->chunk_size;
@@ -1669,6 +1772,8 @@ static int alloc_nand_resource(struct pxa3xx_nand_info *info)
 
                nand_set_controller_data(chip, host);
                chip->ecc.read_page     = pxa3xx_nand_read_page_hwecc;
+               chip->ecc.read_page_raw = pxa3xx_nand_read_page_raw;
+               chip->ecc.read_oob_raw  = pxa3xx_nand_read_oob_raw;
                chip->ecc.write_page    = pxa3xx_nand_write_page_hwecc;
                chip->controller        = &info->controller;
                chip->waitfunc          = pxa3xx_nand_waitfunc;
index 58d7e44..68c3600 100644 (file)
@@ -10,6 +10,7 @@
 #include <spi_flash.h>
 
 static struct mtd_info sf_mtd_info;
+static bool sf_mtd_registered;
 static char sf_mtd_name[8];
 
 static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
@@ -17,6 +18,9 @@ static int spi_flash_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
        struct spi_flash *flash = mtd->priv;
        int err;
 
+       if (!flash)
+               return -ENODEV;
+
        instr->state = MTD_ERASING;
 
        err = spi_flash_erase(flash, instr->addr, instr->len);
@@ -38,6 +42,9 @@ static int spi_flash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
        struct spi_flash *flash = mtd->priv;
        int err;
 
+       if (!flash)
+               return -ENODEV;
+
        err = spi_flash_read(flash, from, len, buf);
        if (!err)
                *retlen = len;
@@ -51,6 +58,9 @@ static int spi_flash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
        struct spi_flash *flash = mtd->priv;
        int err;
 
+       if (!flash)
+               return -ENODEV;
+
        err = spi_flash_write(flash, to, len, buf);
        if (!err)
                *retlen = len;
@@ -73,6 +83,17 @@ static int spi_flash_mtd_number(void)
 
 int spi_flash_mtd_register(struct spi_flash *flash)
 {
+       int ret;
+
+       if (sf_mtd_registered) {
+               ret = del_mtd_device(&sf_mtd_info);
+               if (ret)
+                       return ret;
+
+               sf_mtd_registered = false;
+       }
+
+       sf_mtd_registered = false;
        memset(&sf_mtd_info, 0, sizeof(sf_mtd_info));
        sprintf(sf_mtd_name, "nor%d", spi_flash_mtd_number());
 
@@ -94,10 +115,33 @@ int spi_flash_mtd_register(struct spi_flash *flash)
        sf_mtd_info.numeraseregions = 0;
        sf_mtd_info.erasesize = flash->sector_size;
 
-       return add_mtd_device(&sf_mtd_info);
+       ret = add_mtd_device(&sf_mtd_info);
+       if (!ret)
+               sf_mtd_registered = true;
+
+       return ret;
 }
 
 void spi_flash_mtd_unregister(void)
 {
-       del_mtd_device(&sf_mtd_info);
+       int ret;
+
+       if (!sf_mtd_registered)
+               return;
+
+       ret = del_mtd_device(&sf_mtd_info);
+       if (!ret) {
+               sf_mtd_registered = false;
+               return;
+       }
+
+       /*
+        * Setting mtd->priv to NULL is the best we can do. Thanks to that,
+        * the MTD layer can still call mtd hooks without risking a
+        * use-after-free bug. Still, things should be fixed to prevent the
+        * spi_flash object from being destroyed when del_mtd_device() fails.
+        */
+       sf_mtd_info.priv = NULL;
+       printf("Failed to unregister MTD %s and the spi_flash object is going away: you're in deep trouble!",
+              sf_mtd_info.name);
 }
index 5a2e932..00f8558 100644 (file)
@@ -144,6 +144,14 @@ static int spi_flash_std_probe(struct udevice *dev)
        return spi_flash_probe_slave(flash);
 }
 
+static int spi_flash_std_remove(struct udevice *dev)
+{
+#ifdef CONFIG_SPI_FLASH_MTD
+       spi_flash_mtd_unregister();
+#endif
+       return 0;
+}
+
 static const struct dm_spi_flash_ops spi_flash_std_ops = {
        .read = spi_flash_std_read,
        .write = spi_flash_std_write,
@@ -161,6 +169,7 @@ U_BOOT_DRIVER(spi_flash_std) = {
        .id             = UCLASS_SPI_FLASH,
        .of_match       = spi_flash_std_ids,
        .probe          = spi_flash_std_probe,
+       .remove         = spi_flash_std_remove,
        .priv_auto_alloc_size = sizeof(struct spi_flash),
        .ops            = &spi_flash_std_ops,
 };
index b38f4df..aecd290 100644 (file)
@@ -77,9 +77,6 @@ static inline struct e1000_hw *e1000_hw_from_spi(struct spi_slave *spi)
        return container_of(spi, struct e1000_hw, spi);
 }
 
-/* Not sure why all of these are necessary */
-void spi_init(void)   { /* Nothing to do */ }
-
 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
                unsigned int max_hz, unsigned int mode)
 {
index 516188e..a7bb5b3 100644 (file)
@@ -116,6 +116,20 @@ config ICH_SPI
          access the SPI NOR flash on platforms embedding this Intel
          ICH IP core.
 
+config MESON_SPIFC
+       bool "Amlogic Meson SPI Flash Controller driver"
+       depends on ARCH_MESON
+       help
+         Enable the Amlogic Meson SPI Flash Controller SPIFC) driver.
+         This driver can be used to access the SPI NOR flash chips on
+         Amlogic Meson SoCs.
+
+config MPC8XX_SPI
+       bool "MPC8XX SPI Driver"
+       depends on MPC8xx
+       help
+         Enable support for SPI on MPC8XX
+
 config MT7621_SPI
        bool "MediaTek MT7621 SPI driver"
        depends on ARCH_MT7620
@@ -124,6 +138,13 @@ config MT7621_SPI
          the SPI NOR flash on platforms embedding this Ralink / MediaTek
          SPI core, like MT7621/7628/7688.
 
+config MTK_QSPI
+       bool "Mediatek QSPI driver"
+       help
+         Enable the Mediatek QSPI driver. This driver can be
+         used to access the SPI NOR flash on platforms embedding this
+         Mediatek QSPI IP core.
+
 config MVEBU_A3700_SPI
        bool "Marvell Armada 3700 SPI driver"
        select CLK_ARMADA_3720
@@ -328,12 +349,6 @@ config LPC32XX_SSP
        help
          Enable support for SPI on LPC32xx
 
-config MPC8XX_SPI
-       bool "MPC8XX SPI Driver"
-       depends on MPC8xx
-       help
-         Enable support for SPI on MPC8XX
-
 config MPC8XXX_SPI
        bool "MPC8XXX SPI Driver"
        help
index 7242ea7..392a925 100644 (file)
@@ -31,8 +31,10 @@ obj-$(CONFIG_FSL_QSPI) += fsl_qspi.o
 obj-$(CONFIG_ICH_SPI) +=  ich.o
 obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
 obj-$(CONFIG_LPC32XX_SSP) += lpc32xx_ssp.o
+obj-$(CONFIG_MESON_SPIFC) += meson_spifc.o
 obj-$(CONFIG_MPC8XX_SPI) += mpc8xx_spi.o
 obj-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
+obj-$(CONFIG_MTK_QSPI) += mtk_qspi.o
 obj-$(CONFIG_MT7621_SPI) += mt7621_spi.o
 obj-$(CONFIG_MVEBU_A3700_SPI) += mvebu_a3700_spi.o
 obj-$(CONFIG_MXC_SPI) += mxc_spi.o
index 1db8bbe..cf4de9e 100644 (file)
@@ -34,11 +34,6 @@ static int spi_has_wdrbt(struct atmel_spi_slave *slave)
        return (ATMEL_SPI_VERSION_REV(ver) >= 0x210);
 }
 
-void spi_init()
-{
-
-}
-
 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
                        unsigned int max_hz, unsigned int mode)
 {
index 07fa5e3..4d2c106 100644 (file)
@@ -388,11 +388,6 @@ void spi_cs_deactivate(struct spi_slave *slave)
        /* do nothing */
 }
 
-void spi_init(void)
-{
-       /* do nothing */
-}
-
 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
                        unsigned int max_hz, unsigned int mode)
 {
index f7ed8fb..764c942 100644 (file)
@@ -390,11 +390,6 @@ static int fsl_dspi_cfg_speed(struct fsl_dspi_priv *priv, uint speed)
        return 0;
 }
 #ifndef CONFIG_DM_SPI
-void spi_init(void)
-{
-       /* Nothing to do */
-}
-
 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
 {
        if (((cs >= 0) && (cs < 8)) && ((bus >= 0) && (bus < 8)))
index e994159..7444ae1 100644 (file)
@@ -118,11 +118,6 @@ void spi_free_slave(struct spi_slave *slave)
        free(fsl);
 }
 
-void spi_init(void)
-{
-
-}
-
 int spi_claim_bus(struct spi_slave *slave)
 {
        struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave);
index ce12eee..4b09366 100644 (file)
@@ -47,15 +47,6 @@ static inline struct lpc32xx_spi_slave *to_lpc32xx_spi_slave(
        return container_of(slave, struct lpc32xx_spi_slave, slave);
 }
 
-/* spi_init is called during boot when CONFIG_CMD_SPI is defined */
-void spi_init(void)
-{
-       /*
-        *  nothing to do: clocking was enabled in lpc32xx_ssp_enable()
-        * and configuration will be done in spi_setup_slave()
-       */
-}
-
 /* the following is called in sequence by do_spi_xfer() */
 
 struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
diff --git a/drivers/spi/meson_spifc.c b/drivers/spi/meson_spifc.c
new file mode 100644 (file)
index 0000000..3d55169
--- /dev/null
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
+ * Copyright (C) 2018 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ *
+ * Amlogic Meson SPI Flash Controller driver
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <clk.h>
+#include <dm.h>
+#include <regmap.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/bitfield.h>
+
+/* register map */
+#define REG_CMD                        0x00
+#define REG_ADDR               0x04
+#define REG_CTRL               0x08
+#define REG_CTRL1              0x0c
+#define REG_STATUS             0x10
+#define REG_CTRL2              0x14
+#define REG_CLOCK              0x18
+#define REG_USER               0x1c
+#define REG_USER1              0x20
+#define REG_USER2              0x24
+#define REG_USER3              0x28
+#define REG_USER4              0x2c
+#define REG_SLAVE              0x30
+#define REG_SLAVE1             0x34
+#define REG_SLAVE2             0x38
+#define REG_SLAVE3             0x3c
+#define REG_C0                 0x40
+#define REG_B8                 0x60
+#define REG_MAX                        0x7c
+
+/* register fields */
+#define CMD_USER               BIT(18)
+#define CTRL_ENABLE_AHB                BIT(17)
+#define CLOCK_SOURCE           BIT(31)
+#define CLOCK_DIV_SHIFT                12
+#define CLOCK_DIV_MASK         (0x3f << CLOCK_DIV_SHIFT)
+#define CLOCK_CNT_HIGH_SHIFT   6
+#define CLOCK_CNT_HIGH_MASK    (0x3f << CLOCK_CNT_HIGH_SHIFT)
+#define CLOCK_CNT_LOW_SHIFT    0
+#define CLOCK_CNT_LOW_MASK     (0x3f << CLOCK_CNT_LOW_SHIFT)
+#define USER_DIN_EN_MS         BIT(0)
+#define USER_CMP_MODE          BIT(2)
+#define USER_CLK_NOT_INV       BIT(7)
+#define USER_UC_DOUT_SEL       BIT(27)
+#define USER_UC_DIN_SEL                BIT(28)
+#define USER_UC_MASK           ((BIT(5) - 1) << 27)
+#define USER1_BN_UC_DOUT_SHIFT 17
+#define USER1_BN_UC_DOUT_MASK  (0xff << 16)
+#define USER1_BN_UC_DIN_SHIFT  8
+#define USER1_BN_UC_DIN_MASK   (0xff << 8)
+#define USER4_CS_POL_HIGH      BIT(23)
+#define USER4_IDLE_CLK_HIGH    BIT(29)
+#define USER4_CS_ACT           BIT(30)
+#define SLAVE_TRST_DONE                BIT(4)
+#define SLAVE_OP_MODE          BIT(30)
+#define SLAVE_SW_RST           BIT(31)
+
+#define SPIFC_BUFFER_SIZE      64
+
+struct meson_spifc_priv {
+       struct regmap                   *regmap;
+       struct clk                      clk;
+};
+
+/**
+ * meson_spifc_drain_buffer() - copy data from device buffer to memory
+ * @spifc:     the Meson SPI device
+ * @buf:       the destination buffer
+ * @len:       number of bytes to copy
+ */
+static void meson_spifc_drain_buffer(struct meson_spifc_priv *spifc,
+                                    u8 *buf, int len)
+{
+       u32 data;
+       int i = 0;
+
+       while (i < len) {
+               regmap_read(spifc->regmap, REG_C0 + i, &data);
+
+               if (len - i >= 4) {
+                       *((u32 *)buf) = data;
+                       buf += 4;
+               } else {
+                       memcpy(buf, &data, len - i);
+                       break;
+               }
+               i += 4;
+       }
+}
+
+/**
+ * meson_spifc_fill_buffer() - copy data from memory to device buffer
+ * @spifc:     the Meson SPI device
+ * @buf:       the source buffer
+ * @len:       number of bytes to copy
+ */
+static void meson_spifc_fill_buffer(struct meson_spifc_priv *spifc,
+                                   const u8 *buf, int len)
+{
+       u32 data = 0;
+       int i = 0;
+
+       while (i < len) {
+               if (len - i >= 4)
+                       data = *(u32 *)buf;
+               else
+                       memcpy(&data, buf, len - i);
+
+               regmap_write(spifc->regmap, REG_C0 + i, data);
+
+               buf += 4;
+               i += 4;
+       }
+}
+
+/**
+ * meson_spifc_txrx() - transfer a chunk of data
+ * @spifc:     the Meson SPI device
+ * @dout:      data buffer for TX
+ * @din:       data buffer for RX
+ * @offset:    offset of the data to transfer
+ * @len:       length of the data to transfer
+ * @last_xfer: whether this is the last transfer of the message
+ * @last_chunk:        whether this is the last chunk of the transfer
+ * Return:     0 on success, a negative value on error
+ */
+static int meson_spifc_txrx(struct meson_spifc_priv *spifc,
+                           const u8 *dout, u8 *din, int offset,
+                           int len, bool last_xfer, bool last_chunk)
+{
+       bool keep_cs = true;
+       u32 data;
+       int ret;
+
+       if (dout)
+               meson_spifc_fill_buffer(spifc, dout + offset, len);
+
+       /* enable DOUT stage */
+       regmap_update_bits(spifc->regmap, REG_USER, USER_UC_MASK,
+                          USER_UC_DOUT_SEL);
+       regmap_write(spifc->regmap, REG_USER1,
+                    (8 * len - 1) << USER1_BN_UC_DOUT_SHIFT);
+
+       /* enable data input during DOUT */
+       regmap_update_bits(spifc->regmap, REG_USER, USER_DIN_EN_MS,
+                          USER_DIN_EN_MS);
+
+       if (last_chunk && last_xfer)
+               keep_cs = false;
+
+       regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_ACT,
+                          keep_cs ? USER4_CS_ACT : 0);
+
+       /* clear transition done bit */
+       regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_TRST_DONE, 0);
+       /* start transfer */
+       regmap_update_bits(spifc->regmap, REG_CMD, CMD_USER, CMD_USER);
+
+       /* wait for the current operation to terminate */
+       ret = regmap_read_poll_timeout(spifc->regmap, REG_SLAVE, data,
+                                      (data & SLAVE_TRST_DONE),
+                                      0, 5 * CONFIG_SYS_HZ);
+
+       if (!ret && din)
+               meson_spifc_drain_buffer(spifc, din + offset, len);
+
+       return ret;
+}
+
+/**
+ * meson_spifc_xfer() - perform a single transfer
+ * @dev:       the SPI controller device
+ * @bitlen:    length of the transfer
+ * @dout:      data buffer for TX
+ * @din:       data buffer for RX
+ * @flags:     transfer flags
+ * Return:     0 on success, a negative value on error
+ */
+static int meson_spifc_xfer(struct udevice *slave, unsigned int bitlen,
+                           const void *dout, void *din, unsigned long flags)
+{
+       struct meson_spifc_priv *spifc = dev_get_priv(slave->parent);
+       int blen = bitlen / 8;
+       int len, done = 0, ret = 0;
+
+       if (bitlen % 8)
+               return -EINVAL;
+
+       debug("xfer len %d (%d) dout %p din %p\n", bitlen, blen, dout, din);
+
+       regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 0);
+
+       while (done < blen && !ret) {
+               len = min_t(int, blen - done, SPIFC_BUFFER_SIZE);
+               ret = meson_spifc_txrx(spifc, dout, din, done, len,
+                                      flags & SPI_XFER_END,
+                                      done + len >= blen);
+               done += len;
+       }
+
+       regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB,
+                          CTRL_ENABLE_AHB);
+
+       return ret;
+}
+
+/**
+ * meson_spifc_set_speed() - program the clock divider
+ * @dev:       the SPI controller device
+ * @speed:     desired speed in Hz
+ */
+static int meson_spifc_set_speed(struct udevice *dev, uint speed)
+{
+       struct meson_spifc_priv *spifc = dev_get_priv(dev);
+       unsigned long parent, value;
+       int n;
+
+       parent = clk_get_rate(&spifc->clk);
+       n = max_t(int, parent / speed - 1, 1);
+
+       debug("parent %lu, speed %u, n %d\n", parent, speed, n);
+
+       value = (n << CLOCK_DIV_SHIFT) & CLOCK_DIV_MASK;
+       value |= (n << CLOCK_CNT_LOW_SHIFT) & CLOCK_CNT_LOW_MASK;
+       value |= (((n + 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT) &
+               CLOCK_CNT_HIGH_MASK;
+
+       regmap_write(spifc->regmap, REG_CLOCK, value);
+
+       return 0;
+}
+
+/**
+ * meson_spifc_set_mode() - setups the SPI bus mode
+ * @dev:       the SPI controller device
+ * @mode:      desired mode bitfield
+ * Return:     0 on success, -ENODEV on error
+ */
+static int meson_spifc_set_mode(struct udevice *dev, uint mode)
+{
+       struct meson_spifc_priv *spifc = dev_get_priv(dev);
+
+       if (mode & (SPI_CPHA | SPI_RX_QUAD | SPI_RX_DUAL |
+                   SPI_TX_QUAD | SPI_TX_DUAL))
+               return -ENODEV;
+
+       regmap_update_bits(spifc->regmap, REG_USER, USER_CLK_NOT_INV,
+                          mode & SPI_CPOL ? USER_CLK_NOT_INV : 0);
+
+       regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_POL_HIGH,
+                          mode & SPI_CS_HIGH ? USER4_CS_POL_HIGH : 0);
+
+       return 0;
+}
+
+/**
+ * meson_spifc_hw_init() - reset and initialize the SPI controller
+ * @spifc:     the Meson SPI device
+ */
+static void meson_spifc_hw_init(struct meson_spifc_priv *spifc)
+{
+       /* reset device */
+       regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_SW_RST,
+                          SLAVE_SW_RST);
+       /* disable compatible mode */
+       regmap_update_bits(spifc->regmap, REG_USER, USER_CMP_MODE, 0);
+       /* set master mode */
+       regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_OP_MODE, 0);
+}
+
+static const struct dm_spi_ops meson_spifc_ops = {
+       .xfer           = meson_spifc_xfer,
+       .set_speed      = meson_spifc_set_speed,
+       .set_mode       = meson_spifc_set_mode,
+};
+
+static int meson_spifc_probe(struct udevice *dev)
+{
+       struct meson_spifc_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap);
+       if (ret)
+               return ret;
+
+       ret = clk_get_by_index(dev, 0, &priv->clk);
+       if (ret)
+               return ret;
+
+       ret = clk_enable(&priv->clk);
+       if (ret)
+               return ret;
+
+       meson_spifc_hw_init(priv);
+
+       return 0;
+}
+
+static const struct udevice_id meson_spifc_ids[] = {
+       { .compatible = "amlogic,meson-gxbb-spifc", },
+       { }
+};
+
+U_BOOT_DRIVER(meson_spifc) = {
+       .name           = "meson_spifc",
+       .id             = UCLASS_SPI,
+       .of_match       = meson_spifc_ids,
+       .ops            = &meson_spifc_ops,
+       .probe          = meson_spifc_probe,
+       .priv_auto_alloc_size = sizeof(struct meson_spifc_priv),
+};
diff --git a/drivers/spi/mtk_qspi.c b/drivers/spi/mtk_qspi.c
new file mode 100644 (file)
index 0000000..b510733
--- /dev/null
@@ -0,0 +1,359 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018  MediaTek, Inc.
+ * Author : Guochun.Mao@mediatek.com
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+
+/* Register Offset */
+struct mtk_qspi_regs {
+       u32 cmd;
+       u32 cnt;
+       u32 rdsr;
+       u32 rdata;
+       u32 radr[3];
+       u32 wdata;
+       u32 prgdata[6];
+       u32 shreg[10];
+       u32 cfg[2];
+       u32 shreg10;
+       u32 mode_mon;
+       u32 status[4];
+       u32 flash_time;
+       u32 flash_cfg;
+       u32 reserved_0[3];
+       u32 sf_time;
+       u32 pp_dw_data;
+       u32 reserved_1;
+       u32 delsel_0[2];
+       u32 intrstus;
+       u32 intren;
+       u32 reserved_2;
+       u32 cfg3;
+       u32 reserved_3;
+       u32 chksum;
+       u32 aaicmd;
+       u32 wrprot;
+       u32 radr3;
+       u32 dual;
+       u32 delsel_1[3];
+};
+
+struct mtk_qspi_platdata {
+       fdt_addr_t reg_base;
+       fdt_addr_t mem_base;
+};
+
+struct mtk_qspi_priv {
+       struct mtk_qspi_regs *regs;
+       unsigned long *mem_base;
+       u8 op;
+       u8 tx[3]; /* only record max 3 bytes paras, when it's address. */
+       u32 txlen; /* dout buffer length  - op code length */
+       u8 *rx;
+       u32 rxlen;
+};
+
+#define MTK_QSPI_CMD_POLLINGREG_US 500000
+#define MTK_QSPI_WRBUF_SIZE        256
+#define MTK_QSPI_COMMAND_ENABLE    0x30
+
+/* NOR flash controller commands */
+#define MTK_QSPI_RD_TRIGGER        BIT(0)
+#define MTK_QSPI_READSTATUS        BIT(1)
+#define MTK_QSPI_PRG_CMD           BIT(2)
+#define MTK_QSPI_WR_TRIGGER        BIT(4)
+#define MTK_QSPI_WRITESTATUS       BIT(5)
+#define MTK_QSPI_AUTOINC           BIT(7)
+
+#define MTK_QSPI_MAX_RX_TX_SHIFT   0x6
+#define MTK_QSPI_MAX_SHIFT         0x8
+
+#define MTK_QSPI_WR_BUF_ENABLE     0x1
+#define MTK_QSPI_WR_BUF_DISABLE    0x0
+
+static int mtk_qspi_execute_cmd(struct mtk_qspi_priv *priv, u8 cmd)
+{
+       u8 tmp;
+       u8 val = cmd & ~MTK_QSPI_AUTOINC;
+
+       writeb(cmd, &priv->regs->cmd);
+
+       return readb_poll_timeout(&priv->regs->cmd, tmp, !(val & tmp),
+                                 MTK_QSPI_CMD_POLLINGREG_US);
+}
+
+static int mtk_qspi_tx_rx(struct mtk_qspi_priv *priv)
+{
+       int len = 1 + priv->txlen + priv->rxlen;
+       int i, ret, idx;
+
+       if (len > MTK_QSPI_MAX_SHIFT)
+               return -ERR_INVAL;
+
+       writeb(len * 8, &priv->regs->cnt);
+
+       /* start at PRGDATA5, go down to PRGDATA0 */
+       idx = MTK_QSPI_MAX_RX_TX_SHIFT - 1;
+
+       /* opcode */
+       writeb(priv->op, &priv->regs->prgdata[idx]);
+       idx--;
+
+       /* program TX data */
+       for (i = 0; i < priv->txlen; i++, idx--)
+               writeb(priv->tx[i], &priv->regs->prgdata[idx]);
+
+       /* clear out rest of TX registers */
+       while (idx >= 0) {
+               writeb(0, &priv->regs->prgdata[idx]);
+               idx--;
+       }
+
+       ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_PRG_CMD);
+       if (ret)
+               return ret;
+
+       /* restart at first RX byte */
+       idx = priv->rxlen - 1;
+
+       /* read out RX data */
+       for (i = 0; i < priv->rxlen; i++, idx--)
+               priv->rx[i] = readb(&priv->regs->shreg[idx]);
+
+       return 0;
+}
+
+static int mtk_qspi_read(struct mtk_qspi_priv *priv,
+                        u32 addr, u8 *buf, u32 len)
+{
+       memcpy(buf, (u8 *)priv->mem_base + addr, len);
+       return 0;
+}
+
+static void mtk_qspi_set_addr(struct mtk_qspi_priv *priv, u32 addr)
+{
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               writeb(addr & 0xff, &priv->regs->radr[i]);
+               addr >>= 8;
+       }
+}
+
+static int mtk_qspi_write_single_byte(struct mtk_qspi_priv *priv,
+                                     u32 addr, u32 length, const u8 *data)
+{
+       int i, ret;
+
+       mtk_qspi_set_addr(priv, addr);
+
+       for (i = 0; i < length; i++) {
+               writeb(*data++, &priv->regs->wdata);
+               ret = mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static int mtk_qspi_write_buffer(struct mtk_qspi_priv *priv, u32 addr,
+                                const u8 *buf)
+{
+       int i, data;
+
+       mtk_qspi_set_addr(priv, addr);
+
+       for (i = 0; i < MTK_QSPI_WRBUF_SIZE; i += 4) {
+               data = buf[i + 3] << 24 | buf[i + 2] << 16 |
+                      buf[i + 1] << 8 | buf[i];
+               writel(data, &priv->regs->pp_dw_data);
+       }
+
+       return mtk_qspi_execute_cmd(priv, MTK_QSPI_WR_TRIGGER);
+}
+
+static int mtk_qspi_write(struct mtk_qspi_priv *priv,
+                         u32 addr, const u8 *buf, u32 len)
+{
+       int ret;
+
+       /* setting pre-fetch buffer for page program */
+       writel(MTK_QSPI_WR_BUF_ENABLE, &priv->regs->cfg[1]);
+       while (len >= MTK_QSPI_WRBUF_SIZE) {
+               ret = mtk_qspi_write_buffer(priv, addr, buf);
+               if (ret < 0)
+                       return ret;
+
+               len -= MTK_QSPI_WRBUF_SIZE;
+               addr += MTK_QSPI_WRBUF_SIZE;
+               buf += MTK_QSPI_WRBUF_SIZE;
+       }
+       /* disable pre-fetch buffer for page program */
+       writel(MTK_QSPI_WR_BUF_DISABLE, &priv->regs->cfg[1]);
+
+       if (len)
+               return mtk_qspi_write_single_byte(priv, addr, len, buf);
+
+       return 0;
+}
+
+static int mtk_qspi_claim_bus(struct udevice *dev)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static int mtk_qspi_release_bus(struct udevice *dev)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static int mtk_qspi_transfer(struct mtk_qspi_priv *priv, unsigned int bitlen,
+                            const void *dout, void *din, unsigned long flags)
+{
+       u32 bytes = DIV_ROUND_UP(bitlen, 8);
+       u32 addr;
+
+       if (!bytes)
+               return -ERR_INVAL;
+
+       if (dout) {
+               if (flags & SPI_XFER_BEGIN) {
+                       /* parse op code and potential paras first */
+                       priv->op = *(u8 *)dout;
+                       if (bytes > 1)
+                               memcpy(priv->tx, (u8 *)dout + 1,
+                                      bytes <= 4 ? bytes - 1 : 3);
+                       priv->txlen = bytes - 1;
+               }
+
+               if (flags == SPI_XFER_ONCE) {
+                       /* operations without receiving or sending data.
+                        * for example: erase, write flash register or write
+                        * enable...
+                        */
+                       priv->rx = NULL;
+                       priv->rxlen = 0;
+                       return mtk_qspi_tx_rx(priv);
+               }
+
+               if (flags & SPI_XFER_END) {
+                       /* here, dout should be data to be written.
+                        * and priv->tx should be filled 3Bytes address.
+                        */
+                       addr = priv->tx[0] << 16 | priv->tx[1] << 8 |
+                              priv->tx[2];
+                       return mtk_qspi_write(priv, addr, (u8 *)dout, bytes);
+               }
+       }
+
+       if (din) {
+               if (priv->txlen >= 3) {
+                       /* if run to here, priv->tx[] should be the address
+                        * where read data from,
+                        * and, din is the buf to receive data.
+                        */
+                       addr = priv->tx[0] << 16 | priv->tx[1] << 8 |
+                              priv->tx[2];
+                       return mtk_qspi_read(priv, addr, (u8 *)din, bytes);
+               }
+
+               /* should be reading flash's register */
+               priv->rx = (u8 *)din;
+               priv->rxlen = bytes;
+               return mtk_qspi_tx_rx(priv);
+       }
+
+       return 0;
+}
+
+static int mtk_qspi_xfer(struct udevice *dev, unsigned int bitlen,
+                        const void *dout, void *din, unsigned long flags)
+{
+       struct udevice *bus = dev->parent;
+       struct mtk_qspi_priv *priv = dev_get_priv(bus);
+
+       return  mtk_qspi_transfer(priv, bitlen, dout, din, flags);
+}
+
+static int mtk_qspi_set_speed(struct udevice *bus, uint speed)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static int mtk_qspi_set_mode(struct udevice *bus, uint mode)
+{
+       /* nothing to do */
+       return 0;
+}
+
+static int mtk_qspi_ofdata_to_platdata(struct udevice *bus)
+{
+       struct resource res_reg, res_mem;
+       struct mtk_qspi_platdata *plat = bus->platdata;
+       int ret;
+
+       ret = dev_read_resource_byname(bus, "reg_base", &res_reg);
+       if (ret) {
+               debug("can't get reg_base resource(ret = %d)\n", ret);
+               return -ENOMEM;
+       }
+
+       ret = dev_read_resource_byname(bus, "mem_base", &res_mem);
+       if (ret) {
+               debug("can't get map_base resource(ret = %d)\n", ret);
+               return -ENOMEM;
+       }
+
+       plat->mem_base = res_mem.start;
+       plat->reg_base = res_reg.start;
+
+       return 0;
+}
+
+static int mtk_qspi_probe(struct udevice *bus)
+{
+       struct mtk_qspi_platdata *plat = dev_get_platdata(bus);
+       struct mtk_qspi_priv *priv = dev_get_priv(bus);
+
+       priv->regs = (struct mtk_qspi_regs *)plat->reg_base;
+       priv->mem_base = (unsigned long *)plat->mem_base;
+
+       writel(MTK_QSPI_COMMAND_ENABLE, &priv->regs->wrprot);
+
+       return 0;
+}
+
+static const struct dm_spi_ops mtk_qspi_ops = {
+       .claim_bus      = mtk_qspi_claim_bus,
+       .release_bus    = mtk_qspi_release_bus,
+       .xfer           = mtk_qspi_xfer,
+       .set_speed      = mtk_qspi_set_speed,
+       .set_mode       = mtk_qspi_set_mode,
+};
+
+static const struct udevice_id mtk_qspi_ids[] = {
+       { .compatible = "mediatek,mt7629-qspi" },
+       { }
+};
+
+U_BOOT_DRIVER(mtk_qspi) = {
+       .name     = "mtk_qspi",
+       .id       = UCLASS_SPI,
+       .of_match = mtk_qspi_ids,
+       .ops      = &mtk_qspi_ops,
+       .ofdata_to_platdata       = mtk_qspi_ofdata_to_platdata,
+       .platdata_auto_alloc_size = sizeof(struct mtk_qspi_platdata),
+       .priv_auto_alloc_size     = sizeof(struct mtk_qspi_priv),
+       .probe    = mtk_qspi_probe,
+};
index 0dccc38..b263690 100644 (file)
@@ -400,10 +400,6 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
        return mxc_spi_xfer_internal(mxcs, bitlen, dout, din, flags);
 }
 
-void spi_init(void)
-{
-}
-
 /*
  * Some SPI devices require active chip-select over multiple
  * transactions, we achieve this using a GPIO. Still, the SPI
index 006fe82..5065e40 100644 (file)
@@ -39,10 +39,6 @@ static inline struct mxs_spi_slave *to_mxs_slave(struct spi_slave *slave)
        return container_of(slave, struct mxs_spi_slave, slave);
 }
 
-void spi_init(void)
-{
-}
-
 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
 {
        /* MXS SPI: 4 ports and 3 chip selects maximum */
index ecf54bb..c7fcf05 100644 (file)
@@ -461,11 +461,6 @@ static inline struct omap3_spi_priv *to_omap3_spi(struct spi_slave *slave)
        return container_of(slave, struct omap3_spi_priv, slave);
 }
 
-void spi_init(void)
-{
-       /* do nothing */
-}
-
 void spi_free_slave(struct spi_slave *slave)
 {
        struct omap3_spi_priv *priv = to_omap3_spi(slave);
index 86b71d2..32bb8c8 100644 (file)
@@ -9,16 +9,11 @@
  * Driver for ARM PL022 SPI Controller.
  */
 
-#include <asm/io.h>
 #include <clk.h>
 #include <common.h>
 #include <dm.h>
-#include <dm/platform_data/pl022_spi.h>
-#include <fdtdec.h>
-#include <linux/bitops.h>
-#include <linux/bug.h>
+#include <dm/platform_data/spi_pl022.h>
 #include <linux/io.h>
-#include <linux/kernel.h>
 #include <spi.h>
 
 #define SSP_CR0                0x000
 
 struct pl022_spi_slave {
        void *base;
-#if !CONFIG_IS_ENABLED(OF_PLATDATA)
-       struct clk clk;
-#else
        unsigned int freq;
-#endif
 };
 
 /*
@@ -96,30 +87,13 @@ static int pl022_is_supported(struct pl022_spi_slave *ps)
        return 0;
 }
 
-#if !CONFIG_IS_ENABLED(OF_PLATDATA)
-static int pl022_spi_ofdata_to_platdata(struct udevice *bus)
-{
-       struct pl022_spi_pdata *plat = bus->platdata;
-       const void *fdt = gd->fdt_blob;
-       int node = dev_of_offset(bus);
-
-       plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size);
-
-       return clk_get_by_index(bus, 0, &plat->clk);
-}
-#endif
-
 static int pl022_spi_probe(struct udevice *bus)
 {
        struct pl022_spi_pdata *plat = dev_get_platdata(bus);
        struct pl022_spi_slave *ps = dev_get_priv(bus);
 
        ps->base = ioremap(plat->addr, plat->size);
-#if !CONFIG_IS_ENABLED(OF_PLATDATA)
-       ps->clk = plat->clk;
-#else
        ps->freq = plat->freq;
-#endif
 
        /* Check the PL022 version */
        if (!pl022_is_supported(ps))
@@ -240,11 +214,7 @@ static int pl022_spi_set_speed(struct udevice *bus, uint speed)
        u16 scr = SSP_SCR_MIN, cr0 = 0, cpsr = SSP_CPSR_MIN, best_scr = scr,
            best_cpsr = cpsr;
        u32 min, max, best_freq = 0, tmp;
-#if !CONFIG_IS_ENABLED(OF_PLATDATA)
-       u32 rate = clk_get_rate(&ps->clk);
-#else
        u32 rate = ps->freq;
-#endif
        bool found = false;
 
        max = spi_rate(rate, SSP_CPSR_MIN, SSP_SCR_MIN);
@@ -316,6 +286,25 @@ static const struct dm_spi_ops pl022_spi_ops = {
 };
 
 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
+static int pl022_spi_ofdata_to_platdata(struct udevice *bus)
+{
+       struct pl022_spi_pdata *plat = bus->platdata;
+       const void *fdt = gd->fdt_blob;
+       int node = dev_of_offset(bus);
+       struct clk clkdev;
+       int ret;
+
+       plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size);
+
+       ret = clk_get_by_index(bus, 0, &clkdev);
+       if (ret)
+               return ret;
+
+       plat->freq = clk_get_rate(&clkdev);
+
+       return 0;
+}
+
 static const struct udevice_id pl022_spi_ids[] = {
        { .compatible = "arm,pl022-spi" },
        { }
@@ -327,11 +316,9 @@ U_BOOT_DRIVER(pl022_spi) = {
        .id     = UCLASS_SPI,
 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
        .of_match = pl022_spi_ids,
-#endif
-       .ops    = &pl022_spi_ops,
-#if !CONFIG_IS_ENABLED(OF_PLATDATA)
        .ofdata_to_platdata = pl022_spi_ofdata_to_platdata,
 #endif
+       .ops    = &pl022_spi_ops,
        .platdata_auto_alloc_size = sizeof(struct pl022_spi_pdata),
        .priv_auto_alloc_size = sizeof(struct pl022_spi_slave),
        .probe  = pl022_spi_probe,
index 64dfd74..5ae203d 100644 (file)
@@ -247,11 +247,6 @@ void spi_cs_deactivate(struct spi_slave *slave)
        sh_qspi_cs_deactivate(ss);
 }
 
-void spi_init(void)
-{
-       /* nothing to do */
-}
-
 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
                unsigned int max_hz, unsigned int mode)
 {
index bc2bd63..c58fd0e 100644 (file)
@@ -66,10 +66,6 @@ static int write_fifo_empty_wait(struct sh_spi *ss)
        return 0;
 }
 
-void spi_init(void)
-{
-}
-
 static void sh_spi_set_cs(struct sh_spi *ss, unsigned int cs)
 {
        unsigned long val = 0;
index 0aac0c0..cc5ab5f 100644 (file)
@@ -36,13 +36,6 @@ static inline struct soft_spi_slave *to_soft_spi(struct spi_slave *slave)
 /*                         Public Functions                            */
 /*=====================================================================*/
 
-/*-----------------------------------------------------------------------
- * Initialization
- */
-void spi_init (void)
-{
-}
-
 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
                unsigned int max_hz, unsigned int mode)
 {
index 2e14aba..b7bd243 100644 (file)
@@ -126,8 +126,6 @@ int atmel_df_pow2(int argc, char * const argv[])
                return 1;
        }
 
-       spi_init();
-
        while (1) {
                struct spi_slave *slave;
                char *line, *p;
index 5416041..c15050e 100644 (file)
 #endif
 
 #if !defined(CONFIG_CMD_SPI) || defined(CONFIG_DM_SPI)
-       EXPORT_FUNC(dummy, void, spi_init, void)
        EXPORT_FUNC(dummy, void, spi_setup_slave, void)
        EXPORT_FUNC(dummy, void, spi_free_slave, void)
 #else
-       EXPORT_FUNC(spi_init, void, spi_init, void)
        EXPORT_FUNC(spi_setup_slave, struct spi_slave *, spi_setup_slave,
                    unsigned int, unsigned int, unsigned int, unsigned int)
        EXPORT_FUNC(spi_free_slave, void, spi_free_slave, struct spi_slave *)
index a8e879e..faf512e 100644 (file)
@@ -287,13 +287,6 @@ int  eeprom_write (unsigned dev_addr, unsigned offset, uchar *buffer, unsigned c
 # define CONFIG_SYS_DEF_EEPROM_ADDR CONFIG_SYS_I2C_EEPROM_ADDR
 #endif
 
-#if defined(CONFIG_MPC8XX_SPI)
-extern void spi_init_f (void);
-extern void spi_init_r (void);
-extern ssize_t spi_read         (uchar *, int, uchar *, int);
-extern ssize_t spi_write (uchar *, int, uchar *, int);
-#endif
-
 /* $(BOARD)/$(BOARD).c */
 int board_early_init_f (void);
 int board_fix_fdt (void *rw_fdt_blob); /* manipulate the U-Boot fdt before its relocation */
index 11cb395..83d7745 100644 (file)
 
 /* DSPI and Serial Flash */
 #define CONFIG_CF_DSPI
-#define CONFIG_HARD_SPI
 #define CONFIG_SYS_SBFHDR_SIZE         0x7
 #ifdef CONFIG_CMD_SPI
 #      define CONFIG_SYS_DSPI_CS2
index f08896e..4b8ef38 100644 (file)
 /* DSPI and Serial Flash */
 #define CONFIG_CF_DSPI
 #define CONFIG_SERIAL_FLASH
-#define CONFIG_HARD_SPI
 #define CONFIG_SYS_SBFHDR_SIZE         0x7
 #ifdef CONFIG_CMD_SPI
 
index 16becbd..87cdbae 100644 (file)
 /* DSPI and Serial Flash */
 #define CONFIG_CF_DSPI
 #define CONFIG_SERIAL_FLASH
-#define CONFIG_HARD_SPI
 #define CONFIG_SYS_SBFHDR_SIZE         0x7
 #ifdef CONFIG_CMD_SPI
 
index 99b60d5..d41b7c4 100644 (file)
 
 /* DSPI and Serial Flash */
 #define CONFIG_CF_DSPI
-#define CONFIG_HARD_SPI
 #define CONFIG_SYS_SBFHDR_SIZE         0x13
 #ifdef CONFIG_CMD_SPI
 
index 524a10f..86a1233 100644 (file)
 #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1
 #define CONFIG_SYS_EEPROM_BUS_NUM      1
 
-/*
- * eSPI - Enhanced SPI
- */
-#define CONFIG_HARD_SPI
-
 #if defined(CONFIG_SPI_FLASH)
 #define CONFIG_SF_DEFAULT_SPEED        10000000
 #define CONFIG_SF_DEFAULT_MODE 0
index c9ed70c..eeb19a9 100644 (file)
 #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1
 #define CONFIG_SYS_EEPROM_BUS_NUM      1
 
-/*
- * eSPI - Enhanced SPI
- */
-
-#define CONFIG_HARD_SPI
-
 #define CONFIG_SF_DEFAULT_SPEED                10000000
 #define CONFIG_SF_DEFAULT_MODE         0
 
index 423ecd7..1bbe9d9 100644 (file)
 #define CONFIG_SYS_I2C_NCT72_ADDR      0x4C
 #define CONFIG_SYS_I2C_IDT6V49205B     0x69
 
-/*
- * eSPI - Enhanced SPI
- */
-#define CONFIG_HARD_SPI
-
 #define CONFIG_SF_DEFAULT_SPEED                10000000
 #define CONFIG_SF_DEFAULT_MODE         SPI_MODE_0
 
index 4adcd95..1908d35 100644 (file)
 #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 2
 
 #ifndef CONFIG_TRAILBLAZER
-/*
- * eSPI - Enhanced SPI
- */
-#define CONFIG_HARD_SPI
 
 #define CONFIG_SF_DEFAULT_SPEED                10000000
 #define CONFIG_SF_DEFAULT_MODE         0
index 28124dd..7e4c497 100644 (file)
  */
 #define CONFIG_TSEC1
 #define CONFIG_TSEC2
-#define CONFIG_HARD_SPI
 
 /*
  * NOR FLASH setup
 #define CONFIG_SYS_I2C_RTC_ADDR        0x51
 
 /*
- * SPI setup
- */
-#ifdef CONFIG_HARD_SPI
-#define CONFIG_SYS_GPIO1_PRELIM
-#define CONFIG_SYS_GPIO1_DIR           0x00000001
-#define CONFIG_SYS_GPIO1_DAT           0x00000001
-#endif
-
-/*
  * Ethernet setup
  */
 #ifdef CONFIG_TSEC1
index 7d84d16..4765764 100644 (file)
@@ -43,7 +43,6 @@
 #define CONFIG_MXC_UART
 #define CONFIG_MXC_UART_BASE   UART1_BASE
 
-#define CONFIG_HARD_SPI
 #define CONFIG_DEFAULT_SPI_BUS 1
 #define CONFIG_DEFAULT_SPI_MODE        (SPI_MODE_0 | SPI_CS_HIGH)
 
index 9e59e7a..4bb3621 100644 (file)
 
 /* SPI */
 #ifdef CONFIG_CMD_SPI
-#define CONFIG_HARD_SPI
 #define CONFIG_SPI_HALF_DUPLEX
 #endif
 
index 9465fb4..459ecf3 100644 (file)
 #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 3
 #define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 5
 
-/*
- * eSPI - Enhanced SPI
- */
-#define CONFIG_HARD_SPI
-
 #if defined(CONFIG_SPI_FLASH)
 #define CONFIG_SF_DEFAULT_SPEED        10000000
 #define CONFIG_SF_DEFAULT_MODE 0
index d018c22..4f48370 100644 (file)
@@ -214,11 +214,6 @@ extern unsigned long get_board_sys_clk(unsigned long dummy);
 #define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS 3
 #define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS 5
 
-/*
- * eSPI - Enhanced SPI
- */
-#define CONFIG_HARD_SPI
-
 #if defined(CONFIG_PCI)
 /*
  * General PCI
index c408db8..33ddc67 100644 (file)
@@ -66,7 +66,6 @@
 #define CONFIG_CF_DSPI
 #define CONFIG_SF_DEFAULT_SPEED                50000000
 #define CONFIG_SERIAL_FLASH
-#define CONFIG_HARD_SPI
 #define CONFIG_ENV_SPI_BUS             0
 #define CONFIG_ENV_SPI_CS              1
 
index 956f779..4e274bd 100644 (file)
 #define CONFIG_MXC_UART_BASE   UART1_BASE
 
 /*
- * SPI Configs
- * */
-#define CONFIG_HARD_SPI /* puts SPI: ready */
-
-/*
  * MMC Configs
  * */
 #define CONFIG_SYS_FSL_ESDHC_ADDR      MMC_SDHC1_BASE_ADDR
similarity index 64%
rename from include/dm/platform_data/pl022_spi.h
rename to include/dm/platform_data/spi_pl022.h
index 77fe6da..63a58ee 100644 (file)
@@ -7,22 +7,15 @@
  * in ofdata_to_platdata.
  */
 
-#ifndef __PL022_SPI_H__
-#define __PL022_SPI_H__
+#ifndef __spi_pl022_h
+#define __spi_pl022_h
 
-#if !CONFIG_IS_ENABLED(OF_PLATDATA)
-#include <clk.h>
-#endif
 #include <fdtdec.h>
 
 struct pl022_spi_pdata {
        fdt_addr_t addr;
        fdt_size_t size;
-#if !CONFIG_IS_ENABLED(OF_PLATDATA)
-       struct clk clk;
-#else
        unsigned int freq;
-#endif
 };
 
-#endif
+#endif /* __spi_pl022_h */
index 68e5915..cd1f557 100644 (file)
@@ -366,6 +366,8 @@ static inline bool mtd_has_partitions(const struct mtd_info *mtd)
        return !list_empty(&mtd->partitions);
 }
 
+bool mtd_partitions_used(struct mtd_info *master);
+
 int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
                      struct mtd_oob_region *oobecc);
 int mtd_ooblayout_find_eccregion(struct mtd_info *mtd, int eccbyte,
@@ -562,8 +564,23 @@ unsigned mtd_mmap_capabilities(struct mtd_info *mtd);
 /* drivers/mtd/mtdcore.h */
 int add_mtd_device(struct mtd_info *mtd);
 int del_mtd_device(struct mtd_info *mtd);
+
+#ifdef CONFIG_MTD_PARTITIONS
 int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
 int del_mtd_partitions(struct mtd_info *);
+#else
+static inline int add_mtd_partitions(struct mtd_info *mtd,
+                                    const struct mtd_partition *parts,
+                                    int nparts)
+{
+       return 0;
+}
+
+static inline int del_mtd_partitions(struct mtd_info *mtd)
+{
+       return 0;
+}
+#endif
 
 struct mtd_info *__mtd_next_device(int i);
 #define mtd_for_each_device(mtd)                       \
@@ -581,6 +598,7 @@ int mtd_arg_off_size(int argc, char *const argv[], int *idx, loff_t *off,
 void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
                          const uint64_t length, uint64_t *len_incl_bad,
                          int *truncated);
+bool mtd_dev_list_updated(void);
 
 /* drivers/mtd/mtd_uboot.c */
 int mtd_search_alternate_name(const char *mtdname, char *altname,
index b2b733f..a3afb72 100644 (file)
@@ -240,6 +240,44 @@ int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
        regmap_range_get(map, 0, type, member, valp)
 
 /**
+ * regmap_read_poll_timeout - Poll until a condition is met or a timeout occurs
+ *
+ * @map:       Regmap to read from
+ * @addr:      Offset to poll
+ * @val:       Unsigned integer variable to read the value into
+ * @cond:      Break condition (usually involving @val)
+ * @sleep_us:  Maximum time to sleep between reads in us (0 tight-loops).
+ * @timeout_ms:        Timeout in ms, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout or the regmap_read
+ * error return value in case of a error read. In the two former cases,
+ * the last read value at @addr is stored in @val. Must not be called
+ * from atomic context if sleep_us or timeout_us are used.
+ *
+ * This is modelled after the regmap_read_poll_timeout macros in linux but
+ * with millisecond timeout.
+ */
+#define regmap_read_poll_timeout(map, addr, val, cond, sleep_us, timeout_ms) \
+({ \
+       unsigned long __start = get_timer(0); \
+       int __ret; \
+       for (;;) { \
+               __ret = regmap_read((map), (addr), &(val)); \
+               if (__ret) \
+                       break; \
+               if (cond) \
+                       break; \
+               if ((timeout_ms) && get_timer(__start) > (timeout_ms)) { \
+                       __ret = regmap_read((map), (addr), &(val)); \
+                       break; \
+               } \
+               if ((sleep_us)) \
+                       udelay((sleep_us)); \
+       } \
+       __ret ?: ((cond) ? 0 : -ETIMEDOUT); \
+})
+
+/**
  * regmap_update_bits() - Perform a read/modify/write using a mask
  *
  * @map:       The map returned by regmap_init_mem*()
index 938627b..92427e5 100644 (file)
@@ -118,13 +118,6 @@ struct spi_slave {
 };
 
 /**
- * Initialization, must be called once on start up.
- *
- * TODO: I don't think we really need this.
- */
-void spi_init(void);
-
-/**
  * spi_do_alloc_slave - Allocate a new SPI slave (internal)
  *
  * Allocate and zero all fields in the spi slave, and set the bus/chip
index bd14fe2..b8addea 100644 (file)
@@ -750,7 +750,6 @@ CONFIG_G_DNL_UMS_PRODUCT_NUM
 CONFIG_G_DNL_UMS_VENDOR_NUM
 CONFIG_H264_FREQ
 CONFIG_H8300
-CONFIG_HARD_SPI
 CONFIG_HAS_ETH0
 CONFIG_HAS_ETH1
 CONFIG_HAS_ETH2
index a8d7e68..9a70c15 100644 (file)
@@ -144,3 +144,29 @@ static int dm_test_regmap_getset(struct unit_test_state *uts)
 }
 
 DM_TEST(dm_test_regmap_getset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Read polling test */
+static int dm_test_regmap_poll(struct unit_test_state *uts)
+{
+       struct udevice *dev;
+       struct regmap *map;
+       uint reg;
+       unsigned long start;
+
+       ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
+       map = syscon_get_regmap(dev);
+       ut_assertok_ptr(map);
+
+       start = get_timer(0);
+
+       ut_asserteq(-ETIMEDOUT,
+                   regmap_read_poll_timeout(map, 0, reg,
+                                            (reg == 0xcacafafa),
+                                            1, 5 * CONFIG_SYS_HZ));
+
+       ut_assert(get_timer(start) > (5 * CONFIG_SYS_HZ));
+
+       return 0;
+}
+
+DM_TEST(dm_test_regmap_poll, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);