diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 1dd2e3175b0d188e293a5cd5daa0bce3e1b2c4fb..48f02a22973ad4f67a414116eadf91971f88f58d 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -239,4 +239,13 @@ config SPL_SPI_FLASH_MTD If unsure, say N +config SPI_FLASH_AUTO_MERGE + bool "SPI flash auto merge two flash in one" + default n + depends on SPI_FLASH + help + Enable the auto merge the two SPI flash in one. + + If unsure, say N + endmenu # menu "SPI Flash Support" diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 8a454bfe2bc629bc4cb9d2f87444dea639c7a405..2253d42169d53273af7be23d373205293ff39879 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -556,7 +556,7 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) { struct spi_nor *nor = mtd_to_spi_nor(mtd); - u32 addr, len, rem; + u32 addr, len, rem, target; int ret; dev_dbg(nor->dev, "at 0x%llx, len %lld\n", (long long)instr->addr, @@ -570,14 +570,20 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) len = instr->len; while (len) { +#if defined(CONFIG_SPI_FLASH_AUTO_MERGE) + nor->spi->auto_merge_cs_cur = addr < nor->auto_merge_single_chip_size ? 0 : 1; + target = addr - nor->spi->auto_merge_cs_cur * nor->auto_merge_single_chip_size; +#else + target = addr; +#endif #ifdef CONFIG_SPI_FLASH_BAR - ret = write_bar(nor, addr); + ret = write_bar(nor, target); if (ret < 0) return ret; #endif write_enable(nor); - ret = spi_nor_erase_sector(nor, addr); + ret = spi_nor_erase_sector(nor, target); if (ret) goto erase_err; @@ -923,6 +929,13 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, loff_t addr = from; size_t read_len = len; +#if defined(CONFIG_SPI_FLASH_AUTO_MERGE) + if (addr < nor->auto_merge_single_chip_size && (addr + len) > nor->auto_merge_single_chip_size) + read_len = nor->auto_merge_single_chip_size - addr; + nor->spi->auto_merge_cs_cur = addr < nor->auto_merge_single_chip_size ? 0 : 1; + addr -= nor->spi->auto_merge_cs_cur * nor->auto_merge_single_chip_size; +#endif + #ifdef CONFIG_SPI_FLASH_BAR u32 remain_len; @@ -1246,6 +1259,11 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, ssize_t written; loff_t addr = to + i; +#if defined(CONFIG_SPI_FLASH_AUTO_MERGE) + nor->spi->auto_merge_cs_cur = addr < nor->auto_merge_single_chip_size ? 0 : 1; + addr -= nor->spi->auto_merge_cs_cur * nor->auto_merge_single_chip_size; +#endif + /* * If page_size is a power of two, the offset can be quickly * calculated with an AND operation. On the other cases we @@ -2691,6 +2709,21 @@ int spi_nor_scan(struct spi_nor *nor) puts("\n"); #endif +#if defined(CONFIG_SPI_FLASH_AUTO_MERGE) + nor->auto_merge_single_chip_size = nor->size; + nor->spi->auto_merge_cs_cur = 1; + if (IS_ERR(spi_nor_read_id(nor))) { + printf("spinor enable auto_merge, but only cs0 valid\n"); + return 0; + } + ret = spi_nor_init(nor); + if (!ret) { + mtd->size = mtd->size * 2; + nor->size = nor->size * 2; + printf("spinor enable auto_merge\n"); + } +#endif + return 0; } diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 10b53592e58bb119f829518ab0b3365703416881..c37c323bd5c1ceab1e60d4ecc5e569a703a12603 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -315,6 +315,9 @@ struct spi_nor { u8 bank_read_cmd; u8 bank_write_cmd; u8 bank_curr; +#endif +#ifdef CONFIG_SPI_FLASH_AUTO_MERGE + u32 auto_merge_single_chip_size; #endif enum spi_nor_protocol read_proto; enum spi_nor_protocol write_proto; diff --git a/include/spi.h b/include/spi.h index df99ec5c77b40e0dbfe616d6c9ebcf03cfb3cf9d..77691031565076f291b00d7367764c239afcfe7e 100644 --- a/include/spi.h +++ b/include/spi.h @@ -113,6 +113,9 @@ struct spi_slave { #else unsigned int bus; unsigned int cs; +#endif +#ifdef CONFIG_SPI_FLASH_AUTO_MERGE + unsigned int auto_merge_cs_cur; #endif uint mode; unsigned int wordlen;