From: Tom Rini Date: Wed, 5 Dec 2018 20:06:24 +0000 (-0500) Subject: Merge branch 'master' of git://git.denx.de/u-boot-spi X-Git-Tag: v2019.01-rc2~29 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9450ab2ba8d720bd9f73bccc0af2e2b5a2c2aaf1;hp=a77a8fde7bb850178c2e4ad3db354b536114ea32;p=platform%2Fkernel%2Fu-boot.git Merge branch 'master' of git://git.denx.de/u-boot-spi - Various MTD fixes from Boris - Zap various unused / legacy paths. - pxa3xx NAND update from Miquel Signed-off-by: Tom Rini --- diff --git a/README b/README index a46c7c6..17d56b8 100644 --- 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 */ diff --git a/arch/powerpc/include/asm/config.h b/arch/powerpc/include/asm/config.h index 849a69a..c9c9964 100644 --- a/arch/powerpc/include/asm/config.h +++ b/arch/powerpc/include/asm/config.h @@ -18,13 +18,6 @@ #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 diff --git a/board/freescale/mpc8349emds/mpc8349emds.c b/board/freescale/mpc8349emds/mpc8349emds.c index 4ec0af4..d40ed37 100644 --- a/board/freescale/mpc8349emds/mpc8349emds.c +++ b/board/freescale/mpc8349emds/mpc8349emds.c @@ -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) diff --git a/board/ids/ids8313/ids8313.c b/board/ids/ids8313/ids8313.c index a411d4e..d547af4 100644 --- a/board/ids/ids8313/ids8313.c +++ b/board/ids/ids8313/ids8313.c @@ -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 diff --git a/cmd/eeprom.c b/cmd/eeprom.c index e88cb13..6c29b33 100644 --- a/cmd/eeprom.c +++ b/cmd/eeprom.c @@ -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; diff --git a/cmd/ubi.c b/cmd/ubi.c index 2b74a98..a12ac70 100644 --- 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; diff --git a/common/board_f.c b/common/board_f.c index 835b724..149a722 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -24,7 +24,6 @@ #include #include #include -#include #ifdef CONFIG_SPL #include #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 diff --git a/common/board_r.c b/common/board_r.c index 21d3b3c..5f3d27a 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -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 diff --git a/doc/driver-model/spi-howto.txt b/doc/driver-model/spi-howto.txt index 1955ffe..38c26f6 100644 --- a/doc/driver-model/spi-howto.txt +++ b/doc/driver-model/spi-howto.txt @@ -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 diff --git a/drivers/mtd/mtd_uboot.c b/drivers/mtd/mtd_uboot.c index 5ca560c..d638f70 100644 --- a/drivers/mtd/mtd_uboot.c +++ b/drivers/mtd/mtd_uboot.c @@ -13,6 +13,29 @@ #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 diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index fb6c779..cb7ca38 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -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) { diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 4d2ac81..fd8d8e5 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -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. diff --git a/drivers/mtd/nand/raw/pxa3xx_nand.c b/drivers/mtd/nand/raw/pxa3xx_nand.c index 4c783f1..4d2712d 100644 --- a/drivers/mtd/nand/raw/pxa3xx_nand.c +++ b/drivers/mtd/nand/raw/pxa3xx_nand.c @@ -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; diff --git a/drivers/mtd/spi/sf_mtd.c b/drivers/mtd/spi/sf_mtd.c index 58d7e44..68c3600 100644 --- a/drivers/mtd/spi/sf_mtd.c +++ b/drivers/mtd/spi/sf_mtd.c @@ -10,6 +10,7 @@ #include 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); } diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 5a2e932..00f8558 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -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, }; diff --git a/drivers/net/e1000_spi.c b/drivers/net/e1000_spi.c index b38f4df..aecd290 100644 --- a/drivers/net/e1000_spi.c +++ b/drivers/net/e1000_spi.c @@ -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) { diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 516188e..a7bb5b3 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -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 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7242ea7..392a925 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -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 diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 1db8bbe..cf4de9e 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -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) { diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c index 07fa5e3..4d2c106 100644 --- a/drivers/spi/davinci_spi.c +++ b/drivers/spi/davinci_spi.c @@ -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) { diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c index f7ed8fb..764c942 100644 --- a/drivers/spi/fsl_dspi.c +++ b/drivers/spi/fsl_dspi.c @@ -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))) diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c index e994159..7444ae1 100644 --- a/drivers/spi/fsl_espi.c +++ b/drivers/spi/fsl_espi.c @@ -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); diff --git a/drivers/spi/lpc32xx_ssp.c b/drivers/spi/lpc32xx_ssp.c index ce12eee..4b09366 100644 --- a/drivers/spi/lpc32xx_ssp.c +++ b/drivers/spi/lpc32xx_ssp.c @@ -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 index 0000000..3d55169 --- /dev/null +++ b/drivers/spi/meson_spifc.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014 Beniamino Galvani + * Copyright (C) 2018 BayLibre, SAS + * Author: Neil Armstrong + * + * Amlogic Meson SPI Flash Controller driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 index 0000000..b510733 --- /dev/null +++ b/drivers/spi/mtk_qspi.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 MediaTek, Inc. + * Author : Guochun.Mao@mediatek.com + */ + +#include +#include +#include +#include +#include +#include +#include + +/* 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, +}; diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 0dccc38..b263690 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -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 diff --git a/drivers/spi/mxs_spi.c b/drivers/spi/mxs_spi.c index 006fe82..5065e40 100644 --- a/drivers/spi/mxs_spi.c +++ b/drivers/spi/mxs_spi.c @@ -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 */ diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index ecf54bb..c7fcf05 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -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); diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c index 86b71d2..32bb8c8 100644 --- a/drivers/spi/pl022_spi.c +++ b/drivers/spi/pl022_spi.c @@ -9,16 +9,11 @@ * Driver for ARM PL022 SPI Controller. */ -#include #include #include #include -#include -#include -#include -#include +#include #include -#include #include #define SSP_CR0 0x000 @@ -72,11 +67,7 @@ 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, diff --git a/drivers/spi/sh_qspi.c b/drivers/spi/sh_qspi.c index 64dfd74..5ae203d 100644 --- a/drivers/spi/sh_qspi.c +++ b/drivers/spi/sh_qspi.c @@ -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) { diff --git a/drivers/spi/sh_spi.c b/drivers/spi/sh_spi.c index bc2bd63..c58fd0e 100644 --- a/drivers/spi/sh_spi.c +++ b/drivers/spi/sh_spi.c @@ -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; diff --git a/drivers/spi/soft_spi_legacy.c b/drivers/spi/soft_spi_legacy.c index 0aac0c0..cc5ab5f 100644 --- a/drivers/spi/soft_spi_legacy.c +++ b/drivers/spi/soft_spi_legacy.c @@ -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) { diff --git a/examples/standalone/atmel_df_pow2.c b/examples/standalone/atmel_df_pow2.c index 2e14aba..b7bd243 100644 --- a/examples/standalone/atmel_df_pow2.c +++ b/examples/standalone/atmel_df_pow2.c @@ -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; diff --git a/include/_exports.h b/include/_exports.h index 5416041..c15050e 100644 --- a/include/_exports.h +++ b/include/_exports.h @@ -50,11 +50,9 @@ #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 *) diff --git a/include/common.h b/include/common.h index a8e879e..faf512e 100644 --- a/include/common.h +++ b/include/common.h @@ -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 */ diff --git a/include/configs/M52277EVB.h b/include/configs/M52277EVB.h index 11cb395..83d7745 100644 --- a/include/configs/M52277EVB.h +++ b/include/configs/M52277EVB.h @@ -102,7 +102,6 @@ /* 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 diff --git a/include/configs/M54418TWR.h b/include/configs/M54418TWR.h index f08896e..4b8ef38 100644 --- a/include/configs/M54418TWR.h +++ b/include/configs/M54418TWR.h @@ -151,7 +151,6 @@ /* 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 diff --git a/include/configs/M54451EVB.h b/include/configs/M54451EVB.h index 16becbd..87cdbae 100644 --- a/include/configs/M54451EVB.h +++ b/include/configs/M54451EVB.h @@ -116,7 +116,6 @@ /* 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 diff --git a/include/configs/M54455EVB.h b/include/configs/M54455EVB.h index 99b60d5..d41b7c4 100644 --- a/include/configs/M54455EVB.h +++ b/include/configs/M54455EVB.h @@ -142,7 +142,6 @@ /* DSPI and Serial Flash */ #define CONFIG_CF_DSPI -#define CONFIG_HARD_SPI #define CONFIG_SYS_SBFHDR_SIZE 0x13 #ifdef CONFIG_CMD_SPI diff --git a/include/configs/MPC8536DS.h b/include/configs/MPC8536DS.h index 524a10f..86a1233 100644 --- a/include/configs/MPC8536DS.h +++ b/include/configs/MPC8536DS.h @@ -370,11 +370,6 @@ #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 diff --git a/include/configs/P1022DS.h b/include/configs/P1022DS.h index c9ed70c..eeb19a9 100644 --- a/include/configs/P1022DS.h +++ b/include/configs/P1022DS.h @@ -386,12 +386,6 @@ #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 diff --git a/include/configs/UCP1020.h b/include/configs/UCP1020.h index 423ecd7..1bbe9d9 100644 --- a/include/configs/UCP1020.h +++ b/include/configs/UCP1020.h @@ -287,11 +287,6 @@ #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 diff --git a/include/configs/controlcenterd.h b/include/configs/controlcenterd.h index 4adcd95..1908d35 100644 --- a/include/configs/controlcenterd.h +++ b/include/configs/controlcenterd.h @@ -182,10 +182,6 @@ #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 diff --git a/include/configs/ids8313.h b/include/configs/ids8313.h index 28124dd..7e4c497 100644 --- a/include/configs/ids8313.h +++ b/include/configs/ids8313.h @@ -159,7 +159,6 @@ */ #define CONFIG_TSEC1 #define CONFIG_TSEC2 -#define CONFIG_HARD_SPI /* * NOR FLASH setup @@ -274,15 +273,6 @@ #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 diff --git a/include/configs/mx31pdk.h b/include/configs/mx31pdk.h index 7d84d16..4765764 100644 --- a/include/configs/mx31pdk.h +++ b/include/configs/mx31pdk.h @@ -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) diff --git a/include/configs/mxs.h b/include/configs/mxs.h index 9e59e7a..4bb3621 100644 --- a/include/configs/mxs.h +++ b/include/configs/mxs.h @@ -143,7 +143,6 @@ /* SPI */ #ifdef CONFIG_CMD_SPI -#define CONFIG_HARD_SPI #define CONFIG_SPI_HALF_DUPLEX #endif diff --git a/include/configs/p1_p2_rdb_pc.h b/include/configs/p1_p2_rdb_pc.h index 9465fb4..459ecf3 100644 --- a/include/configs/p1_p2_rdb_pc.h +++ b/include/configs/p1_p2_rdb_pc.h @@ -576,11 +576,6 @@ #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 diff --git a/include/configs/p1_twr.h b/include/configs/p1_twr.h index d018c22..4f48370 100644 --- a/include/configs/p1_twr.h +++ b/include/configs/p1_twr.h @@ -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 diff --git a/include/configs/stmark2.h b/include/configs/stmark2.h index c408db8..33ddc67 100644 --- a/include/configs/stmark2.h +++ b/include/configs/stmark2.h @@ -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 diff --git a/include/configs/ts4800.h b/include/configs/ts4800.h index 956f779..4e274bd 100644 --- a/include/configs/ts4800.h +++ b/include/configs/ts4800.h @@ -43,11 +43,6 @@ #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 diff --git a/include/dm/platform_data/pl022_spi.h b/include/dm/platform_data/spi_pl022.h 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 --- a/include/dm/platform_data/pl022_spi.h +++ b/include/dm/platform_data/spi_pl022.h @@ -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 -#endif #include 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 */ diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 68e5915..cd1f557 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -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, diff --git a/include/regmap.h b/include/regmap.h index b2b733f..a3afb72 100644 --- a/include/regmap.h +++ b/include/regmap.h @@ -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*() diff --git a/include/spi.h b/include/spi.h index 938627b..92427e5 100644 --- a/include/spi.h +++ b/include/spi.h @@ -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 diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index bd14fe2..b8addea 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -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 diff --git a/test/dm/regmap.c b/test/dm/regmap.c index a8d7e68..9a70c15 100644 --- a/test/dm/regmap.c +++ b/test/dm/regmap.c @@ -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);